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.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.