;; -*- Mode:Common-Lisp; Package:MACTOOLBOX; Base:10; Fonts:(CPTFONT HL10B HL12I CPTFONT CPTFONTB) -*- 

;Ï1;; INSTRUCTIONS for EXAMPLES in this FILE:Ï*
;Ï1;;     *  Compile and load this file.  For example, if you are reading this in a Zmacs buffer, then use META-Z.Ï*
;Ï1;;         Also, see Implementation Note after the REQUIRE form below.Ï*
;Ï1;;     *  Make sure the default TB Server is running, enter Ï*(tb:launch-default-tb-server t)Ï1 in aÏ*
;Ï1;;         listener.  (You will have to click on the microExplorer window to reselect it after the launch.)Ï*
;Ï1;;     * Shrink the microExplorer window until it occupies the lower half of the screen leaving the upper halfÏ*
;Ï1;;         free for the window  some of these examples create.Ï*
;Ï1;;     * Enter Ï*(tb:Ï2example-nameÏ*)Ï1 in a listenerÏ*
;Ï1;;     * If the example puts up its own window, then click on it to select the TB Server.Ï*
;Ï1;;        If the example does NOT put up its own window (e.g., the menu examples) then following theÏ*
;Ï1;;        instructions printed in the Listener and click on the "tbserver" item from the Apple Menu in theÏ*
;Ï1;;        Menu Bar to see your example.Ï*
;Ï1;;     * The best way to tell when your example is running is to what the Menu Bar change.Ï*
;Ï1;;     * After you have clicked on "Quit" in the File Menu on the Menu Bar, you will have to click on theÏ*
;Ï1;;        microExplorer window to reselect it.Ï*


(require  "TOOLBOX-MACROS" "SYS:PUBLIC-MX;TOOLBOX-MACROS")
;Ï1;; IMPLEMENTATION NOTE:  This file requires macros in the TOOLBOC-MACROS file of the PUBLIC-MXÏ*
;Ï1;; directory (the same directory this file normally resides in).  The above REQUIRE form should load theÏ*
;Ï1;; macro file automatically.  However, if you are keeping your files in non-standard places, you will have toÏ*
;Ï1;; load the macro file yourself.Ï*



;Ï1;;; Ï4DRAWING METHODS EXAMPLEÏ*Ï*
(defun Ï4EXAMPLE-DRAWINGÏ* (&optional (sleep-time 3))
  (declare (values ignore))
  
  ;Ï1; Open a window and make it the current port.Ï*
  (with-cWindow (window :title "Ï3Example DrawingÏ*")
    ;Ï1; IMPLEMENTATION NOTE:  The macros such s WITH-CWINDOW, WITH-CWINDOW-RES,Ï*
    ;Ï1; WITH-WINDOW, and WITH-WINDOW-RES are the much preferred way to create, use, and dispose ofÏ*
    ;Ï1; a temporary window.  A new window of the appropriate variety is created use the macro arguments.Ï*
    ;Ï1; A  symbol (Ï*windowÏ1, in this case) is bound to it.  Finally, the new window is made to be the currentÏ*
    ;Ï1; port for drawing withing the body of the macro (the following Ï*letÏ1, in this case).Ï*
    ;Ï1;Ï*
    ;Ï1; Upon normal or abnormal exit from the body, the previous port is restored and the new window isÏ*
    ;Ï1; disposed of thereby freeing all associated Macintosh memory.  If you had specified the :WSTORATEÏ*
    ;Ï1; argument for the window (i.e., the new window is to use previously allocated memory and willÏ*
    ;Ï1; presumably be used again elsewhere) then the new window is merely closed which frees up it newÏ*
    ;Ï1; contents but does not free up the window itself.Ï*
    ;Ï1;Ï*
    ;Ï1; PROGRAMMING NOTE:  'C' Windows (i.e., windows built on color grafPorts) should be used for allÏ*
    ;Ï1; new work--even when the window is to be displayed on a monochrome screen.Ï*

    (sleep 1)
    (let ((rect      (make-instance 'Rect :left 40 :top 10 :right 130 :bottom 40))
	  (oval      (make-instance 'Oval :left 150 :top 10 :right 240 :bottom 40))
	  (roundrect (make-instance 'RoundRect :left 260 :top 10 :right 350
				    :bottom 40)))
      ;Ï1; tell each object to frame itself, paint itself, and invert itself with a short wait in betweenÏ*
      (dolist (message '(:frame :paint :invert))
	(send rect message)
	(sleep 1)
	(send oval message)
	(sleep 1)
	(send roundrect message)
	(sleep 1)
	(send rect :offset 0 40)
	(send oval :offset 0 40)
	(send roundrect :offset 0 40)
	(sleep sleep-time))
      );Ï1;let
          Ï*);Ï1;with-window
    Ï*);Ï1;example-drawingÏ*



;Ï1;;; Ï4POLYGON EXAMPLEÏ*Ï*
(defun Ï4EXAMPLE-POLYGON Ï*(&optional (sleep-time 5))
  (declare (values ignore))
  
  (with-cWindow (window :title "Ï3Example PolygonÏ*")
    (with-instance (poly Polygon)
      ;Ï1; IMPLEMENTATION NOTE:  The WITH-INSTANCE macro is a convenient way to create a temporaryÏ*
      ;Ï1; instance of a flavor during the execution of a body of code and then dispose of it upon normalÏ*
      ;Ï1; or abnormal exit from the body.  This macro can be used only with flavors which accept aÏ*
      ;Ï1; :DISPOSE message (e.g., PixPat, Region, PixMap, Polygon, Picture, etc.).Ï*
      ;Ï1;Ï*
      ;Ï1; In addition, certain flavors (e.g., Region, Polygon, Picture) carry warnings that only one can beÏ*
      ;Ï1; open at one time.  If you always use this macro to create instances of these flavors, it will signalÏ*
      ;Ï1; a  MULTIPLE-OPEN-INSTANCE-ERROR error if more than one instance is created at run time.  ItÏ*
      ;Ï1; cannot, however, detect duplicates of these instances created in other manners (e.g., by directÏ*
      ;Ï1; MAKE-INSTANCE).

             Ï*;Ï1;  Define the polygon.  We will define an unusually shaped concave one.Ï*
      (!MoveTo 100 10)
      (!LineTo 150 10)
      (!LineTo  60 50)
      (!LineTo 150 90)
      (!LineTo 100 90)
      (!LineTo 100 10)

      ;Ï1; PROGRAMMING NOTE:  The code between the WITH-INSTANCE and the !ClosePoly act to defineÏ*
      ;Ï1; the polygon.  During this phase, QuickDraw accumulates information about the object you areÏ*
      ;Ï1; defining (in thie case, a polygon).  The !ClosePoly tells QuickDraw to take what its got and make aÏ*
      ;Ï1; graphics object out of it.  The code after the !ClosePoly simply operates of the "pre-defined"Ï*
      ;Ï1; graphics objects.Ï*
      (!ClosePoly)

Ï1              Ï*;Ï1;  Now that the polygon is defined, Quickdraw can perform a number of operations on it.Ï*
      (dolist (message '(:frame :paint :invert))
	(send Poly message)
	(send Poly :offset 100 0)
	(sleep 1))
      (send Poly :fill !dkgray)

      ;;Ï1  Sleep for a few seconds, so we have time to admire our handiwork, then exit.Ï*
      (sleep sleep-time)))
  );Ï1;example-polygonÏ*



;Ï1;;; Ï4PICTURE EXAMPLESÏ*Ï*
(defun Ï4EXAMPLE-PICTURE Ï*(&optional (sleep-time 5))
  (with-cwindow (window :title "Ï3Example PictureÏ*")
Ï1        Ï*;Ï1;  Make the clipRgn small, so !DrawPicture will work.Ï*
    (!ClipRect (send window :portRect))
    (let ((frame      (make-instance 'rect :left 10 :top 10 :right 60 :bottom 60))
	  (oval       (make-instance 'oval :left 10 :top 10 :right 60 :bottom 60))
	  (DrawFrame1 (make-instance 'Rect
				     :left 100 :top 10 :right 120 :bottom 30))
	  (DrawFrame2 (make-instance 'Rect
				     :left 100 :top 50 :right 140 :bottom 90))
	  (DrawFrame3 (make-instance 'Rect
				     :left 160 :top 10 :right 250 :bottom 60)))
      (with-instance (picture Picture :picframe frame)
	;Ï1;  Draw the picture.  Notice that this does not actually draw anything on the screen.Ï*
	(dotimes (i 5)
	  (send oval :fill !black)
	  (send oval :inset 3 3)
	  (send oval :erase)
	  (send oval :inset 3 3))
	
      ;Ï1; PROGRAMMING NOTE:  The code between the WITH-INSTANCE and the !ClosePicture act toÏ*
      ;Ï1; define the picture.  During this phase, QuickDraw accumulates information about the object youÏ*
      ;Ï1; are defining (in thie case, a picture).  The !ClosePicture tells QuickDraw to take what its got andÏ*
      ;Ï1; make a graphics object out of it.  The code after the !ClosePicture simply operates of the "pre-deÏ*
      ;Ï1; "pre-defined" graphics objects.Ï*
	(!ClosePicture)

	;Ï1;  Redraw the picture in three different locations, in three different sizes.Ï*
	(!DrawPicture picture DrawFrame1)
	(!DrawPicture picture DrawFrame2)
	(!DrawPicture picture DrawFrame3)

	;Ï1; wait a few seconds to admire our handy work and then returnÏ*
	(sleep sleep-time))))
  );Ï1;example-pictureÏ*



;Ï1;;; Ï4MENU EXAMPLEÏ*Ï*
(defun Ï4EXAMPLE-MENU Ï*()
  (declare (values ignore))
  (with-menus ((FileMenu FileMenuID :menuID 128 :title "Ï3FileÏ*")
	       (EditMenu EditMenuID :menuID 129 :title "Ï3EditÏ*"))
    (initialize-example-menu FileMenu EditMenu)
    (with-menu-bar (FileMenu EditMenu)
      (format t
	"Ï3~%TB:EXAMPLE-MENU is now runningÏ*.  Ï3Pull down Ï*the Apple Menu in theÏ3 Ï*MenuÏ3~Ï*
 Ï3        ~%BAR Ï*and Ï3then select \"tbserver\" at the bottom to see your example File~
         ~%and Edit menus.Ï*")

Ï1              Ï*;Ï1; Main Event LoopÏ*
      (loop-on-event (:sleep 1)
Ï1                  Ï*;Ï1; PROGRAMMING NOTE:  The Ï*:SLEEP 1Ï1 argument to LOOP-ON-EVENT says to return as soon 
                  Ï*;Ï1; as anyÏ* Ï1event occurs (remember, the event mask is !everyEvent) -OR- return after one 'TICK'
                  Ï*;Ï1; (1/60-th of aÏ* Ï1second) has elapsed, whichever comes first.Ï*
    
	(#.!mouseDown (example-menu-mousedown-handler event 1))
	;Ï1;  IMPLEMENTATION NOTE:  This example only needs to worry about mouseDown events, so Ï*
	;Ï1; there are no other event handled here.Ï*
	(otherwise (ignore)))
      ;Ï1; IMPLEMENTATION NOTE:  This LOOP-ON-EVENT macro does not need a cleanup clauseÏ*
      ;Ï1; the only cleanup required is for the menus and the WITH-MENUS and WITH-MENU-BAR macrosÏ*
      ;Ï1; are doing that for us.  If you use these macros, you should only need a separate cleanup clauseÏ*
      ;Ï1; to handle application-specific cleanup.Ï*
      ))
  ;Ï1; PROGRAMMING NOTE:  At this point, the example menu "application" has quit and cleared the Menu Ï*
  ;Ï1; Bar, but the microExplorer application has not yet been re-selected (i.e., the micorExplorer window Ï*
  ;Ï1; title bar is not highlighted and the window will not accept keyboard input).  The following functionÏ*
  ;Ï1; call re-selects the microExplorer window.Ï*
  (select-application)
  nil
  );Ï1;example-menuÏ*


(defun Ï4INITIALIZE-EXAMPLE-MENU Ï*(FileMenu EditMenu)
  "Ï2create menus and put them into the Menu BarÏ*"
  (declare (values ignore))

  ;Ï1; PROGRAMMING NOTE:  Your menus should always include the standard Apple Menu at the left endÏ*
  ;Ï1; of the Menu Bar.  This Apple Menu should list all available desk accessories as well as an "About..."Ï*
  ;Ï1; item at the top of the menu which describes your application (e.g., name, version number, copyrightÏ*
  ;Ï1; notice, etc.).Ï*
  ;Ï1;Ï*
  ;Ï1; However Ï2thisÏ*  example takes tutorial license with the Macintosh standards and, for the sake ofÏ*
  ;Ï1; simplicity, does Ï2notÏ*  include the standard Apple Menu.  The EXAMPLE-SHELL example in theÏ*
  ;Ï1; PUBLIC-MX shows how to set up the Apple Menu.Ï*

  ;Ï1; IMPLEMENTATION NOTE:  In traditional Macintosh applications, the "initialize menus" subprogramÏ*
  ;Ï1; first defines the menus with !NewMenu or !GetMenu; then adds items to these menus withÏ*
  ;Ï1; !AppendMenu and !AddResMenu; and finally redraws the Menu Bar with these newly defined menus.Ï*
  ;Ï1; A separate cleanup procedure disposed of the menus and clears the Menu Bar.Ï*
  ;Ï1;Ï*
  ;Ï1; If you use the WITH-MENUS and WITH-MENU-BAR macros, then the only things left for an initializeÏ*
  ;Ï1; menu function to do is to load up menu items...which is what this function is doing now.  There is noÏ*
  ;Ï1; need for a cleaup procedure that only cleans up menus.  Also, there is no longer a need to the globalÏ*
  ;Ï1; DEFVARs and DEFCONSTANTs for menu handles and menu IDs.Ï*
  
  ;Ï1; FILEÏ*
  (!AppendMenu FileMenu "Quit")
  ;Ï1; This creates a menu named "File" with one item named "Quit"Ï*

  ;Ï1; EDITÏ*
  (!AppendMenu EditMenu "Undo;(-;Cut;Copy;Paste")
  ;Ï1; IMPLEMENTATION NOTE:  Remember, the text string to !AppendMenu is really a mini-language.Ï*
  ;Ï1; Semicolons separate vertical menu items, hyphens specify a horizontal dividing line between items,Ï*
  ;Ï1; and a left parentheses make the next item unselectable.  Therefore this menu, named "Edit", will lookÏ*
  ;Ï1; something like this:Ï*
  ;Ï1;Ï*
  ;Ï1;Ï*	Ï1UndoÏ*
  ;Ï1;Ï*	Ï1--------      <-- line will be dimmed because it is not selectableÏ*
  ;Ï1;Ï*	Ï1CutÏ*
  ;Ï1;Ï*	Ï1CopyÏ*
  ;Ï1;Ï*	Ï1PasteÏ*
  ;Ï1;Ï*
  ;Ï1; Of course, selecting one of these will have no effect since we haven't provided any code support forÏ*
  ;Ï1; them.Ï*
  );Ï1; initialize-example-menuÏ*


(defun Ï4EXAMPLE-MENU-MOUSEDOWN-HANDLER Ï*(event QuitItem)
  "Ï2handle all mouseDown events for both EXAMPLE-MENUS and
EXAMPLE-HMENUS examples.Ï*"
  (declare (special FileMenuID))
  ;Ï1; IMPLEMENTATION NOTE:  The "Quit" menu item number is passed in as an argument to this functionÏ*
  ;Ï1; rather than being a declared constant so that this function can server two examples which haveÏ*
  ;Ï1; a need for distinct "Quit" item numbers.Ï*
  
  ;Ï1; first, find out where the mouse was clickedÏ*
  (multiple-value-bind (partcode whichWindow)
      (FindWindow event)
    (declare (ignore whichWindow))	       ;Ï1there's only one window of interestÏ*
    (case (the fixnum partcode)
      (#.!inMenuBar			       ;Ï1in a menuÏ*
       ;Ï1; second, find out which item of which menuÏ*
       (multiple-value-bind (whichMenu whichItem)
	   (!MenuSelect event)
	Ï1 Ï*;Ï1;  Here is where we take any appropriate action based on whatever menuÏ* Ï1item was selected.Ï*
	Ï1 Ï*;Ï1;This usually means calling functions that execute each possible menu command, but in thisÏ*
	Ï1 Ï*;Ï1; example we only check if the user selected Quit from the file menu.Ï*
	 (if (and (= whichMenu FileMenuID)
		  (= whichItem QuitItem))
	Ï1            Ï*;Ï1; then he did click on "Quit" in the "File" menu, so exit event loopÏ*
	     (throw 'EVENT-LOOP-EXIT nil)

	     ;Ï1; else he clicked elsewhere, so just unhighlight the menu and returnÏ*
	     (!HiliteMenu 0))))
Ï1              Ï*;Ï1;  In this example we only care about mouseDowns in the menu bar, but other mouseDowns couldÏ*
      ;Ï1;be checked for here.Ï*
      (otherwise (ignore))))
  );Ï1;example-menu-mouseDown-handlerÏ*



;Ï1;; Ï4HIERARCHICAL MENU EXAMPLEÏ*Ï*
(defun Ï4EXAMPLE-HMENU Ï*()
  (declare (values ignore))
  (with-menus ((FileMenu FileMenuID :menuID 128 :title "Ï3FileÏ*")
	       (EditMenu EditMenuID :menuID 129 :title "Ï3EditÏ*")
	       (HMenu    HMenuID    :menuID 130))
    (initialize-example-hmenus FileMenu EditMenu HMenu)
    (with-menu-bar (FileMenu EditMenu (HMenu HMenuID FileMenu 1))
      (format t
	"Ï3~%TB:EXAMPLE-HMENU is now runningÏ*.  Ï3Pull down Ï*the Apple Menu in theÏ3 Ï*Menu BarÏ3~Ï*
 Ï3        ~%Ï*and Ï3then select \"tbserver\" at the bottom to see your example File and~
         ~%Edit menus.Ï*")

      (loop-on-event (:sleep 1)
	(#.!mouseDown (example-menu-mouseDown-handler event 2))
	;Ï1NOTE: the mouseDown handler is the same as the one in EXAMPLE-MENU aboveÏ*
	(otherwise    (ignore)))
Ï1              Ï*;Ï1; IMPLEMENTATION NOTE:  This LOOP-ON-EVENT macro does not need a cleanup clauseÏ*
      ;Ï1; the only cleanup required is for the menus and the WITH-MENUS and WITH-MENU-BAR macrosÏ*
      ;Ï1; are doing that for us.  If you use these macros, you should only need a separate cleanup clauseÏ*
      ;Ï1; to handle application-specific cleanup.Ï*
      ))
  ;Ï1; PROGRAMMING NOTE:  At this point, the example menu "application" has quit and cleared the Menu Ï*
  ;Ï1; Bar, but the microExplorer application has not yet been re-selected (i.e., the micorExplorer window Ï*
  ;Ï1; title bar is not highlighted and the window will not accept keyboard input).  The following functionÏ*
  ;Ï1; call re-selects the microExplorer window.Ï*
  (select-application)
  nil
  );Ï1;example-hmenusÏ*


(defun Ï4INITIALIZE-EXAMPLE-HMENUS Ï*(FileMenu EditMenu HMenu)
  "Ï2create the menusÏ*"
Ï1    Ï*;Ï1;  File
    Ï*;Ï1;  The first item of the File menu will have a hierarchical menu.Ï*
  (!AppendMenu FileMenu "Test Hierarchical Item;Quit")

Ï1     Ï*;Ï1;  EditÏ*
  (!AppendMenu EditMenu "Undo;(-;Cut;Copy;Paste")

Ï1     Ï*;Ï1;  Hierarchical Menu.Ï*
  (!AppendMenu HMenu "One;Two;Three")
  );Ï1;initialize-example-hmenus
