home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Pascal / source / list manager package ƒ / TextList.c < prev    next >
Encoding:
Text File  |  1990-01-07  |  52.6 KB  |  1,429 lines  |  [TEXT/MPS ]

  1. /*
  2.  
  3.                      Sample Source Code by Jack A. Littleton
  4.  
  5.                      Example List Manager Application--TextList
  6.                      -------------------------------------------
  7.  
  8.     TextList.c -- C source code for CTextList
  9.     This file and all files in this package are copyright © 1989 by
  10.     Jack A. Littleton, All rights reserved.
  11.     Version 1.0 - December 3, 1989
  12.     
  13.     This package includes:
  14.         TextList.c         -- This file
  15.         TextList.p         -- Pascal source code
  16.         TextList.a         -- Assembly source code
  17.         TextList.r         -- Rez source code for all TextList applications
  18.         PTextList.r        -- Pascal-specific Rez source code
  19.         CTextList.r        -- C-specific Rez source code
  20.         PTextList.make     -- Makefile for Pascal TextList application
  21.         CTextList.make     -- Makefile for C TextList application
  22.         ATextList.make     -- Makefile for Assembly TextList application
  23.         
  24.         NumList.p        -- Pascal source code for NumList application
  25.         NumLDEF.p        -- Pascal source code for NumList List Definition proc
  26.         NumList.c        -- C source code
  27.         NumLDEF.c        -- C source code for List Definition procedure
  28.         NumList.a        -- Assembly source code
  29.         NumLDEF.a        -- Assembly source code for List Definition proc
  30.         NumList.r        -- Rez source code for all TextList applications
  31.         PNumList.make    -- Makefile for Pascal NumList application
  32.         CNumList.make    -- Makefile for C NumList application
  33.         ANumList.make    -- Makefile for Assembly NumList application
  34.         
  35.         SampleList.txt    -- Documentation for this package
  36.         
  37. ABOUT TextList.c:
  38.     This is the C source code for PTextList, a C implementation of an 
  39.     application that uses the List Manager.  This implementation uses the only 
  40.     List Definition (LDEF) that is supplied with the system (LDEF #0), which 
  41.     can handle only text in the cells.
  42.     
  43.     The application handles multiple windows with a single list in each window.
  44.     The list has both vertical and horizontal scroll bars.  The cell size, font,
  45.     font size, and number of cells per row can be set by the user.  A "List"
  46.     menu allows you to set flags that affect how the list reacts to mouse
  47.     clicks (the selFlags field in the ListHandle).  The items that are set in
  48.     the List menu do not take affect until you create a new list.  When a new
  49.     window is created, the application looks at which items in the List menu
  50.     have been selected, and creates the list with those characteristics.  Note
  51.     that changes in the List menu do not affect previously created lists.  This
  52.     means that you can have several different lists open with different
  53.     characteristics, allowing you to see the differences.
  54.     
  55.     The "Edit" menus allows cut/paste, but not through normal scrap techniques.
  56.     Cells can be cut/pasted from one window to another, but not from CTextList
  57.     to another application.  This was implemented to show how to get, set and
  58.     clear data from a cell.
  59.     
  60.     Find is supported in the "File" menu.  This uses the LSearch procedure to
  61.     find a match in the list.
  62.     
  63.     The windows and list support growing and zooming.
  64.     
  65.     Other important notes on implementation are given in the documentation for
  66.     the appropriate routine.
  67.     
  68. A NOTE:  This is just an example of a program that uses the List Manager.  It
  69.     is not meant to be a full-blown application, and may not be suitable as
  70.     a template for a new application.  It is just meant to show as many List
  71.     Manager routines as possible.  In fact, this program was written as
  72.     research for a programming tutorial and was never planned as a application.
  73.  
  74. BUGS AND OTHER INSECTS:
  75. Window title -- The window title in the DoNew() procedure acts really wierd.
  76.     The way the window is supposed to work is the word "Untitled", followed by
  77.     a dash, then the window number.  In the C version, however, several garbage
  78.     characters are inserted between the dash and the window number.  I have
  79.     spent several days trying to fix this problem to no avail.  This kind of
  80.     problem with strings is one reason why I really dislike C.
  81.  
  82. Crash after quitting -- Here's another one for the "Believe it or not" file.
  83.     When the font is changed to a font that is not supplied with the Apple 
  84.     System disk (i.e. not Chicago, Geneva, New York, Times, Courier, etc.), the
  85.     program will crash when a menu item is selected after quitting, but only
  86.     while still in the MPW Shell, and while there were windows (lists) open.  
  87.     In other words, this only happens when the program CTextList is launched 
  88.     from within the MPW Shell.
  89. */
  90.  
  91. #include <Types.h>            /* Mac type definitions                        */
  92. #include <Resources.h>        /* Resource Manager headers                    */
  93. #include <QuickDraw.h>        /* QuickDraw headers                        */
  94. #include <Windows.h>        /* Window Manager headers                    */
  95. #include <OSUtils.h>        /* OS Utilities headers                        */
  96. #include <Controls.h>        /* Control Manager headers                    */
  97. #include <Desk.h>            /* Desk Manager headers                        */
  98. #include <Dialogs.h>        /* Dialog Manager headers                    */
  99. #include <Events.h>            /* Event Manager headers                    */
  100. #include <Fonts.h>            /* Font Manager (for GetFNum)                */
  101. #include <Lists.h>            /* List Manager headers                        */
  102. #include <Memory.h>            /* Memory Manager headers                    */
  103. #include <Menus.h>            /* Menu Manager headers                        */
  104. #include <Packages.h>        /* Package Manager (for NumToString, etc.)    */
  105. #include <SegLoad.h>        /* Segment Loader Manager (for UnloadSeg)    */
  106. #include <TextEdit.h>        /* TextEdit (for TEInit)                    */
  107. #include <ToolUtils.h>        /* Toolbox Utilities Manager                */
  108. #include <Traps.h>            /* Trap addresses                            */
  109.  
  110. #include <StdIO.h>
  111. #include <String.h>
  112.  
  113. /* MENU RESOURCE CONSTANTS */
  114. #define    NumMenus        5            /* Number of menus */
  115.  
  116. #define    AppleMenu        1111        /* Resource ID of apple menu    */
  117. #define AppleID            1            /* Index ID of apple menu        */
  118.  
  119. #define FileMenu        1112        /* Resource ID of File menu    */
  120. #define FileID            2            /* Index ID of apple menu    */
  121. #define NewItem            1            /* Item ID for "New List"    */
  122. #define CloseItem        2            /* Item ID for "Close"        */
  123. #define AddItem            3            /* Item ID for "New Row"    */
  124. #define DeleteItem        4            /* Item ID for "Delete Row"    */
  125. #define FindItem        5            /* Item ID for "Find"        */
  126. #define Quit            6            /* Item ID for "Quit"        */
  127.  
  128. #define EditMenu        1113        /* Resource ID of Edit menu        */
  129. #define EditID            3            /* Index ID of Edit menu        */
  130. #define UndoItem        1            /* Item ID of "Undo"            */
  131. #define CutItem            3            /* Item ID of "Cut"                */
  132. #define CopyItem        4            /* Item ID of "Copy"            */
  133. #define PasteItem        5            /* Item ID of "Paste"            */
  134. #define ClearItem        6            /* Item ID of "Clear"            */
  135. #define SClipItem        8            /* Item ID of "Show Clipboard"    */
  136.  
  137. #define ListMenu        1114        /* Resource ID of List Menu                */
  138. #define ListID            4            /* Index ID of List Menu                */
  139. #define    OneSelItem        1            /* Item ID of "One Selection Only"        */
  140. #define    DragWOShItem    2            /* Item ID of "Drag w/o Shift            */
  141. #define    NoDJointItem    3            /* Item ID of "No Disjoing Select."        */
  142. #define    NoExtendItem    4            /* Item ID of "Don't Extent"            */
  143. #define    NoExpandItem    5            /* Item ID of "Don't Exp. as Rect"        */
  144. #define    UseSenseItem    6            /* Item ID of "Use Sense"                */
  145. #define NoHliteItem        7            /* Item ID of "Don't Hilite MT cells"    */
  146.  
  147. #define CellMenu        1115        /* Resource ID of Cell Menu        */
  148. #define CellID            5            /* Index ID of Cell Menu        */
  149. #define IndentItem        1            /* Item ID of "Indentation…"    */
  150. #define    CSizeItem        2            /* Item ID of "Cell Size…"        */
  151. #define    FSizeItem        4            /* Item ID of "Font Size…"        */
  152.  
  153. #define FontSMenu        1            /* Resource ID of "Font" sub-menu    */
  154.  
  155. /* DIALOG/ALERT BOX CONSTANTS */
  156. #define CellDlog        128            /* Res ID of CellSize/Indentation dialog    */
  157. #define FontSDlog        129            /* Res ID of Find dialog                    */
  158. #define FindDlog        130            /* Res ID of FontSize/Cells per Col dilaog    */
  159. #define AboutDlog        1112        /* Res ID of About dialog                    */
  160.  
  161. /* STRING RESOURCE CONSTANTS */
  162. #define theStrList        128            /* Res ID of string list         */
  163. #define indentInd        1            /* Index ID for "Indentation"    */
  164. #define vertInd            2            /* Index ID for "vertical"        */
  165. #define horizInd        3            /* Index ID for "horizontal"    */
  166. #define cSizeInd        4            /* Index ID for "Cell Size"        */
  167.  
  168. #define    theWind            1113
  169.  
  170. extern _DataInit();
  171.  
  172. typedef struct {
  173.     WindowRecord    docWindow;
  174.     ListHandle        docList;
  175. } DocumentRecord, *DocumentPeek;
  176.  
  177.     Rect            gDragArea;            /* Area in which a window can be dragged        */
  178.     Rect            gGrowArea;            /* Minimum area a window can be shrunk to        */
  179.     WindowPtr        gActvWindow;        /* The active window                            */
  180.     DocumentPeek    gWindInfo;            /* Information about the window                    */
  181.     MenuHandle        gMenuItem[NumMenus];/* An array of the application's menus            */
  182.     EventRecord        gEvents;            /* The event record returned by GetNextEvent    */
  183.     Boolean            gFinished;            /* Flag set when program is to terminate        */
  184.     Ptr                gClipboard;            /* Pointer to our private scrap                    */
  185.     short            gClipLen;            /* Size of the private scrap                    */
  186.     MenuHandle        gFontSMenu;            /* Handle to the font sub-menu                    */
  187.     Str255            gFontName;            /* Name of the current font                        */
  188.     short            gFontItem;            /* Item ID of the current font                    */
  189.     short            gFontSize;            /* Size of the current font                        */
  190.     short            gNumWind;            /* Number of open windows                        */
  191.  
  192. void DoNew();
  193.  
  194. /*
  195. #    Initialize -- Initialize toolbox managers, menus and global variables
  196. #
  197. #    Called by -- Main
  198. #
  199. #    Description -- First, the application's heap zone is expanded and a block
  200. #                of master pointers are allocated, then the toolbox managers are
  201. #                initialized.  Then the menus are called from the resource fork
  202. #                and inserted into the menu bar.  The "Font" menu is initialized
  203. #                next by looking for the defualt font in the font menu.  If the
  204. #                font is not found, then the applicationFont is used instead.
  205. #                Finally, the global variables are defined, and a new window
  206. #                is displayed.
  207. */
  208. void Initialize()
  209.  
  210. {
  211.     short            i;                    /* for loop control variable        */
  212.     short            menuID;                /* Menu ID of menu being added        */
  213.     Str255            *dfltString = "\pCourier";    /* Name of default font        */
  214.     Str255            theString;            /* Font name returned by GetItem    */
  215.     short            numItems;            /* Number of items in font menu        */
  216.     GrafPtr            screenPort;            /* Returned by GetWMgrPort            */
  217.     Rect            screenArea;            /* The screen dimensions            */
  218.     
  219. MaxApplZone();
  220. MoreMasters();                                /* Get a block of master pointers    */
  221. InitGraf(&qd.thePort);                        /* Initialize QuickDraw                */
  222. InitFonts();                                /* Initialize font Manager            */
  223. InitCursor();                                /* Initialize cursor (to arrow)        */
  224. InitWindows();                                /* Initialize window manager        */
  225. InitMenus();                                /* Initialize menu manager            */
  226. TEInit();                                    /* Initialize TextEdit                */
  227. InitDialogs(nil);                            /* Initialize Dialog Manager        */
  228.  
  229. FlushEvents(everyEvent,0);                    /* Empty the event queue            */
  230. GetWMgrPort(screenPort);                    /* Get the window manager's port    */
  231. SetPort(screenPort);                        /* Set up the graf port                */
  232. screenArea = qd.screenBits.bounds;            /* Get the size of the screen        */
  233. SetRect(&gDragArea, 5, 25,                    /* Set the area in which a window    */
  234.         qd.screenBits.bounds.right - 5,        /* can be dragged                    */
  235.         qd.screenBits.bounds.bottom - 10);
  236. SetRect(&gGrowArea, 65, 65,                    /* Set the minimum size a window     */
  237.         qd.screenBits.bounds.right - 5,        /* can be shrunk to                 */
  238.         qd.screenBits.bounds.right - 10);
  239.  
  240. menuID = 1111;                                /* Initialize to the first menu's res ID    */
  241. for (i=1;i<=NumMenus;i++)                    /* For each menu the application owns:        */
  242.     {
  243.     gMenuItem[i] = GetMenu(menuID++);        /* Get the menu, then increment menu ID */
  244.     InsertMenu(gMenuItem[i],0);                /* Insert the menu in the menu bar        */
  245.     }
  246. AddResMenu(gMenuItem[AppleID],'DRVR');        /* Add DA resources to the apple menu            */
  247. gFontSMenu = GetMenu(FontSMenu);            /* Get the font sub-menu                        */
  248. AddResMenu(gFontSMenu, 'FONT');                /* Add the font resources to the font sub-menu    */
  249. InsertMenu(gFontSMenu, -1);                    /* Insert the font sub-menu                        */
  250. numItems = CountMItems(gFontSMenu);            /* Find how many items are in the font menu        */
  251. for (i=1;i<=numItems;i++)                    /* Keep looping until default font is found        */
  252.     {
  253.     GETITEM(gFontSMenu, i, &theString);        /* Get the name of the item                        */
  254.     if (EQUALSTRING(&theString, dfltString, false, false))    /* If it is the default font    */
  255.         {
  256.         CheckItem(gFontSMenu, i, true);        /* Check the item                        */
  257.         gFontItem = i;                        /* Set the global itemID variable        */
  258.         gFontName = theString;                /* Set the global font name variable    */
  259.         }
  260.     }
  261. DrawMenuBar();                                /* Draw the menu bar                        */
  262. gActvWindow = nil;                            /* There is no window open                    */
  263. gClipboard = NewPtr(256);                    /* Initialize space for the private scrap    */
  264. gFontSize = 10;                                /* Initialize the default font size            */
  265. gFinished = false;                            /* Initialize the finished flag                */
  266. gNumWind = 0;                                /* Initialize the window counter            */
  267. DoNew();                                    /* Open an Untitled window                    */
  268. return;
  269. }
  270.  
  271. /*
  272. #    DoAboutBox -- Show dialog box with program information
  273. #
  274. #    Called by -- DoAppleMenu
  275. #
  276. #    Description -- Displays a dialog box, usually containing a picture that
  277. #                gives information about the program.  The dialog terminates
  278. #                after the user clicks in the dialog.
  279. */
  280. void DoAboutBox()
  281.  
  282. {
  283.     Boolean            doneDialog;            /* Set to true if finished with dialog    */
  284.     DialogPtr        doDialog;            /* The dialog pointer                    */
  285.     short            itemHit;            /* Item returned by ModalDialog()        */
  286.     WindowPtr        thisPort;            /* Port active when called                 */
  287.  
  288. doneDialog = false;                            /* Initialize flag                */
  289. GetPort(&thisPort);                            /* Get current port                */
  290. doDialog = GetNewDialog(AboutDlog,nil,(DialogPtr)-1);    /* Get the dialog    */
  291. SetPort(doDialog);                            /* Set the Dialog's port        */
  292.  
  293. do /* while (doneDialog != true */            /* Keep looping until finished    */
  294.     {
  295.     ModalDialog(nil, &itemHit);                /* Find which item was clicked in     */
  296.     switch (itemHit)
  297.         {
  298.         case 1:
  299.             doneDialog = true;                /* If the OK button was hit, the quit    */
  300.             break;
  301.         }
  302.     } while (doneDialog != true);
  303.  
  304. DisposDialog(doDialog);                        /* Get rid of the dialog    */
  305. HiliteMenu(0);                                /* Unhilite the apple menu    */
  306. SetPort(thisPort);                            /* Restore the port            */
  307. return;
  308. }
  309.  
  310. /*
  311. #    DoAppleMenu -- An item was selected from the Apple (DA) menu
  312. #
  313. #    Called by -- HandleMenuSelect
  314. #
  315. #    Description -- There are two cases that need to be checked.  If the itemID
  316. #                passed as a parameter is 1, then call the DoAboutBox routine.
  317. #                If the item ID is not one, then it is assumed that a Desk
  318. #                Accessory was selected, and the DA should be opened.  Note that
  319. #                item 2 should be a dashed line that is disabled; therefore
  320. #                itemID should never be 2.
  321. */
  322. void DoAppleMenu(itemID)
  323.     short            itemID;
  324.  
  325. {
  326.     short            result;                /* Result returned by GetDeskAcc--ignored        */
  327.     Str255            dAName;                /* Name of item selected-passed to OpenDeskAcc    */
  328.     
  329. if (itemID == 1)                            /* If the About… item was picked, then    */
  330.     DoAboutBox();                            /* Bring up the About box                */
  331. else
  332.     {                                        /* Otherwise, a DA was selected        */
  333.     GetItem(gMenuItem[AppleID], itemID, &dAName);    /* Get the name of the DA    */
  334.     result = OpenDeskAcc(&dAName);            /* And open it--ignore the result    */
  335.     HiliteMenu(0);                            /* Unhilite the menu                */
  336.     }
  337. return;
  338. }
  339.  
  340. /*
  341. #    DoUnhilite -- Dim menu items when no list is present
  342. #
  343. #    Called by -- DoClose (only when last window is closed)
  344. #
  345. #    Description -- This routine dims menu items that can cause errors when
  346. #                selected with no list present (i.e. any menu item that calls a
  347. #                routine that expects a valid ListHandle)
  348. */
  349. void DoUnhilite()
  350.  
  351. {
  352. DisableItem(gMenuItem[FileID], 2);
  353. DisableItem(gMenuItem[FileID], 3);
  354. DisableItem(gMenuItem[FileID], 4);
  355. DisableItem(gMenuItem[FileID], 5);
  356. return;
  357. }
  358.  
  359. /*
  360. #    DoHilite -- Hilite menu items when a new list is created
  361. #
  362. #    Called by -- DoNew (when no windows were present before DoNew call)
  363. #
  364. #    Description -- This routines hilites the menu items dimmed by DoUnhilite 
  365. #                when a new window is created and it is the only window (i.e.
  366. #                gNumWind = 0 before window was created)
  367. */
  368. void DoHilite()
  369. {
  370. EnableItem(gMenuItem[FileID], 2);
  371. EnableItem(gMenuItem[FileID], 3);
  372. EnableItem(gMenuItem[FileID], 4);
  373. EnableItem(gMenuItem[FileID], 5);
  374. return;
  375. }
  376.  
  377. /*
  378. #    DoNew -- Create a new window and list
  379. #
  380. #    Called by -- Initialize and DoFileMenu
  381. #
  382. #    Description -- This routine allocates space for a new document record,
  383. #                which is used in the wStorage parameter in the GetNewWindow
  384. #                call.  A new window is then created.  If one or more windows
  385. #                are present before the new window is created, the window size
  386. #                is scaled down to allow windows behind the new window to be 
  387. #                visible.  After scaling, the window is assigned a name in the
  388. #                format : Untitled—<window number>, and then the window is
  389. #                finally drawn.
  390. #
  391. #    LIST MANAGER SPECIFICS:
  392. #    ---- ------- ---------
  393. #    Setting selFlags -- Before the list is created, each of the items in the 
  394. #                List menu is looked at to see if the user has selected that 
  395. #                item.  If the item is checked, the constant representing that
  396. #                flag is added to a flag constant that is later added to the 
  397. #                selFlags field in the ListHandle.
  398. #
  399. #    Creating the list -- After the menu items have been scanned, a new list is
  400. #                created with the List Manager routine LNew.  RView is the
  401. #                enclosing rectangle of the list, which is the same as the
  402. #                window the list is in, except for a 15 pixel margin on the 
  403. #                bottom and right sides of the window to allow space for the
  404. #                scroll bars.  DataBounds is the number of cells the list is
  405. #                initialized with.  
  406. #
  407. #    Drawing the list -- Once the window and list have been drawn, the List
  408. #                manager routine LDoDraw is called, which draws the list when
  409. #                necessary.
  410. */
  411. void DoNew()
  412.  
  413. {
  414.     short        fNum;                    /* The font number used for the list    */
  415.     short        theMark;                /* Returned by GetItemMark                */
  416.     char        flags;                    /* Flags for the ListHandle                */
  417.     char        numStr[1];                /* String version of the window number    */
  418.     char        temp[255];                /* Temporary string for window title    */
  419.     char        windTitle[255];            /* Title of the new window                */
  420.     Rect        rView;                    /* Size of the initial list                */
  421.     Rect        dataBounds;                /* Number of cells in the initial list    */
  422.     Point        cSize;                    /* Size of the cells in the list        */
  423.     Ptr            windRec;                /* Window storage pointer                */
  424.     
  425. windRec = NewPtr(sizeof(DocumentRecord));        /* Allocate space for document record        */
  426. gActvWindow = GetNewWindow(1113, windRec, (WindowPtr)-1);    /* Get a new window                */
  427. gActvWindow->portRect.top = gActvWindow->portRect.top + (gNumWind * 20);    /* Set the sieze    */
  428. gActvWindow->portRect.left = gActvWindow->portRect.left + (gNumWind * 20);
  429. SetPort(gActvWindow);                        /* Set the port to the new window            */
  430. if (gNumWind == 0)                            /* If this is the only window, then hilite    */
  431.     DoHilite();                                /* the necessary menu items                    */
  432. gNumWind += 1;                                /* Increment the number of windows            */
  433. NumToString((long)gNumWind, &numStr[0]);    /* Create the window title                    */
  434. SetWTitle(gActvWindow, strcat("Untitled—", &numStr[0]));
  435. gWindInfo = (DocumentPeek)gActvWindow;        /* Get the document record pointer            */
  436. GETFNUM(&gFontName, &fNum);                    /* Get the font number of the current font    */
  437. gActvWindow->txFont = fNum;                    /* Set the current font                        */
  438. gActvWindow->txSize = gFontSize;                /* And font size                            */
  439. rView = gActvWindow->portRect;                /* Create the rView rectangle for LNew        */
  440. rView.right -= 15;                            /* Remember to allow enough space for the    */
  441. rView.bottom -= 15;                            /* scroll bars                                */
  442. ShowWindow(gActvWindow);                        /* Make the windows visible                    */
  443. SetRect(&dataBounds, 0, 0, 4, 1);            /* Set the number of default cells            */
  444. SetPt(&cSize, 100, 16);                        /* Set the default cell size                */
  445.  
  446. flags = 0;                                    /* Initialize flags */
  447. GetItemMark(gMenuItem[ListID], 1, &theMark);    /* lOnlyOne bit        */
  448. if (theMark == checkMark)
  449.     flags += lOnlyOne;
  450. GetItemMark(gMenuItem[ListID], 2, &theMark);    /*lExtendDrag bit    */
  451. if (theMark == checkMark)
  452.     flags += lExtendDrag;
  453. GetItemMark(gMenuItem[ListID], 3, &theMark);    /* lNoDisjoint bit */
  454. if (theMark == checkMark)
  455.     flags += lNoDisjoint;
  456. GetItemMark(gMenuItem[ListID], 4, &theMark);    /* lNoExtend bit */
  457. if (theMark == checkMark)
  458.     flags += lNoExtend;
  459. GetItemMark(gMenuItem[ListID], 5, &theMark);    /* lNoRect bit */
  460. if (theMark == checkMark)
  461.     flags += lNoRect;
  462. GetItemMark(gMenuItem[ListID], 6, &theMark);    /* lUseSense bit */
  463. if (theMark == checkMark)
  464.     flags += lUseSense;
  465. GetItemMark(gMenuItem[ListID], 7, &theMark);    /* lNoNilHilite bit */
  466. if (theMark == checkMark)
  467.     flags += lNoNilHilite;
  468.  
  469.                                             /* vvv Create a new list vvv */
  470. gWindInfo->docList = LNEW(&rView, &dataBounds, cSize, 
  471.                         0, gActvWindow, true, false, true, true);
  472. (*gWindInfo->docList)->selFlags = flags;        /* Set the selFlags field    */
  473. LDoDraw(true, gWindInfo->docList);            /* Allow drawing            */
  474. return;
  475. }
  476.  
  477. /*
  478. #    DoClose -- Handle closing a window and disposing of its contents
  479. #
  480. #    Called by -- DoFileMenu and HandleMouseDown
  481. #
  482. #    Description -- This routine is called when "Close" is selected from the
  483. #                "File" menu, or the mouse is clicked in the go away region of 
  484. #                the window.  Any contents of the window should be handled
  485. #                (i.e. disposed) before the window is closed.  Before doing any
  486. #                closing, the windowKind field should be checked.  If it is
  487. #                negative, the window to be closed belongs to a desk accessory.
  488. #                When this happens, call CloseDeskAcc and pass the value in 
  489. #                windowKind.  If a window is closed, and no other windows belong
  490. #                to the application, the gNumWind variable is set to zero, and
  491. #                the DoUnhilite procedure is called to dim the necessary menu
  492. #                items.
  493. #
  494. #    LIST MANAGER SPECIFICS
  495. #    ---- ------- ---------
  496. #    Disposing of the list -- Before closing the window, you need to call
  497. #                LDispose to get rid of the list.
  498. */
  499. void DoClose()
  500.  
  501. {
  502.     WindowPtr        testWindow;            /* The window to be closed        */
  503.     DocumentPeek    whatWindow;            /* Information about the window    */
  504.  
  505. testWindow = FrontWindow();                    /* Get the frontmost window            */
  506. whatWindow = (DocumentPeek)testWindow;        /* Get information of the window    */
  507. if ((whatWindow->docWindow).windowKind > 0)    /* If it is an application…            */
  508.     {
  509.     LDispose(whatWindow->docList);            /* Get rid of the list                */
  510.     CloseWindow(testWindow);                /* Get rid of the window            */
  511.     gActvWindow = FrontWindow();                /* Get the new frontmost window        */
  512.     if (gActvWindow == nil)                    /* If there is no front window        */
  513.         {
  514.         gNumWind = 0;                        /* Reset the window counter            */
  515.         DoUnhilite();                        /* Unhilight the appropriate menus    */
  516.         }
  517.     else                                    /* If there is a front window        */
  518.         {
  519.         SelectWindow(gActvWindow);            /* Make sure it is selected                */
  520.         gWindInfo = (DocumentPeek)gActvWindow;/* Get information about the new window    */
  521.         }
  522.     }
  523. else                                        /* If the window is not an app…    */
  524.     {                                        /* It is a DA                    */
  525.     CloseDeskAcc((whatWindow->docWindow).windowKind);    /* Close the DA     */
  526.     }
  527. HiliteMenu(0);
  528. return;
  529. }
  530.  
  531. /*
  532. #    DoQuit -- Stop the application
  533. #
  534. #    Called by -- DoFileMenu
  535. #
  536. #    Description -- The main function of this routine is to set the "finished"
  537. #                flag so the main event loop will stop looping.  I also close
  538. #                all the windows and it's associated items.  I know that I don't
  539. #                have to do this because the system will get rid of all the
  540. #                application's memory when it quits, but hey, I like to clean
  541. #                up afterwards.
  542. #
  543. #    LIST MANAGER SPECIFICS
  544. #    ---- ------- ---------
  545. #    Disposing of the list -- BEFORE closing the window, you must get rid of the
  546. #                list by calling LDispose.
  547. */
  548. void DoQuit()
  549.  
  550. {
  551.     short            errNo;                /* Returned by FSClose                */
  552.     WindowPtr        testWindow;            /* False when cancel is chosen        */
  553.     DocumentPeek    windPeek;            /* Document record of top window    */
  554.     Boolean            stopLoop;            /* Flag to stop window-closing loop    */
  555.  
  556. stopLoop = false;                            /* Initialize loop flag                */
  557. testWindow = FrontWindow();                    /* Get the top window                */
  558. windPeek = (DocumentPeek)testWindow;        /* Get the top window's doc record    */
  559. if (testWindow != nil)                        /* If there is a window active        */
  560.     {
  561.     do
  562.         {
  563.         LDispose(windPeek->docList);        /* Get rid of the list                */
  564.         CloseWindow(testWindow);            /* Get rid of the window            */
  565.         testWindow = FrontWindow();            /* Get the new front window            */
  566.         if (testWindow != nil)                /* If there is still a front window */
  567.             windPeek = (DocumentPeek)testWindow;    /* Get window information    */
  568.         else
  569.             stopLoop = true;                /* Otherwise, stop.                    */
  570.         }
  571.     while (stopLoop != true);
  572.     }
  573. gFinished = true;                            /* Stop running the program            */
  574. return;
  575. }
  576.  
  577. /*
  578. #    DoFind -- A List Manager specific routine that searches for data in a cell
  579. #
  580. #    Called By -- DoFileMenu
  581. #
  582. #    Description -- This routine puts up a dialog box that the user will type
  583. #                the text to be found into.  After the user clicks the OK button,
  584. #                the List Manager routine LSearch to find the cell (if any) that
  585. #                data is located in.  Note that theCell must be initialized to
  586. #                (0,0) because the LSearch routine starts searching at theCell.
  587. */
  588. void DoFind()
  589.  
  590. {
  591.     DialogPtr        theDialog;            /* Pointer to the dialog box             */
  592.     short            itemHit;            /* Item returned by ModalDialog            */
  593.     Boolean            doneDialog;            /* ModalDialog loop flag                */
  594.     short            theType;            /* Returned by GetDitem--not used        */
  595.     short            dataLen;            /* Length of the find text                */
  596.     Cell            theCell;            /* The cell the text is found in        */
  597.     Handle            item;                /* A handle to the dialog editText item    */
  598.     Rect            box;                /* Returned by GetDItem--not used        */
  599.     char            theString[255];        /* The find text                        */
  600.     DialogRecord    dStorage;            /* The dialog record                    */
  601.     
  602. theDialog = GetNewDialog(FindDlog, &dStorage, (DialogPtr)-1);    /* Get the dialog    */
  603. doneDialog = false;                            /* Initialize the loop flag    */
  604. do /* while (doneDialog != true */            /* Keep looping until finished with dialog    */
  605.     {
  606.     ModalDialog(nil, &itemHit);                /* Get item clicked in                */
  607.     switch (itemHit)
  608.         {
  609.         case 1:                                /* If the OK button was hit, then    */
  610.             doneDialog = true;                /* Set the flag to quit the dialog     */
  611.             GetDItem(theDialog, 2, &theType, &item, &box);    /* Get the editText item */
  612.             GetIText(item, &theString[0]);    /* Get the find text                */
  613.             dataLen = strlen(&theString[0]);/* Set the length of the scrap        */
  614.             SetPt(&theCell, 0, 0);            /* Initialize the cell                */
  615.             if (LSearch(&theString[0], dataLen, nil, &theCell, gWindInfo->docList))
  616.                 LSetSelect(true, &theCell, gWindInfo->docList);
  617.             else
  618.                 SysBeep(20);                /* Beep if nothing was found        */
  619.             break;
  620.         }
  621.     } while (doneDialog != true);
  622. CloseDialog(theDialog);                        /* Get rid of the dialog            */
  623. return;
  624. }
  625.  
  626. /*
  627. #    DoFileMenu -- Respond to the user selecting an item in the File Menu
  628. #
  629. #    Called By -- HandleMenuSelect
  630. #
  631. #    Description -- This routine is simply a case statement that calls a routine
  632. #                that handles the selected item
  633. #
  634. #    LIST MANAGER SPECIFICS
  635. #    ---- ------- ---------
  636. #    Adding a row -- When the itemID "AddItem" is passed in the item ID parameter,
  637. #                the case statement simply calls LAddRow to add another row.  The
  638. #                rowNum parameter is passed 32767 to ensure that the row is added
  639. #                to the end of the list.
  640. #    Deleting a row -- When the item ID "DeleteItem" is passed in the item ID
  641. #                parameter, the case statement finds which cell (if any) is
  642. #                selected, then calls LDelRow to delete the row the selected
  643. #                cell is in.
  644. */
  645. void DoFileMenu(itemID)
  646.     short            itemID;
  647.  
  648. {
  649.     short            newRow;                /* Number of the new row    */
  650.     Cell            theCell;            /* Generic cell variable    */
  651.     
  652. switch (itemID)
  653.     {
  654.     case NewItem:                            /* Get a new list */
  655.         DoNew();
  656.         break;
  657.     
  658.     case CloseItem:                            /* Close a list        */
  659.         DoClose(&gActvWindow);
  660.         break;
  661.         
  662.     case AddItem:                            /* Add a new row */
  663.         newRow = LAddRow(1, 32767, gWindInfo->docList);
  664.         break;
  665.     
  666.     case DeleteItem:                        /* Get rid of a new row */
  667.         SetPt(&theCell, 0, 0);                /* Initialize theCell to the first cell in the list    */
  668.         if (LGetSelect(true, &theCell, gWindInfo->docList))    /* If a cell is selected            */
  669.             {
  670.             LDelRow(1, theCell.v, gWindInfo->docList);        /* Delete the row that cell is in    */
  671.             }
  672.         break;
  673.     
  674.     case FindItem:                            /* Find data in a cell    */
  675.         DoFind();
  676.         break;
  677.         
  678.     case Quit:                                /* Quit the program        */
  679.         DoQuit();
  680.         break;
  681.     }
  682. HiliteMenu(0);
  683. return;
  684. }
  685.  
  686. /*
  687. #    DoEditMenu -- Respond to the user selecting an item from the Edit menu
  688. #
  689. #    Called By -- HandleMenuSelect
  690. #
  691. #    Description -- The routine is a case statement that handles all the items
  692. #                in the edit menu.
  693. #
  694. #    LIST MANAGER SPECIFICS
  695. #    ---- ------- ---------
  696. #    Cutting a cell -- Cut was implemented by using LGetCell to get the data, 
  697. #                then calling LClrCell to clear the cell.
  698. #    Copying a cell -- Same as cutting, but LClrCell wasn't called.
  699. #    Pasting a cell -- Paste was implemented by using LSetCell.
  700. #    Clearing a cell -- Clear was implemented by using LClrCell.
  701. #    About LGetSelect -- Before LGetSelect is called, the theCell parameter is
  702. #                initialized to the first cell in the list (0,0).  The reason
  703. #                for this is that LGetSelect finds the first cell that is
  704. #                hilighted that is *equal to or greater than* the theCell
  705. #                parameter.  Therefore, if you want to find the first cell in
  706. #                the entire list, set the theCell parameter to (0,0).
  707. */
  708. void DoEditMenu(itemID)
  709.     short            itemID;
  710.  
  711. {
  712.     Cell            theCell;            /* Generic cell variable                */
  713.     short            dataLen;            /* Length of data in the private scrap    */
  714.     
  715. if (gActvWindow != nil)                        /* If a window exists, then    */
  716.     {
  717.     switch(itemID)
  718.         {
  719.         case UndoItem:                        /* Undo is not supported    */
  720.             break;
  721.         
  722.         case CutItem:                        /* Cut data from a cell                                */
  723.             SetPt(&theCell, 0, 0);            /* Initialize theCell to the first cell in the list */
  724.             if (LGetSelect(true, &theCell, gWindInfo->docList))    /* Find the selected cell        */
  725.                 {
  726.                 gClipLen = 256;                                    /* Initialize the scrap length    */
  727.                 LGetCell(gClipboard, &gClipLen, &theCell, gWindInfo->docList);    /* Get the data     */
  728.                 LClrCell(&theCell, gWindInfo->docList);            /* Clear data in the cell        */
  729.                 LDraw(&theCell, gWindInfo->docList);                /* Draw the cell                */
  730.                 }
  731.             else
  732.                 SysBeep(20);
  733.             break;
  734.         
  735.         case CopyItem:                        /* Copy data from a cell    */
  736.             SetPt(&theCell, 0, 0);
  737.             if (LGetSelect(true, &theCell, gWindInfo->docList))
  738.                 {
  739.                 gClipLen = 256;
  740.                 LGetCell(gClipboard, &gClipLen, &theCell, gWindInfo->docList);
  741.                 LDraw(&theCell, gWindInfo->docList);
  742.                 }
  743.             else
  744.                 SysBeep(20);
  745.             break;
  746.         
  747.         case ClearItem:                        /* Clear data from a cell */
  748.             SetPt(&theCell, 0, 0);
  749.             if (LGetSelect(true, &theCell, gWindInfo->docList))
  750.                 {
  751.                 LClrCell(&theCell, gWindInfo->docList);
  752.                 LDraw(&theCell, gWindInfo->docList);
  753.                 }
  754.             else
  755.                 SysBeep(20);
  756.             break;
  757.             
  758.         case PasteItem:                        /* Paste data into a cell    */
  759.             SetPt(&theCell, 0, 0);
  760.             if (LGetSelect(true, &theCell, gWindInfo->docList))
  761.                 {
  762.                 LSetCell(gClipboard, gClipLen, &theCell, gWindInfo->docList);
  763.                 LDraw(&theCell, gWindInfo->docList);
  764.                 }
  765.             else
  766.                 SysBeep(20);
  767.             break;
  768.         }
  769.     }
  770. HiliteMenu(0);
  771. return;
  772. }
  773.  
  774. /*
  775. #    DoListMenu -- Respond to the user selecting an item from the List menu
  776. #
  777. #    Called By -- HandleMenuSelect
  778. #
  779. #    Description -- This routine simply checks or unchecks the menu item passed
  780. #                as a parameter.  When a new list is created, these menu items
  781. #                are polled to see which flags should be set.
  782. */
  783. void DoListMenu(itemID)
  784.     short            itemID;
  785.  
  786. {
  787.     short            theMark;                /* Mark returned by GetItemMark        */
  788.     
  789. GetItemMark(gMenuItem[ListID], itemID, &theMark);    /* Get the mark of the item        */
  790. if (theMark == checkMark)                            /* If it is a check mark then    */
  791.     CheckItem(gMenuItem[ListID], itemID, false);        /* Uncheck the item                */
  792. else
  793.     CheckItem(gMenuItem[ListID], itemID, true);        /* Otherwise check it            */
  794. HiliteMenu(0);
  795. return;
  796. }    
  797.  
  798. /*
  799. #    DoFontMenu -- Respond to a user selecting an item in the Font sub menu
  800. #
  801. #    Called By -- HandleMenuSelect
  802. #
  803. #    Description -- When an item is selected, the "old" Font name is unchecked,
  804. #                the new font is set, and it checked in the menu.  Then the
  805. #                font name and item global variables are set.
  806. */
  807. void DoFontMenu(itemID)
  808.     short            itemID;
  809. {
  810.     Str255            *theString;            /* Name of the font selected    */
  811.  
  812. CheckItem(gFontSMenu, gFontItem, false);    /* Uncheck the current font name        */
  813. GETITEM(gFontSMenu, itemID, theString);        /* Get the name of the selected font    */
  814. CheckItem(gFontSMenu, itemID, true);        /* Check the item                        */
  815. gFontName = *theString;                        /* Set the global font var                */
  816. gFontItem = itemID;                            /* Set the global item Id                */
  817. HiliteMenu(0);
  818. return;
  819. }
  820.  
  821. /*
  822. #    DoCellMenu -- Respond to the user selecting an item in the Cell menu
  823. #
  824. #    Called by -- HandleMenuSelect
  825. #
  826. #    Description -- This routine sends the itemID to a case statement where it
  827. #                is handled.  If the itemID is "IndentItem", then the vertical
  828. #                and horizontal coordinates are retrieved from the dialog box
  829. #                used to ask the user for the coordinates, then sets the indent
  830. #                field of the ListHandle to those coordinates.  If itemID is
  831. #                CSizeItem, then the coordinates of the cell size are retrieved
  832. #                from the dialog box, then set by using LCellSize.  If itemID is
  833. #                FSizeItem, then the font size entered in the dialog box is
  834. #                set in the txSize field of the grafPort.  This change does not
  835. #                take affect until a new list is created.
  836. */
  837. void DoCellMenu(itemID)
  838.     short            itemID;
  839. {
  840.     Str255            theString;            /* String returned by GetIndString/GetIText */
  841.     DialogRecord    dStorage;            /* Storage for the dialog record            */
  842.     DialogPtr        theDialog;            /* Pointer to the dialog                    */
  843.     short            theType;            /* Not used--passed to GetDItem                */
  844.     Handle            item;                /* Handle to item, returned by GetDItem        */
  845.     Rect            box;                /* Not used--passed to GetDItem                */
  846.     Point            origIndent;            /* Data indent before changing                */
  847.     long            vertIndent;            /* Vertical indentation set by user            */
  848.     long            horizIndent;        /* Horizontal indentation set by user        */
  849.     short            itemHit;            /* Item number returned by ModalDialog        */
  850.     Boolean            doneDialog;            /* Flag set when user is done with dialog    */
  851.     Handle            vertItem;            /* Handle to vertical indent. text box        */
  852.     Handle            horizItem;            /* Handle to horizontal indent. text box    */
  853.  
  854. doneDialog = false;                            /* Initialize the doneDialog flag        */
  855. switch(itemID)
  856.     {
  857.     case IndentItem:                        /* Set the indent field of the List        */
  858.         if (gActvWindow != nil)                /* If a window is present…                */
  859.             {
  860.             /* Draw a dialog and set the editText items */
  861.             theDialog = GetNewDialog(CellDlog, &dStorage, (DialogPtr)-1);
  862.             GetDItem(theDialog, 4, &theType, &item, &box);
  863.             GETINDSTRING(&theString, theStrList, vertInd);
  864.             SETITEXT(item, &theString);
  865.             GetDItem(theDialog, 5, &theType, &item, &box);
  866.             GETINDSTRING(&theString, theStrList, horizInd);
  867.             SETITEXT(item, &theString);
  868.             GetDItem(theDialog, 6, &theType, &item, &box);
  869.             GETINDSTRING(&theString, theStrList, indentInd);
  870.             SETITEXT(item, &theString);
  871.             origIndent = (*gWindInfo->docList)->indent;
  872.             vertIndent = origIndent.v;
  873.             horizIndent = origIndent.h;
  874.             GetDItem(theDialog, 2, &theType, &vertItem, &box);
  875.             NUMTOSTRING(vertIndent, &theString);
  876.             SETITEXT(vertItem, &theString);
  877.             GetDItem(theDialog, 3, &theType, &horizItem, &box);
  878.             NUMTOSTRING(horizIndent, &theString);
  879.             SETITEXT(horizItem, &theString);
  880.             ShowWindow(theDialog);
  881.             do /* while (doneDialog != true */
  882.                 {
  883.                 /* When an event occurs, check if the OK button was hit */
  884.                 ModalDialog(nil, &itemHit);
  885.                 switch (itemHit)
  886.                     {
  887.                     case 1:
  888.                         /* If the OK button was hit, get the editText items and set the indent field */
  889.                         doneDialog = true;
  890.                         GETITEXT(vertItem, &theString);
  891.                         STRINGTONUM(&theString, &vertIndent);
  892.                         GETITEXT(horizItem, &theString);
  893.                         STRINGTONUM(&theString, &horizIndent);
  894.                         SetPt(&origIndent, (short)horizIndent, (short)vertIndent);
  895.                         (*gWindInfo->docList)->indent = origIndent;
  896.                         LUpdate(gActvWindow->visRgn, gWindInfo->docList);
  897.                         break;
  898.                     }
  899.                 } 
  900.             while (doneDialog != true);
  901.             CloseDialog(theDialog);
  902.             }
  903.         else
  904.             SysBeep(20);
  905.         break;
  906.     
  907.     case CSizeItem:                            /* Set the cell size     */
  908.         if (gActvWindow != nil)
  909.             {
  910.             theDialog = GetNewDialog(CellDlog, &dStorage, (DialogPtr)-1);
  911.             GetDItem(theDialog, 4, &theType, &item, &box);
  912.             GETINDSTRING(&theString, theStrList, vertInd);
  913.             SETITEXT(item, &theString);
  914.             GetDItem(theDialog, 5, &theType, &item, &box);
  915.             GETINDSTRING(&theString, theStrList, horizInd);
  916.             SETITEXT(item, &theString);
  917.             GetDItem(theDialog, 6, &theType, &item, &box);
  918.             GETINDSTRING(&theString, theStrList, cSizeInd);
  919.             SETITEXT(item, &theString);
  920.             origIndent = (*gWindInfo->docList)->cellSize;
  921.             vertIndent = origIndent.v;
  922.             horizIndent = origIndent.h;
  923.             GetDItem(theDialog, 2, &theType, &vertItem, &box);
  924.             NUMTOSTRING(vertIndent, &theString);
  925.             SETITEXT(vertItem, &theString);
  926.             GetDItem(theDialog, 3, &theType, &horizItem, &box);
  927.             NUMTOSTRING(horizIndent, &theString);
  928.             SETITEXT(horizItem, &theString);
  929.             ShowWindow(theDialog);
  930.             do /* while (doneDialog != true */
  931.                 {
  932.                 ModalDialog(nil, &itemHit);
  933.                 switch (itemHit)
  934.                     {
  935.                     case 1:
  936.                         /* If the OK button was hit, get the editText items the user set,
  937.                            and call LCellSize to change the cell size */
  938.                         doneDialog = true;
  939.                         GETITEXT(vertItem, &theString);
  940.                         STRINGTONUM(&theString, &vertIndent);
  941.                         GETITEXT(horizItem, &theString);
  942.                         STRINGTONUM(&theString, &horizIndent);
  943.                         SetPt(&origIndent, (short)horizIndent, (short)vertIndent);
  944.                         LCellSize(&origIndent, gWindInfo->docList);
  945.                         break;
  946.                     }
  947.                 } 
  948.             while (doneDialog != true);
  949.             CloseDialog(theDialog);
  950.             }
  951.         else
  952.             SysBeep(20);
  953.         break;
  954.     
  955.     case FSizeItem:                            /* Set the font size */
  956.         theDialog = GetNewDialog(FontSDlog, &dStorage, (DialogPtr)-1);
  957.         GetDItem(theDialog, 2, &theType, &item, &box);
  958.         SETITEXT(item, "\p10");
  959.         ShowWindow(theDialog);
  960.         do /* while (doneDialog != true */
  961.             {
  962.             ModalDialog(nil, &itemHit);
  963.             switch (itemHit)
  964.                 {
  965.                 case 1:
  966.                     /* If the OK button was hit, get the editText item and set the font size */
  967.                     doneDialog = true;
  968.                     GETITEXT(item, &theString);
  969.                     STRINGTONUM(&theString, &horizIndent);
  970.                     gFontSize = (short)horizIndent;
  971.                     break;
  972.                 }
  973.             } 
  974.         while (doneDialog != true);
  975.         CloseDialog(theDialog);
  976.         break;
  977.     }
  978. HiliteMenu(0);
  979. }
  980.  
  981. /*
  982. #    HandleMenuSelect -- Determines which menu was selected from
  983. #
  984. #    Called By -- HandleMouseDown/HandleKeyDown
  985. #
  986. #    Description -- This routines finds the menuID and itemID of the item
  987. #                selected by the user.  The menu information is passed in the
  988. #                parameter menuInfo.  The high-order word contains the menuID
  989. #                and the low-order word holds the itemID.  These items are
  990. #                extracted by using HiWord and LoWord, respectively.  The menuID
  991. #                is sent to a case statement which calls a routine that handles
  992. #                that menu.
  993. */
  994. void HandleMenuSelect(menuInfo)
  995.     long            menuInfo;
  996.  
  997. {
  998.     short            menuID;                /* Menu's resource ID     */
  999.     short            itemID;                /* ID of item selected    */
  1000.  
  1001. menuID = HiWord(menuInfo);                    /* High order word holds menu ID    */
  1002. itemID = LoWord(menuInfo);                    /* Low order word holds item ID        */
  1003.  
  1004. if (menuID != 0)                            /* If a real, existing menu was selected     */
  1005.     switch (menuID)                            /* Then handle the event in the menu        */
  1006.         {
  1007.         case AppleMenu:                        /* The apple menu was selected    */
  1008.             DoAppleMenu(itemID);
  1009.             break;
  1010.         
  1011.         case FileMenu:                        /* The File menu was selected    */
  1012.             DoFileMenu(itemID);
  1013.             break;
  1014.         
  1015.         case EditMenu:                        /* The Edit menu was selected    */
  1016.             DoEditMenu(itemID);
  1017.             break;
  1018.         
  1019.         case ListMenu:                        /* The List menu was selected    */
  1020.             DoListMenu(itemID);
  1021.             break;
  1022.         
  1023.         case CellMenu:                        /* The Cell menu was selected    */
  1024.             DoCellMenu(itemID);
  1025.             break;
  1026.         
  1027.         case FontSMenu:                        /* The Font submenu was selected    */
  1028.             DoFontMenu(itemID);
  1029.         }
  1030. }
  1031.  
  1032. /*
  1033. #    HandleContent -- Respond to a mouse event inside a window
  1034. #
  1035. #    Called By -- HandleMouseDown
  1036. #    
  1037. #    Description -- When a mouse-down event occurs in the content portion of a
  1038. #                window (when FindWindow returns inContent), the application must
  1039. #                take appropriate action:
  1040. #                    1. Make The Window Active - If the window passed in the
  1041. #                        whichWindow parameter is not the active window, then
  1042. #                        it must be made active by calling SelectWindow.  
  1043. #                        The global window pointer and document record must
  1044. #                        reflect the changes.
  1045. #                    2. If the window is already active, you need to find if
  1046. #                        the click occurred inside an object in the window
  1047. #                        such as a TextEdit box, control, or indicator.  Note
  1048. #                        that the TextEdit, Control and List Managers
  1049. #                        (among others) require the mouse down loaction in
  1050. #                        local coordinates, so the routine GlobalToLocal
  1051. #                        is called to get the local point coordinates.
  1052. #
  1053. #    LIST MANAGER SPECIFICS
  1054. #    ---- ------- ---------
  1055. #    Click occurs in the list -- A check must be made to see if the mouse down
  1056. #                occurred in the list.  You do this by getting the list rect
  1057. #                from the rView field in the ListHandle and calling PtInRect.
  1058. #                Remember that rView returns the rect coordinates in the LOCAL
  1059. #                coordinate system, so the point returned by GlobalToLocal
  1060. #                should be used.
  1061. #                    If the mouse down was in the list, then call the List 
  1062. #                Manager routine LClick.  This routine will handle any actions
  1063. #                needed in the list (selecting, moving scroll bars) according
  1064. #                to the list definition procedure (LDEF).
  1065. #                    IMPORTANT NOTE:  The rView rectangle DOES NOT include the
  1066. #                scroll bars.  Before using PtInRect to find if the click 
  1067. #                occurred in the list, add 15 to the bottom and right fields of
  1068. #                the rect to include the scroll bars.  If you don't do this, the
  1069. #                list will not scroll.
  1070. */
  1071. void HandleContent(whichWindow)
  1072.     WindowPtr        whichWindow;
  1073.  
  1074. {
  1075.     Point            thePoint;            /* Events.where in local coordinates    */
  1076.     Rect            theRect;            /* The area the list occupies            */
  1077.     Boolean            yorn;                /* Junk result from LClick                */
  1078.  
  1079. gActvWindow = FrontWindow();                /* Get the frontmost window                    */
  1080. thePoint = gEvents.where;                    /* Set up a point to be converted to local    */
  1081. GlobalToLocal(&thePoint);                    /* Convert to local coordinates                */
  1082. if (whichWindow != gActvWindow)                /* If the window selected isn't frontmost    */
  1083.     {
  1084.     SelectWindow(whichWindow);                /* Make it the frontmost window    */
  1085.     gActvWindow = whichWindow;                /* Set the global VAR            */
  1086.     gWindInfo = (DocumentPeek)gActvWindow;    /* Set the window information    */
  1087.     }
  1088.     
  1089. if (gWindInfo->docList != nil)                /* If a list exists, then    */
  1090.     {
  1091.     theRect = (*gWindInfo->docList)->rView;    /* Get the bounding rect of the list        */
  1092.     theRect.right +=  15;                    /* Account for the vertical and                */
  1093.     theRect.bottom += 15;                    /* horizontal scroll bars                    */
  1094.     if (PtInRect(&thePoint, &theRect))        /* If the mouse click was in the list, then    */
  1095.         yorn = LClick(&thePoint, gEvents.modifiers, gWindInfo->docList);    /* Tell the list it was clicked in    */
  1096.     }
  1097. }
  1098.  
  1099. /*
  1100. #    HandleGrow -- Respond to a mouse down event in the grow icon
  1101. #
  1102. #    Called by -- HandleMouseDown
  1103. #
  1104. #    Description -- When a mouse down event occurs in the grow icon (when
  1105. #                FindWindow returns inGrow) the application must grow the
  1106. #                window, following the movements of the mouse.  This i
  1107. #                this is accomplished by calling GrowWindow, which returns the
  1108. #                new width and height of the window (or 0 if no change was
  1109. #                made).  The width is in the low-order word of the long result
  1110. #                and the height is in the high-order word.  These values are
  1111. #                extracted using LoWord and HiWord.  After getting this result,
  1112. #                SizeWindow is called, passing the height and width returned by
  1113. #                GrowWindow.  After this is done, the window is marked as "dirty"
  1114. #                and updated by calling InvalRect.
  1115. #
  1116. #    LIST MANAGER SPECIFICS
  1117. #    ---- ------- ---------
  1118. #    Growing the list -- You can use the height and width values returned by
  1119. #                GrowWindow in the ListManager routine LSize, remembering to
  1120. #                subtract room for the scroll bars, if any.
  1121. */
  1122. void HandleGrow(whichWindow)
  1123.     WindowPtr        whichWindow;
  1124.  
  1125. {
  1126.     long            windSize;            /* The new size of window after it is grown    */
  1127.     short            vert;                /* The vertical component of growth            */
  1128.     short            horiz;                /* The horizontal component of growth        */
  1129.  
  1130. windSize = GrowWindow(whichWindow,&gEvents.where,&gGrowArea);    /* Grow the window        */
  1131. vert = HiWord(windSize);                /* High order word holds vertical change    */
  1132. horiz = LoWord(windSize);                /* Low order word holds horizontal change    */
  1133. SizeWindow(whichWindow, horiz, vert, true);    /* Make changes to the window            */
  1134. LSize(horiz-15, vert-15, gWindInfo->docList);/* Make changes to the list                */
  1135. InvalRect(&whichWindow->portRect);        /* Get the window ready for updating        */
  1136. }
  1137.  
  1138. /*
  1139. #    HandleMouseDown -- Take care of a mouse-down event.
  1140. #
  1141. #    Called by -- Main program
  1142. #
  1143. #    Description --  The major block of the program is a case statement that
  1144. #                branches to the constant returned by the window manager 
  1145. #                function FindWindow.  Most of the events are handled inside the
  1146. #                case statement; a few have external routines.  The routines
  1147. #                that are called from this routine are:
  1148. #                    HandleMenuSelect    (inMenuBar)
  1149. #                    HandleContent        (inContent)
  1150. #                    HandleGrow            (inGrow)
  1151. */
  1152. void HandleMouseDown()
  1153.  
  1154. {
  1155.     WindowPtr        whichWindow;        /* WindowPtr returned by FindWindow            */
  1156.     DocumentPeek    windPeek;            /* Information about window                    */
  1157.     long            menuInfo;            /* Menu Information returned by MenuSelect    */
  1158.     short            dPartCode;            /* Part code returned by FindWindow            */
  1159.     short            width;                /* Vertical change made by zooming            */
  1160.     short            height;                /* Horizontal change made by zooming        */
  1161.     Rect            zoomRect;            /* Window rect after zooming                */
  1162.  
  1163. dPartCode = FindWindow(&gEvents.where, &whichWindow);    /* Find where click occrred    */
  1164. switch (dPartCode)
  1165.     {
  1166.     case inMenuBar:                        /* Click occurred in menu bar    */
  1167.         menuInfo = MenuSelect(&gEvents.where);    /* Get menuID,  item ID    */
  1168.         HandleMenuSelect(menuInfo);
  1169.         break;
  1170.     
  1171.     case inContent:                     /* Click in content region        */
  1172.         HandleContent(whichWindow);
  1173.         break;
  1174.     
  1175.     case inDrag:                        /* Click in drag region            */
  1176.         DragWindow(whichWindow, &gEvents.where, &gDragArea);    /* Drag the window */
  1177.         break;
  1178.     
  1179.     case inGrow:                        /* Click in grow icon            */
  1180.         HandleGrow(whichWindow);
  1181.         break;
  1182.     
  1183.     case inGoAway:                        /* Click in close box            */
  1184.         if (TrackGoAway(whichWindow, &gEvents.where))    /* If mouse pressed and released        */
  1185.             DoClose();                            /* inside box, then close the window    */
  1186.         break;
  1187.     
  1188.     case inSysWindow:                    /* Click in DA window            */
  1189.         SystemClick(&gEvents, whichWindow);
  1190.         break;
  1191.     
  1192.     case inZoomIn:                        /* Click in zoom box            */
  1193.     case inZoomOut:    
  1194.         if (TrackBox(whichWindow,&gEvents.where,dPartCode))    
  1195.             {                            /* If mouse pressed and released in box, then    */
  1196.             windPeek = (DocumentPeek)whichWindow;    /* Get window info                    */
  1197.             ZoomWindow(whichWindow,dPartCode,true);    /* Zoom the window                    */
  1198.             zoomRect = whichWindow->portRect;        /* Get new window coordinates        */
  1199.             width = zoomRect.right - zoomRect.left;    /* Find width and height of window    */
  1200.             height = zoomRect.bottom - zoomRect.top;/* Call LSize to zoom list            */
  1201.             LSize(width-15, height-15, windPeek->docList);
  1202.             InvalRect(&whichWindow->portRect);        /* Mark window as needing update    */
  1203.             }
  1204.         break;
  1205.     }
  1206. return;
  1207. }
  1208.  
  1209. /*
  1210. #    HandleUpdateEvt -- Do a window update
  1211. #
  1212. #    Called by -- main event loop
  1213. #
  1214. #    Description -- When GetNextEvent returns updateEvt, this routine is called
  1215. #                to redraw the contents of a window.
  1216. #
  1217. #    LIST MANAGER SPECIFICS
  1218. #    ---- ------- ---------
  1219. #    LUpdate -- The List Manager routine LUpdate is called to re-draw the window
  1220. #                that needs updating.
  1221. */
  1222. void HandleUpdateEvt()
  1223.  
  1224. {
  1225.     short            yorn;                /* for loop control variable    */
  1226.     WindowPtr        theWindow;            /* Window to be updated            */
  1227.     DocumentPeek    theList;            /* Information about the window    */
  1228.     GrafPtr            savePort;            /* Active port when called        */
  1229.     
  1230. theWindow = (WindowPtr)gEvents.message;        /* Get the window to be updated                        */
  1231. theList = (DocumentPeek)theWindow;            /* Find window information                            */
  1232. GetPort(&savePort);                            /* Save this port                                    */
  1233. SetPort(theWindow);                            /* Get the window's port, in case it's different    */
  1234.  
  1235. BeginUpdate(theWindow);                        /* Start the update            */
  1236.     EraseRect(&(theWindow->portRect));            /* Erase the window        */
  1237.     LUpdate(theWindow->visRgn, theList->docList);    /* Update the list    */
  1238.     DrawGrowIcon(theWindow);                    /* Draw the grow icon    */
  1239. EndUpdate(theWindow);                        /* End the update            */
  1240. SetPort(savePort);                            /* Resore the original port    */
  1241. }
  1242.  
  1243. /*
  1244. #    HandleActivateEvt -- Make a window active, deactivate another window
  1245. #
  1246. #    Called by -- main event loop
  1247. #
  1248. #    Description -- When an activate event is needed, GetNextEvent returns
  1249. #                activateEvt, plus a flag in the modifiers field.  If the flag
  1250. #                is an activate flag (bit 0 is 1 -- see Inside Mac), then
  1251. #                a grow icon (if any) is drawn, and scroll bars (if any) are
  1252. #                made active.  If the flag is a deactivate flag (bit 0 is 0),
  1253. #                then the grow icon is erased and any scroll bars are inactivated.
  1254. #
  1255. #    LIST MANAGER SPECIFICS
  1256. #    ---- ------- ---------
  1257. #    LActivate -- The list manager routine LActivate is called to make a list
  1258. #                either active or inactive.
  1259. */
  1260. void HandleActivateEvt()
  1261.  
  1262. {
  1263.     WindowPtr        theWindow;            /* Window that is active/inactive    */
  1264.     DocumentPeek    windPeek;            /* Information about the window        */
  1265.     Rect            invH;                /* Grow icon rect to be erased        */
  1266.     
  1267. theWindow = (WindowPtr)gEvents.message;        /* The window to be (in)activated    */
  1268. windPeek = (DocumentPeek)theWindow;            /* Get window information            */
  1269. if ((gEvents.modifiers & 1) == 1)            /* If it is an activate event, then    */
  1270.     {
  1271.     SetPort(theWindow);                        /* Set the port to the window's        */
  1272.     gActvWindow = theWindow;                    /* Make this window the active one    */
  1273.     LActivate(true, windPeek->docList);        /* Activate the list                */
  1274.     DrawGrowIcon(theWindow);                /* Draw the grow icon                */
  1275.     }
  1276. else                                        /* If this is a deactivate event    */
  1277.     {
  1278.     LActivate(false, windPeek->docList);    /* Inactivate the list                */
  1279.     SetRect(&invH, theWindow->portRect.right - 14,    /* Create the grow icon rect    */
  1280.                    theWindow->portRect.bottom - 14,
  1281.                    theWindow->portRect.right,
  1282.                    theWindow->portRect.bottom);
  1283.     EraseRect(&invH);                        /* Erase the grow icon                */
  1284.     }
  1285. }
  1286.  
  1287. /*
  1288. #    HandleKeyDown -- Respond to a key being pressed.
  1289. #
  1290. #    Called by -- main event loop
  1291. #
  1292. #    Description -- There are several special cases to be checked for this
  1293. #                routine.  If the command key is depressed when the key is down,
  1294. #                then the key down event is a command key equivalent, and the
  1295. #                character that represents the key is passed to the Menu Manager
  1296. #                routine MenuKey.
  1297. #                If the command key is not pressed, then the character should be
  1298. #                passed to the application.  There are several non-printin keys
  1299. #                that need to be handled specially.  These keys are the carrriage
  1300. #                return (13), tab (9), backspace (8), and enter (3).  If the key
  1301. #                pressed wansn't any of these keys, then the character should be
  1302. #                sent to the application.
  1303. #
  1304. #    LIST MANAGER SPECIFICS
  1305. #    ---- ------- ---------
  1306. #    The following special cases are handled in the following way:
  1307. #        CR -- Advance one row in same column
  1308. #        Tab -- Advance one column in the same row.  If the current cell is the
  1309. #            last cell in the row, then go to the first column in the next row.
  1310. #            (For more information on how CR's and tabs are handled, see the
  1311. #            description of LNextCell in the List Manager chapter of Inside 
  1312. #            Macintosh.)
  1313. #        Backspace -- Delete data in the cell
  1314. #        Enter -- Unselect the currently selected cell.
  1315. #        Any printing character -- add the character to the data for the cell.
  1316. */
  1317. void HandleKeyDown(modifiers)
  1318.     short            modifiers;
  1319.  
  1320. {
  1321.     char        theKey;                    /* The key that was depressed        */
  1322.     Cell        theCell;                /* Generic cell variable            */
  1323.     Ptr            dataPtr;                /* Pointer to data in cell            */
  1324.     short        dataLen;                /* Length of data in cell            */
  1325.     long        menuInfo;                /* Returned by menu key                */
  1326.     
  1327. if ((modifiers & cmdKey) == cmdKey)        /* If the command key was down, then    */
  1328.     {
  1329.     menuInfo = MenuKey(LoWord(gEvents.message & charCodeMask));    /* Get the menuID, item ID    */
  1330.     HandleMenuSelect(menuInfo);
  1331.     }
  1332. else                                    /* Command key not down    */
  1333.     {
  1334.     SetPt(&theCell, 0, 0);                /* Initialize theCell parameter    */
  1335.     if (LGetSelect(true, &theCell, gWindInfo->docList))
  1336.         {
  1337.         theKey = LoWord(gEvents.message & charCodeMask);
  1338.         switch(theKey)
  1339.             {
  1340.             case 13:                    /* Carriage return    */
  1341.                 LSetSelect(false, &theCell, gWindInfo->docList);
  1342.                 if (LNextCell(false, true, &theCell, gWindInfo->docList))
  1343.                     LSetSelect(true, &theCell, gWindInfo->docList);
  1344.                 else
  1345.                     {
  1346.                     theCell.v = 0;
  1347.                     LSetSelect(true, &theCell, gWindInfo->docList);
  1348.                     }
  1349.                 break;
  1350.             
  1351.             case 9:                        /* Tab pressed    */
  1352.                 LSetSelect(false, &theCell, gWindInfo->docList);
  1353.                 if (LNextCell(true,true, &theCell, gWindInfo->docList))
  1354.                     LSetSelect(true, &theCell, gWindInfo->docList);
  1355.                 else
  1356.                     {
  1357.                     theCell.v = 0;
  1358.                     LSetSelect(true, &theCell, gWindInfo->docList);
  1359.                     }
  1360.                 break;
  1361.             
  1362.             case 8:                        /* Backspace    */
  1363.                 dataLen = 256;
  1364.                 LGetCell(dataPtr, &dataLen, &theCell, gWindInfo->docList);
  1365.                 if (dataLen !=0)
  1366.                     LSetCell(dataPtr, dataLen-1, &theCell, gWindInfo->docList);
  1367.                 break;
  1368.             
  1369.             case 3:                        /* Enter    */
  1370.                 LSetSelect(false, &theCell, gWindInfo->docList);
  1371.                 break;
  1372.                 
  1373.             default:                    /* Printable char    */
  1374.                 LAddToCell(&theKey, 1, &theCell, gWindInfo->docList);
  1375.                 LDraw(&theCell, gWindInfo->docList);
  1376.                 break;
  1377.             }
  1378.         }
  1379.     }
  1380. }
  1381.  
  1382. /*
  1383. #    The Main Program
  1384. #
  1385. #    Called by -- The entry point
  1386. #
  1387. #    Description -- The main program is used to initialize any variables and
  1388. #                data structures.  After this, the program enters an "event 
  1389. #                loop".  The event loop calls SystemTask, which handles DA's and
  1390. #                other system necessities, then calls GetNextEvent, which returns
  1391. #                an event constant when an event occurs.
  1392. */
  1393. void main()
  1394.  
  1395. {
  1396. UnloadSeg((Ptr) _DataInit);
  1397. Initialize();
  1398. do
  1399.     {
  1400.     SystemTask();
  1401.     if (GetNextEvent(everyEvent, &gEvents))    /* Find which event occurred    */
  1402.         {
  1403.         switch (gEvents.what)
  1404.             {
  1405.             case mouseDown:                    /* Mouse button pressed            */
  1406.                 HandleMouseDown();
  1407.                 break;
  1408.                 
  1409.             case keyDown:                    /* Key pressed                    */
  1410.                 HandleKeyDown(gEvents.modifiers);
  1411.                 break;
  1412.             
  1413.             case autoKey:
  1414.                 break;
  1415.             
  1416.             case updateEvt:                    /* Window needs updating        */
  1417.                 HandleUpdateEvt();
  1418.                 break;
  1419.             
  1420.             case activateEvt:                /* Window needs activating        */
  1421.                 HandleActivateEvt();
  1422.                 break;
  1423.             
  1424.             default:
  1425.                 break;
  1426.             }
  1427.         }
  1428.     } while (gFinished != true);
  1429. }