TweetFollow Us on Twitter

Reusable MacApp
Volume Number:2
Issue Number:12
Column Tag:Advanced Mac'ing

Reusable MacApp Classes

By Kurt J. Schmucker, PPI, Inc.

Kurt Schmucker is Technical Director for Educational Services at PPI in Sandy Hook, CT. He is also author of the best selling book Object-Oriented Programming for the Macintosh. In this article, Kurt introduces us to some nifty object oriented programming constructs for MacApp.

Designing Reusable Classes for MacApp Applications

Introduction

One of the most important benefits of object-oriented programming is the ability to easily reuse code. This reusability is of a completely different nature than the reusability of the Mac Toolbox, on one hand, and a Pascal unit, on the other. This is because of the dynamic binding and inheritance of object-oriented languages, of which Object Pascal is one example. In an object-oriented language, the messages sent to objects are not resolved until run-time and this resolution depends on the class of the object that receives the message. This dynamic binding is essential to the design and implementation of a framework like MacApp. For example, when MacApp wants to draw the interior of one of the windows in your application, it sends the Draw message to the view object installed in that window with some code like this:

window.fView.Draw;

The view that receives this message will be an instance of some view class that you have designed, and since you overrode its Draw method, the code you wrote will be invoked by this message. In this way even though the MacApp framework was written independently from your application, it can still call your code.

In addition, this same message (window.fView.Draw) is used for all the windows. For each window, the Draw message is sent to the appropriate view object which “knows” how to draw itself. Thus, the MacApp code for the TWindow class is reusable across all MacApp applications since it can be used without change in all of them.

There is also another kind of reusability. You might want to reuse all the functionality of the MacApp TWindow class, for example, except that you want one little change: you want a window that always asks for a confirmation before opening or closing. (Okay, so this is a weird thing to do. I'm just trying to make a point.) In an object-oriented language like Object Pascal, this is easy to do. You just design a new subclass of TWindow, call it TConfirmingWindow. This new class inherits all the functionality of the TWindow class, but in addition, you can augment the actions taken when the window opens or closes by designing your own methods for the Open and Close messages. Designing your own methods for the TConfirmingWindow is considerably easier than defining your own window or menu definition procedures -- the closest analog on the Mac. For example, this would be the way you would augment the open behavior of the window:

PROCEDURE TConfirmingWindow.Open;  OVERRIDE;
BEGIN
     IF SELF.ConfirmOpen
       THEN INHERITED Open;
END;

Fig. 1 The QuadWorld Program

This method is invoked when an instance of TConfirmingWindow is sent the Open message. This method first sends the message ConfirmOpen to this window, presumably to ask the user if this window really should appear on the Mac screen. If the answer is yes, this method then invokes its inherited Open method: the Open method for the TWindow class.

In this last example, you have reused code by inheriting it, overriding to augment the existing behavior of the window. The bottom line is that to implement the confirming window took you just a few lines of code.

This article discusses how you can use dynamic binding and inheritance to build your own reusable MacApp classes. In doing so, we will develop such a class and demonstrate its reusability by subclassing it to achieve two new kinds of functionality with only the minimum of work.

Note that the style of reusability possible in an object-oriented language is not meant to replace the kinds of software packaging found in traditional subroutine libraries like the Toolbox or a unit. Rather it is an additional tool in the hands of the Mac programmer, a tool that is appropriate for many tasks but not everything.

Rules of Thumb for Reusable Classes

Using an object-oriented language does not guarantee reusable software, just as using structured programming does not guarantee readable or maintainable code. Object-oriented programming does, however, give you the potential for a level of reusability unachievable in languages that do not have dynamic binding or inheritance.

Here are some of the rules of thumb that I use to design reusable classes. Like all rules of thumb, they are meant to be followed in moderation.

Rule 1: Whenever you are faced with a choice, design a new method.

Rule 2: Methods should be single purpose.

Rule 3: Store as instance variables the data that is needed by more than one of your methods, or data that may be needed by a subclass.

Rule 4: In deciding on the superclass for a new class, method inheritance is more important than data inheritance.

Rule 5: Write for the library, not just for yourself.

Rule 6: Code defensively. You never know who will call your methods and under what circumstances.

Rule 1 encourages all major and most minor decisions to be made in separate methods so that these decisions can be overridden in subclasses. This gives the class the maximum flexibility as a base for new subclasses. Because this principle was followed in MacApp, it was easy to design the TConfirmingWindow class. What should happen when a window is to be open is a single method in the class and thus to change this in the subclass, only one method need be overridden. There is one drawback to following this rule: proliferation of methods. You can see this in MacApp, which consists of only 39 classes but over 560 methods. The benefits of this rule, however, outweigh this inconvenience.

Rule 2 reiterates that methods should be replaceable components of building blocks: replaceable in subclasses. If methods are multi-purpose, this is difficult. In the case of the TConfirmingWindow class, we were able to override one decision -- what to do when a window is to be opened -- in one method, without having to worry about what other things this method might do. This made the TConfirmingWindow class an excellent base for new classes. A corollary of this rule is that methods tend to be short: at most a few dozen statements or so.

Rule 3 encourages you to avoid global variables by storing data needed by several methods in instance variables. In addition to the data you need, consider also the data that might be needed by a subclass: data needed to support different resolutions of the decisions you made. (Rule 1)

Rule 4 helps you decide on the superclass for a class you are designing. Examine the behavior you will inherit from the superclass rather than the data you will also inherit.

Rule 5 encourages you to go that extra step or two. Don’t do just the bare minimum that will solve the problem at hand: design the additional functionality that will make this a class worthy of being in a library.

Rule 6 warns you that since your class may be subclassed by many other programmers, its methods may be called in circumstances you cannot control. You must therefore code extremely defensively.

QuadWorld Geometric Editor and the TListView Class

The application that will be used to demonstrate this design of reusable classes is the QuadWorld application. QuadWorld is a simple MacDraw-like geometric editor. It allows the user to enter and manipulate various kinds of quadrilaterals without regard to the geometric constraints associated with special quadrilaterals like rhombi. QuadWorld presents two representations (views) of the quadrilaterals to the end user: a graphical view and a textual view. It is the textual view that will be developed as a reusable MacApp class. Figure 1 is a screen dump of QuadWorld in action. For a more detailed discussion of the implementation of the QuadWorld application, as well as a complete listing of the QuadWorld application, see Object-Oriented Programming for the Macintosh, Hayden, 1986, by myself. The complete source is also available on the MacTutor Source Code Disk for this issue, Number 15, $8.00 from MacTutor.)

The list view class is a good candidate for some special design attention since its functionality -- displaying a list of text items so that the user can select one with the mouse -- is needed by many applications. (QuadWorld was designed and implemented before the new 128K ROMs with the List Manager was released.) Other parts of QuadWorld are not such good candidates. After all, how often do you need the code to rotate a rhombus?

This brings up an interesting point. Any class designed in Object Pascal can be reused and so, for that matter, can any piece of code. What we are talking about here is designing the code of a class to be used with the MacApp class library, so that it can be reused easily by other programmers who may not have access to the source code or don’t want to bother with all the fine points of the algorithms involved. These programmers will still want to be able to make small modifications to the functionality of the class, in the way that TConfirmingWindow is a slight modification of the vanilla window modelled by TWindow. This can be almost trivial to do, if the original class was designed well, by following the rules of thumb discussed earlier.

The TListView Class

The essential structure of the TListView class is shown in Figure 2. This collection of methods follows most (if not all) of the rules outlined above. For example, since I had to make a choice when setting up the QuickDraw port (font, text size, text style, etc.), I coded my preference in a separate method (SetPen). If you needed the functionality of this class, but wanted one of these characteristics to be different, you would only have to subclass TListView and override this one method.

Less obviously, whenever I am about to do something with an entire entry in the list (test for coverage by a mouse click, highlight, or move the pen into position for drawing), I use a method to compute the rectangle surrounding an item. Who knows, perhaps someone would want to accomplish this aspect of a list view differently. (In fact, the last section of this article does exactly this.)

In the area of data, the fCurrentItem instance variable always stores the number of the item currently being processed (drawn, enumerated, etc.) in case a subclass needs to use it. The fItemHeight variable stores the height of an individual item since this data is needed by several methods.

Of course, like any good idea, you can carry these rules-of-thumb of class design too far. Abusing rule 1, for example, will result in so many methods that no one can understand what is going on and, in addition, performance will degrade. I hope that I have successfully straddled the fence between a class that can’t easily be used as a basis for inheritance and one with so many methods as to be incomprehensible.

When a class is properly designed, note how short and simple the methods turn out:

PROCEDURE TListView.ChangeSelection(
 index: INTEGER);
BEGIN
 SELF.fFrame.Focus;
 SELF.DoHighlightSelection(SELF.fHLDesired, hlOff);
 SELF.fCurrentSelection := index;
 SELF.DoHighlightSelection(hlOff, SELF.fHLDesired);
END;

FUNCTION  TListView.DoMouseCommand(
 VAR downLocalPoint: Point; 
 VAR info: EventInfo;
 VAR hysteresis: Point): TCommand; OVERRIDE;
VAR index: INTEGER;
BEGIN
{If this mouse press results in a change of the current selection, let 
the document deal with it in any way it chooses.  This is done because 
the document might control several views, or might deal with a changed 
selection in some other application-specific manner. }

        DoMouseCommand := gNoChanges;
        index := SELF.PtToIndex(downLocalPoint);
        IF (index > 0) THEN
          BEGIN
             IF fCurrentSelection = index 
 { A click on the current selection means to
 deselect it }
 THEN
 TListDocument(SELF.fDocument).
 SetSelection(0)
 ELSE
 TListDocument(SELF.fDocument).
 SetSelection(index);
          END
END;

These methods are short and clear enough that it is easy to see that they are correct just by reading them.

Some of the interrelationships between the methods of the TListView class are also shown in Figure 2. Basically, there are a few basic methods that encode my decisions to some issues as to how a list view should behave (DrawOneItem, SetUpBox, SetItemHeightAndLineAscent, and SetPen). The rest of the methods are written in terms of each other and these basic ones, as you can see in both the ChangeSelection and DoMouseCommand methods above.

To get some new functionality in a subclass of a class designed in this way, you only need (usually) to override one or more of the basic methods -- everything else just works. On a considerably larger scale, MacApp works exactly the same way. Instead of modelling just a list of selectable items, MacApp models an entire Macintosh application and you just override some classes to add the functionality that distinguishes your application from all other ones.

The full source code for the TListView class is at the end of this article. (Since the MacApp classes can currently only be accessed from MPW Pascal, all the sample code and all the work for this article was done in MPW. While the latest version of TML Pascal supports the Object Pascal extensions, it does not yet support other Pascal extensions used by MacApp.)

Some TListView Subclass

In order to demonstrate the flexibility of a properly designed class like TListView, let’s use it as the superclass for two new classes. These two new classes will both portray lists of items in the QuadWorld application, but each will do so in a different way.

Figure 3

TTwoLineListView

The TTwoLineListView class presents a two-line entry for each quadrilateral. The first line is the type of quadrilateral, just like in TListView. However this does not allow you to distinguish between each of the squares or each of the rhombi, for example, without interacting with the view by highlighting individual quadrilaterals. TTwoLineListView corrects this problem. The second line of an entry in a TTwoLineListView display the coordinates of the vertices of the quadrilateral. Figure 3 shows a screen dump of QuadWorld using the TTwoLineListView.

To accomplish the functionality of the TTWoLineListView we had do nothing more than subclass TListView and override two of its basic methods, DrawOneItem and SetItemHeightAndLineAscent. Even this overriding did not require us to re-implement the functionality of the basic methods in TListView, but merely augment their computations. As was mentioned in Ken Doyle’s article on Object Pascal, the keyword INHERITED can be used to access a method of an ancestor or superclass. In TTwoLineListView, I did so in both of its methods.

Since the major theme of this article is reusability in MacApp, let me document the steps to add TTwoLineListView to QuadWorld, in particular, and the general steps of adding any new class to an application written with MacApp. Adding a new view like the two-line list view to an application like QuadWorld consisted of the following amount of work:

Design the new class.

= For the TTwoLineListView this was about 30 lines of MPW Pascal with a stub routine for the construction and formatting the line of text representing the vertices. (See step 4.)

Incorporate this new class into the application.

= Modify the make file to include dependencies on the new class file. In the case of the QuadWorld make file, this was three modifications, each of which were adding another dependency to an existing rule.

= Modify the USES statement in the application’s major unit (UQuadWorld.p, in the case of QuadWorld) and main program (MQuadWorld.p) by adding the name of the new unit to the existing USES statement.

= Refer to the new class in the major unit of the application. In the case of the TTwoLineListView class in QuadWorld, this consisted of modifying the data type of one temporary variable in method TQuadDocument.DoMakeViews from the type TListView to the type TTwoLineListView. This causes an object of the TTwoLineListView class to be allocated at run-time and to be connected to the other objects that comprise the QuadWorld application.

Add whatever features necessary to the application to generate any new information needed by the new class.

= For QuadWorld, this meant providing methods in the TQuadDocument class and in the various quadrilateral classes to generate a string representing the vertex coordinates of any quadrilateral.

TMiniIconListView

The TMiniIconListView solves the problem of the individual who cannot remember which is a rhombus and which is a parallelogram since it presents a little icon for each type of quadrilateral. This icon is the same for all quadrilaterals, for all parallelograms, etc. Figure 4 shows a screen dump of QuadWorld using the TTwoLineListView.

To implement TMiniIconListView, I inherited from TListView and overrode only the DrawOneItem basic method.

Adding the necessary features to QuadWorld to generate the information needed by the mini-icon view (step 3 above) provides an interesting example of how programming with an object-oriented language differs from programming with a non-object-oriented language. My first version of TMiniIconListView.DrawOneItem ignored the peripheral issue of generating this information, concentrating rather on the structural issues of the new class that was being designed. This was done by using a stub routine for actually obtaining and drawing the icon:

PROCEDURE TMiniIconListView.DrawOneItem
 (item: Str255);  OVERRIDE;
    { Draw the mini-icon }
 PROCEDURE DrawIcon;
 VAR  tempRect: Rect;
 
 BEGIN
     { The rectangle into which the icon will be drawn }
 tempRect := SELF.SetUpBox(SELF.fCurrentItem);
 tempRect.right := tempRect.left +  SELF.fItemHeight;
    { Fake the icon for now }
 InsetRect(tempRect, 4, 4);
 FrameRect(tempRect);
 END;

BEGIN
 DrawIcon;
 Move(SELF.fItemHeight, 0);
 INHERITED DrawOneItem(item);
END;

To complete the TMiniIconListView class required fleshing out this stub. There were two extremes for this task: a non-flexible, non-object-oriented, closed solution something like this:

 
{ Get the icon by testing the itemString }
 CASE item OF
 'a Quadrilateral':icon := quadIcon;
 'a Parallelogram':icon := parallelogramIcon;
 'a Rhombus':    icon := rhombusIcon;
 'a Rectangle':  icon := rectangleIcon;
 'a Square':icon := squareIcon;
 OTHERWISEicon := quadIcon

or a flexible, object-oriented, open solution something like this:

{ Get the icon by “asking” the quad what its icon is }
icon := (SELF.fCurrentItem).AsQuad.MiniIconNumber

The object-oriented solution turns out to be slightly longer, but was so much clearer and more malleable with respect to future changes in QuadWorld that there really wasn't any choice as to which was the truly “best” solution.

To be more precise, the modifications to QuadWorld to generate the information needed by the mini-icon view were:

“Flesh” out the stub routine as follows:

PROCEDURE TMiniIconListView.DrawOneItem
 (item: Str255);  OVERRIDE;
   { Draw the mini-icon }
 PROCEDURE DrawIcon;
 VAR  tempRect: Rect;
 tempHandle: Handle;
 myDocument: TMiniIconListDocument;
 BEGIN
     { The rectangle into which the icon will be drawn }
 tempRect := SELF.SetUpBox(SELF.fCurrentItem);
 tempRect.right := tempRect.left +  SELF.fItemHeight;

    { Get the icon }
 myDocument := 
 TMiniIconListDocument(SELF.fDocument);
 tempHandle := 
 GetIcon(myDocument.ReportIconNumber
 (SELF.fCurrentItem));
 FailNIL(tempHandle);
 
     { Draw the Icon }
 PlotIcon(tempRect, tempHandle);
 END;
 
BEGIN
 DrawIcon;
 Move(SELF.fItemHeight, 0);
 INHERITED DrawOneItem(item);
END;

Add the new method ReportIconNumber to the TDocument class displayed by the TMiniIconListView.

This task is one of the few made more difficult by the characteristics of MPW Pascal. Even if you know that the instance of the subclass of TDocument that you will be using in your application will, at run-time, understand a message like ReportIconNumber, you must find some way to inform the compiler that everything is OK at compile-time. (More robust object-oriented languages like Smalltalk-80® and Objective-C® have no such requirement.) The solution to this difficulty, in the case of Object Pascal, is to define an abstract superclass with a null method for ReportIconNumber. This is the class TMiniIconListDocument.

Change the inheritance of TQuadDocument so that it is a specialization of TMiniIconListDocument and then implement the ReportIconNumber method as follows:

FUNCTION  TQuadDocument.ReportIconNumber
 (itemNumber: INTEGER): INTEGER;  OVERRIDE;
VAR theQuad: TQuad;
BEGIN
        theQuad := TQuad(SELF.ListIndexToQuad(itemNumber));
        IF theQuad = NIL
     THEN ReportIconNumber := cQuadIcon
     ELSE ReportIconNumber := theQuad.MiniIconNumber;
END;

Add the MiniIconNumber method to all the quadrilateral classes so that each kind of quadrilateral “knows” what its particular mini-icon number is.

Add the resource ids for the five new icons to the UQuadWorld unit.

Add the icon resources to the compiled QuadWorld application with ResEdit.

The source code for these two subclasses of TListView is also appended to the end of this article. For the QuadWorld program itself, see Source Code Disk #15.

{  List View unit used in the  QuadWorld Application  }
{ Copyright 1986, Productivity Products International, Inc. }
{ Reproduction & distribution rights granted to MacTutor }

 { This unit implements a list view like that of the Smalltalk
Listview class, i.e., a vertical list of text items any one of
which can be selected with the mouse.  Like the Smalltalk
class, this TListView makes some assumptions about the
protocol of the document it displays.  In particular,
TListView assumes that its fDocument field refers to an
instance of a subclass of TListDocument (defined here) and
thus has the following additional document methods (at a
minimum):
        T(Your)Document.SetSelection(newSelectionIndex);

This method is used to communicate to your document that the selection 
has changed, presumably because the user has selected a text string in 
the TListView
              T(Your)Document.ReportListItem: Str255;

A function which returns the textual version of a given item to be displayed 
by the TListView. Note that your document can contain primarily non-textual 
data - the ListView will display a textual representation of that data, 
a representation that you construct in this method.

     To see one example of how this ListView class can be used, see the 
QuadWorld application on source disk 15. }

UNIT UListView;

INTERFACE

USES
  { This set of units are portions of the Macintosh ROM }
    MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,

  { This set of units are portions of MacApp }
    UObject, UList, UMacApp;

TYPE
    TListDocument = OBJECT(TDocument)
 { an abstract superclass that contains null methods
 needed for the proper use of a list view }
      { No additional instance variables }
        PROCEDURE TListDocument.SetSelection(
 newSelectionIndex: INTEGER);
        FUNCTION  TListDocument.ReportListItem(                itemNumber: 
INTEGER): Str255;
    END;   { of TListDocument }

    TListView = OBJECT(TView)
    { Instance variables }
        fCurrentItem:   INTEGER; { index of the current        
 selection, if any, otherwise 0 }
        fCurrentSelection:   INTEGER;{ index of the current
 selection, if any, 
 otherwise 0 } 
        fNumberOfItems:  INTEGER;  { number of items
 currently in the list }
        fItemHeight:  INTEGER;{ height of each line            
 including leading }
        fLineAscent:  INTEGER;{ position of baseline           
 relative to top of line }

   { Initialization }
        PROCEDURE TListView.IListView(
 itsParent: TView;   itsDocument: TListDocument;
 itsExtent: Rect;  itsVDeterminer: SizeDeterminer;
 itCanSelect: BOOLEAN);
         {$IFC qDebug}
        PROCEDURE TListView.Inspect; OVERRIDE;
 { Debugging print of the listView }
         {$ENDC}
   { Commands and Selections }
        PROCEDURE TListView.ChangeSelection(
 index: INTEGER);
        FUNCTION  TListView.DoMouseCommand(
 VAR downLocalPoint: Point; VAR info: EventInfo;
 VAR hysteresis: Point): TCommand;  OVERRIDE;
        FUNCTION  TListView.PtToIndex(
 testPoint: Point): INTEGER;
 { Convert from a point in local view
 coordinates to the index of the list of itemsat               
 this point.  This is a method so that it can
 easily be overridden by clients. }

   { Displaying }
        PROCEDURE TListView.AboutToDraw;  OVERRIDE;
 { Set the font and text style }
        PROCEDURE TListView.CalcMinExtent(
 VAR minExtent: Rect);  OVERRIDE;
 { This method must be overridden since a list view
 has a variable vertical extent. }
        PROCEDURE TListView.DoHighlightSelection(
 fromHL, toHL: HLState);  OVERRIDE;
        PROCEDURE TListView.Draw(area: Rect);  OVERRIDE;
        PROCEDURE TListView.DrawOneItem(item: Str255); 
 { Draw one item.  This is here so that it can                 
 easilly be overridden by a client. }
        PROCEDURE TListView.InvalidateItem(
 itemNumber: INTEGER);
        PROCEDURE TListView.SetItemHeightAndLineAscent;
 { Setup the item height and ascent for drawing the
 text; this is a method so that it can be overridden
 easily by clients}
        FUNCTION  TListView.SetUpBox(index: INTEGER): Rect;    
 { Calculate the surrounding rectangle for an item }
        PROCEDURE TListView.SetPen;
 { Setup the pen for drawing the text; this is a               method 
so that it can be overridden easily by
 clients}
    END;  { TListView }

IMPLEMENTATION

{ Private data }
CONST
 txMargin = 4;   { horizontal space between view edge and
 the left edge of the text }

{ *****  TListDocument  (an abstract superclass )  ****** }

    PROCEDURE TListDocument.SetSelection(
 newSelectionIndex: INTEGER);
    BEGIN
        {$IFC qDebug}
 ProgramBreak('Call to TListDocument.SetSelection
  - an abstract superclass');
 {$ENDC}
    END;

    FUNCTION  TListDocument.ReportListItem(
 itemNumber: INTEGER): Str255;
    BEGIN
        {$IFC qDebug}
 ProgramBreak('Call to TListDocument.ReportList
  - an abstract superclass'); 
 {$ENDC}
    END;


{ ****************  TListView  ************************ }

    PROCEDURE TListView.IListView(itsParent: TView;
 itsDocument: TListDocument;   itsExtent: Rect;
 itsVDeterminer: SizeDeterminer;
 itCanSelect: BOOLEAN);
    BEGIN
 SELF.IView(itsParent, itsDocument, itsExtent, sizeFixed,
 itsVDeterminer, itCanSelect, hlDim);
 SELF.fCurrentItem := 0;
 SELF.fCurrSelection := 0;
 SELF.fNumberOfItems := 0;
 SELF.fItemHeight := 17;       { Reasonable default }
 SELF.fLineAscent := 12;       { Reasonable default }
 SELF.fInformBeforeDraw := TRUE;
 { Before drawing the first time, call the
 AboutToDraw method }
    END;
 
{$IFC qDebug}
    PROCEDURE TListView.Inspect; OVERRIDE; 
 { Debugging print of the listView }
    BEGIN
 INHERITED Inspect;
 WriteLn(' The current item is: ', SELF.fCurrentItem);
 WriteLn(' The selected item is: ',SELF.fCurrentSelection);
 WriteLn(' The number of items is: ',SELF.fNumberOfItems);
 WriteLn(' The item height is: ', SELF.fItemHeight);
 WriteLn(' The line ascent is: ', SELF.fLineAscent);
    END;
{$ENDC}

{ Set the font and text style just before drawing the view for the first 
time }
    PROCEDURE TListView.AboutToDraw;  OVERRIDE;
 BEGIN
 SELF.SetPen;
 SELF.SetItemHeightAndAscent;
 SELF.AdjustExtent;
 SELF.fInformBeforeDraw := FALSE;  { No longer call
 this method }
 END;
 
{ This method must be overridden so that MacApp can determine the view's 
true extent }
    PROCEDURE TListView.CalcMinExtent(
 VAR minExtent: Rect);  OVERRIDE;
     BEGIN
     { How many items are there? }
        SELF.fCurrentItem := 1;
        WHILE (TListDocument(SELF.fDocument).
 ReportListItem( SELF.fCurrentItem ) <> ' ')
               DO SELF.fCurrentItem := SELF.fCurrentItem + 1;
        SELF.fNumberOfItems := SELF.fCurrentItem - 1;
 SELF.fCurrentItem := 0;
 { No item currently being processed }

     { Set the amount of room needed for that many items }
   minExtent := SELF.fExtentRect;
        IF SELF.fSizeDeterminer[v] <> sizeFixed
 { Only need to adjust vertical extent }
          THEN minExtent.botRight.v :=
 SELF.fNumberOfItems*SELF.fItemHeight;
    END;


    PROCEDURE TListView.ChangeSelection(
 index: INTEGER);
    BEGIN
        SELF.fFrame.Focus;
        SELF.DoHighlightSelection(SELF.fHLDesired, hlOff);
        SELF.fCurrentSelection := index;
        SELF.DoHighlightSelection(hlOff, SELF.fHLDesired);
    END;

{ Dim highlighting of text by gray XORing is not very readable, so dim 
highlight a text string by framing it with a gray rectangle.  (Standard 
highlighting when the window displaying
the view is active is still to invert - black XORing.)  The state transition 
diagram is:                                                          
     hlTo

               |  OFF   |    DIM   |   ON
          -----|--------|----------|--------
          OFF  |  (NA)  |   Frame  | Invert
          -----|--------|----------|--------
          DIM  | Frame  |   (NA)   | Frame +
hlFrom         |        |          | Invert
          -----|--------|----------|---------
          ON   | Invert | Invert + |  (NA)
               |        |  Frame   |
          -----|--------|----------|---------

  Since this matrix is (almost) symmetric, we can add together
the hlFrom and hlTo parameters and take one action for each of the three 
possible sums.  }

    PROCEDURE TListView.DoHighlightSelection(
 fromHL, toHL: HLState); OVERRIDE;
    VAR r:  Rect;
    BEGIN
        IF (SELF.fCurrentSelection > 0) THEN
            BEGIN
                { Make r be the rectangle to invert }
                r := SELF.SetUpBox(SELF.fCurrentSelection);
                InsetRect(r, 1, 1);

                { Set the pen pattern and mode properly }
                PenPat(ltGray);
                PenMode(patXor);

                IF RectIsVisible(r) THEN 
 { only do highlighting if part of the rectangle is            
 visible }
                  BEGIN
                      CASE (fromHl + toHL) OF
 hlOffDim:  FrameRect(r);
 hlOffOn:   InvertRect(r);
 hlDimOn:   IF fromHL = hlDim
 THEN BEGIN
 FrameRect(r);   InvertRect(r);
 END
 ELSE BEGIN
 InvertRect(r);  FrameRect(r);
 END;
                      END  { of CASE }
                  END
            END
    END;

    FUNCTION  TListView.DoMouseCommand(
 VAR downLocalPoint: Point; VAR info: EventInfo;
 VAR hysteresis: Point): TCommand; OVERRIDE;
    VAR index: INTEGER;
    BEGIN
        { If this mouse press results in a change of the current selection, 
let the document deal with it in any way it chooses.  This is done because 
the document might control several views, or might deal with a changed 
selection in some other application-specific manner. }

        DoMouseCommand := gNoChanges;
        index := SELF.PtToIndex(downLocalPoint);
        IF (index > 0) THEN
          BEGIN
              IF fCurrentSelection = index 
 { A click on current selection means to deselect it }
                THEN
 TListDocument(SELF.fDocument).SetSelection(0)
                ELSE
 TListDocument(SELF.fDocument).
 SetSelection(index);
          END
    END;

{ Write the textual representation of all the items, properly positioned 
}
    PROCEDURE TListView.Draw(area: Rect); OVERRIDE;
    VAR bBox:  Rect;    { the bounding box for a single item }
        stringToDraw:  Str255;
    BEGIN
         SELF.fCurrentItem := 1;
 { Get each item in turn from the document and draw it }
         stringToDraw := TListDocument(SELF.fDocument).
 ReportListItem( SELF.fCurrentItem );
         WHILE (stringToDraw <> ' ') DO
            BEGIN
                { Calculate the rectangle to fill }
                bBox := SELF.SetUpBox( SELF.fCurrentItem );

                IF RectIsVisible(bBox) THEN
 { only write text that will be seen }
                    BEGIN
                      MoveTo(bBox.left + txMargin, 
 bBox.top + SELF.fLineAscent);
                      SELF.DrawOneItem(stringToDraw);
                    END;

                SELF.fCurrentItem:= SELF.fCurrentItem + 1;
                stringToDraw := TListDocument(SELF.fDocument).
 ReportListItem( SELF.fCurrentItem);
            END;
          SELF.fNumberOfItems := SELF.fCurrentItem - 1;
          SELF.fCurrentItem := 0;
 { No item currently being processed }
    END;


    PROCEDURE TListView.DrawOneItem(item: Str255);
    BEGIN
        DrawString(item);
    END;

{ In theory, this method invalidates the area occupied by the item, that 
is, the listDocument will send this message to the view when any single 
item needs to be redrawn and will pass the number of this item as the 
message argument.   In reality, this method invalidates the entire panel 
so as not to leave "holes" in the textual representation of the document. 
 The argument is never used.   }

    PROCEDURE TListView.InvalidateItem(
 itemNumber: INTEGER);
    BEGIN
        SELF.AdjustExtent;
 { In case the size of the view has changed }
        SELF.InvalidRect(SELF.fExtentRect); 
 { AdjustExtent will cause a focus }
    END;

{ Decide what item is indicated by this point; return 0 iff this point 
indicates no item }
    FUNCTION  TListView.PtToIndex(
 testPoint: Point): INTEGER;
    VAR  i: INTEGER;   { FOR Loop Index }
    BEGIN
        PtToIndex := 0;     { Assume the item is NOT found }
        FOR i := 1 TO SELF.fNumberOfItems DO
           IF PtInRect(testPoint, SELF.SetUpBox(i))
             THEN BEGIN
 PtToIndex := i;
 LEAVE       { Don't check the rest }
                  END
    END;

{ Set the line spacing characteristics.  This is a separate method so 
that clients can easily override it without also having to worry about 
setting the font. It assumes that SetPet
has been called and that the view has been focused. }

    PROCEDURE TListView.SetItemHeightAndLineAscent;  
    VAR fInfo: FontInfo;
    BEGiN
      GetFontInfo(fInfo);
      WITH fInfo DO
        BEGIN
          SELF.fItemHeight := ascent + descent + leading + 1;
          SELF.fLineAscent := ascent + (leading DIV 2) - 1;
        END;
    END;

{ Set up the pen for drawing the characters; assumes that we are focused 
on the correct window (or a frame in the correct window); this is a method 
so it can be overridden easily }
    PROCEDURE TListView.SetPen;
    BEGIN
      PenNormal;
      TextFont(SystemFont);
      TextSize(12);
      TextFace([]);
    END;

{ Create a rectangle, for this item. }
    FUNCTION  TListView.SetUpBox(index: INTEGER): Rect;
    VAR  bBox: Rect;
    BEGIN
    { use same left and right as view, calculate the top and
 bottom for this item number}
        WITH bBox DO
            BEGIN
                left := SELF.fExtentRect.left;
                top := (index - 1)* SELF.fItemHeight;
 { Subtract 1 to get the TOP line }
                right := SELF.fExtentRect.right;
                bottom := top + SELF.fItemHeight;
            END;
        SetUpBox := bBox;
    END;

END.


{ TwoLineList View unit which is used in a variant of the MacApp QuadWorld 
Application.
Copyright 1986 by Productivity Products International, Inc. }

UNIT UTwoLineListView;

INTERFACE

USES
  { This set of units are portions of the Macintosh ROM }
    MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,

  { This set of units are portions of MacApp }
    UObject, UList, UMacApp, UListView;

TYPE
    TTwoLineListDocument = OBJECT(TListDocument)
 { an abstract superclass that contains methods
 needed for the proper use of a two-line list view }
     { No additional instance variables }
        FUNCTION
 TTwoLineListDocument.ReportCoordinateString
 (itemNumber: INTEGER): Str255;      
    END;   { of TTwoLineListDocument }

    TTwoLineListView = OBJECT(TListView)
      { No additional instance variables }
        PROCEDURE TTwoLineListView.DrawOneItem
 (item: Str255);  OVERRIDE;    
        PROCEDURE TTwoLineListView.
 SetItemHeightAndLineAscent;   OVERRIDE;
    END;  { TTwoLineListView }

IMPLEMENTATION

{ ***  TTwoLineListDocument  (an abstract superclass )  ** }

    FUNCTION  TTwoLineListDocument.ReportCoordinateString
 (itemNumber: INTEGER): Str255;
    BEGIN
{$IFC qDebug}
 ProgramBreak('Call to TTwoLineListDocument.
 ReportCoordinateString- an abstract superclass'); 
{$ENDC}
    END;
 

{ *****************  TTwoLineListView  ***************}

{ Draw one item which consists of two lines.  Use the
overridden procedure to draw the first line and then augment
with the code to draw the second line. }
  PROCEDURE TTwoLIneListView.DrawOneItem
 (item: Str255);  OVERRIDE;
  VAR myDocument:TTwoLineListDocument;
  BEGIN
 INHERITED DrawOneItem(item);
 Move(-StringWidth(item), SELF.fItemHeight DIV 2);
 
        myDocument := TTwoLineListDocument
 (SELF.fDocument);
      DrawString(myDocument.ReportCoordinateString
 (SELF.fCurrentItem));
    END;

{ Double the item height for a two-line item. }
  PROCEDURE TTwoLineListView.
 SetItemHeightAndLineAscent;  OVERRIDE;
  BEGIN
 INHERITED SetItemHeightAndLineAscent;
 SELF.fItemHeight := 2*SELF.fItemHeight;
  END;

END.

 { MiniIcon ListView unit which is used in a variant of the the MacApp 
QuadWorld Application. Copyright 1986 by Productivity Products International, 
Inc., for MacTutor. }

UNIT UMiniIconListView;

INTERFACE

USES
  { This set of units are portions of the Macintosh ROM }
    MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,

  { This set of units are portions of MacApp }
    UObject, UList, UMacApp, UListView;

TYPE
    TMiniIconListDocument = OBJECT(TListDocument)
 { an abstract superclass that contains methods          needed for the 
proper use of a mini-iconlist view }
      { No additional instance variables }
        FUNCTION  TMiniIconListDocument.ReportIconNumber
 (itemNumber: INTEGER): INTEGER; 
    END;   { of TMiniIconListDocument }
    TMiniIconListView = OBJECT(TListView)
      { No additional instance variables }
        PROCEDURE TMiniIconListView.DrawOneItem
 (item: Str255);  OVERRIDE;    
    END;  { TMiniIconListView }
IMPLEMENTATION
{ ***  TMiniIconListDocument  (an abstract superclass )  *** }
    FUNCTION  TMiniIconListDocument.
 ReportIconNumber(itemNumber: INTEGER): INTEGER;
    BEGIN
{$IFC qDebug}
 ProgramBreak('Call to TMiniIconListDocument.
 ReportIconNumber- an abstract superclass');
{$ENDC}
    END;
{ **************** TMiniIconListView  ***************** }
{ Draw an icon first, then draw the text string }
    PROCEDURE TMiniIconListView.DrawOneItem
 (item: Str255);  OVERRIDE;
   { Draw the mini-icon }
 PROCEDURE DrawIcon;
 VAR  tempRect: Rect;
 tempHandle: Handle;
 myDocument: TMiniIconListDocument;
 BEGIN
    { The rectangle into which the icon will be drawn }
 tempRect := SELF.SetUpBox(SELF.fCurrentItem);
 tempRect.right := tempRect.left + 
 SELF.fItemHeight;
    { Get the icon }
 myDocument := 
 TMiniIconListDocument(SELF.fDocument);
 tempHandle := 
 GetIcon(myDocument.ReportIconNumber
 (SELF.fCurrentItem));
 FailNIL(tempHandle);
    { Draw the Icon }
 PlotIcon(tempRect, tempHandle);
 END;
    BEGIN
 DrawIcon;
 Move(SELF.fItemHeight, 0);
 INHERITED DrawOneItem(item);
    END;
END.
 
AAPL
$103.30
Apple Inc.
+0.80
MSFT
$45.09
Microsoft Corpora
-0.34
GOOG
$577.33
Google Inc.
+5.73

MacTech Search:
Community Search:

Software Updates via MacUpdate

TextSoap 7.4.0 - Flexible text editing u...
TextSoap is for people who work with text. TextSoap effortlessly cleans up text from endlessly different formats. Wash away unwanted characters, spaces, tabs. Fix paragraphs with hard returns at the... Read more
NetShade 6.0.2 - Browse privately using...
NetShade is an Internet security tool that conceals your IP address on the web. NetShade routes your Web connection through either a public anonymous proxy server, or one of NetShade's own dedicated... Read more
Mac DVDRipper Pro 5.0 - Copy, backup, an...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
pwSafe 3.1 - Secure password management...
pwSafe provides simple and secure password management across devices and computers. pwSafe uses iCloud to keep your password databases backed-up and synced between Macs and iOS devices. It is... Read more
StatsBar 1.8 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Path Finder 6.5.5 - Powerful, award-winn...
Path Finder is a file browser that combines the familiar Finder interface with the powerful utilities and innovative features. Just a small selection of the Path Finder 6 feature set: Dual pane... Read more
QuarkXPress 10.2.1 - Desktop publishing...
With QuarkXPress, you can communicate in all the ways you need to -- and always look professional -- in print and digital media, all in a single tool. Features include: Easy to Use -- QuarkXPress is... Read more
Skype 6.19.0.450 - Voice-over-internet p...
Skype allows you to talk to friends, family and co-workers across the Internet without the inconvenience of long distance telephone charges. Using peer-to-peer data transmission technology, Skype... Read more
VueScan 9.4.41 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
Cloud 3.0.0 - File sharing from your men...
Cloud is simple file sharing for the Mac. Drag a file from your Mac to the CloudApp icon in the menubar and we take care of the rest. A link to the file will automatically be copied to your clipboard... Read more

Latest Forum Discussions

See All

Modern Combat 5 Gets a Major Multiplayer...
Modern Combat 5 Gets a Major Multiplayer Update Posted by Jessica Fisher on September 2nd, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Alien Creeps TD Review
Alien Creeps TD Review By Jennifer Allen on September 2nd, 2014 Our Rating: :: EXPENSIVE DEFENSESUniversal App - Designed for iPhone and iPad Alien Creeps TD would be a fun if unremarkable Tower Defense game, but its heavy focus on... | Read more »
The Journey Down: Chapter Two Review
The Journey Down: Chapter Two Review By Jennifer Allen on September 2nd, 2014 Our Rating: :: DARK YET ENTICINGUniversal App - Designed for iPhone and iPad It’s a little dark, in every sense of the word, but The Journey Down:... | Read more »
Function Space, a Social Network App for...
Function Space, a Social Network App for Science, Launches on iOS Posted by Ellis Spice on September 2nd, 2014 [ permalink ] | Read more »
Stupidfast – How Taylor Martinez Switche...
How do you make an Endless Running game more than just another Endless Running game? By adding real life prizes to it, of course! That’s the thinking behind StupidFast: a game designed for football enthusiasts, and the brainchild of former college... | Read more »
Little Raiders: Robin’s Revenge Review
Little Raiders: Robin’s Revenge Review By Jennifer Allen on September 2nd, 2014 Our Rating: :: CASUAL RAIDINGUniversal App - Designed for iPhone and iPad Combining simple combat with village building is a potent combination for... | Read more »
Treasure Tombs: Ra Deal Coming from Bulk...
Treasure Tombs: Ra Deal Coming from Bulkypix and Dark Tonic This Fall Posted by Jessica Fisher on September 2nd, 2014 [ permalink ] Dark Tonic and | Read more »
Pirate Bash Review
Pirate Bash Review By Nadia Oxford on September 2nd, 2014 Our Rating: :: BAD PIRATES, GOOD TIMESUniversal App - Designed for iPhone and iPad Pirate Bash’s turn-based battles add an intriguing twist to a typical physics game.   | Read more »
Tiny Tower Vegas Review
Tiny Tower Vegas Review By Jennifer Allen on September 2nd, 2014 Our Rating: :: STEADY DEVELOPMENTUniversal App - Designed for iPhone and iPad Build a huge tower again but Vegas-style in Tiny Tower Vegas.   | Read more »
The Manhattan Project Review
The Manhattan Project Review By Andrew Fisher on September 2nd, 2014 Our Rating: :: ROCKET SCIENCEUniversal App - Designed for iPhone and iPad The Manhattan Project offers a great Euro-style gameplay experience, but it is totally... | Read more »

Price Scanner via MacPrices.net

Apple refurbished iPads available for up to $...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
Are We Now In The Post-Post-PC Era?
A longtime and thoroughgoing laptop aficionado, I was more than a little dismayed by Steve Jobs’s declaration back in 2010 when he sprang the iPad on an unsuspecting world. that we’d entered a “post-... Read more
PC Outlook Improves, But 2014 Shipments Still...
According to the International Data Corporation (IDC) Worldwide Quarterly PC Tracker, worldwide PC shipments are expected to fall by -3.7 percent in 2014. To hat’s actually an improvement from the... Read more
IDC Lowers Tablet Sales Projections for 2014...
Following a second consecutive quarter of softer than expected demand, International Data Corporation (IDC) has lowered its worldwide tablet plus 2-in-1 forecast for 2014 to 233.1 million units. The... Read more
Apple now offering refurbished 21-inch 1.4GHz...
The Apple Store is now offering Apple Certified Refurbished 21″ 1.4GHz iMacs for $929 including free shipping plus Apple’s standard one-year warranty. Their price is $170 off the cost of new models,... Read more
Save $50 on the 2.5GHz Mac mini, on sale for...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Save up to $300 on an iMac with Apple refurbi...
The Apple Store has Apple Certified Refurbished iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. These are the best prices on... Read more
The Rise of Phablets
Carlisle & Gallagher Consulting Group, a businesses and technology consulting firm focused solely on the financial services industry, has released an infographic depicting the convergence of... Read more
Bad Driver Database App Allows Good Drivers t...
Bad Driver Database 1.4 by Facile Group is a new iOS and Android app that lets users instantly input and see how many times a careless, reckless or just plain stupid driver has been added to the... Read more
Eddy – Cloud Music Player for iPhone/iPad Fre...
Ukraine based CapableBits announces the release of Eddy, its tiny, but smart and powerful cloud music player for iPhone and iPad that allows users to stream or download music directly from cloud... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.