home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / DirectoryPopup 1.0 / DirectoryPopup Source / DirectoryPopup.c next >
Encoding:
C/C++ Source or Header  |  1996-06-03  |  6.6 KB  |  264 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    Project:        <none>
  3.  *
  4.  *    Filename:         DirectoryPopup.c
  5.  *
  6.  *    Author:         Marco Piovanelli
  7.  *
  8.  *    Revision History:
  9.  *
  10.  *            1996.06.02                MP        created this file
  11.  *
  12.  */
  13.  
  14.  
  15. #include "DirectoryPopup.h"
  16. #include "Utilities.h"
  17.  
  18. #ifndef __FOLDERS__
  19. #include <Folders.h>
  20. #endif
  21.  
  22. #ifndef __DEVICES__
  23. #include <Devices.h>
  24. #endif
  25.  
  26. #ifndef __ICONS__
  27. #include <Icons.h>
  28. #endif
  29.  
  30. #ifndef __GESTALT__
  31. #include <Gestalt.h>
  32. #endif
  33.  
  34. #ifndef __TEXTUTILS__
  35. #include <TextUtils.h>
  36. #endif
  37.  
  38. //    private constants
  39.  
  40. enum
  41. {
  42.     kFinderIconIndicator    =    0x1A ,            //    menu item cmd for "Finder" icons
  43.     kFinderIconBaseID        =    -4000 ,
  44.     kStandardFileStrings    =    -6046 ,
  45.     kIndTrashName            =    2
  46. } ;
  47.  
  48. OSType GetVolumeKind ( SInt16 inVolumeRefNum )
  49. {
  50.     OSType volumeKind = 0 ;
  51.     HParamBlockRec pb ;
  52.     DCtlPtr pDCtlEntry ;
  53.     DRVRHeaderPtr pDriver ;
  54.     
  55.     //    get volume info
  56.     BlockClear ( & pb, sizeof ( pb ) ) ;
  57.     pb . volumeParam . ioVRefNum = inVolumeRefNum ;
  58.     if ( PBHGetVInfoSync ( & pb ) == noErr )
  59.     {
  60.         //    get a pointer to the driver control entry of the volume's driver
  61.         pDCtlEntry = * GetDCtlEntry ( pb . volumeParam . ioVDRefNum ) ;
  62.         
  63.         //    get a pointer to the driver itself
  64.         pDriver = ( DRVRHeaderPtr ) pDCtlEntry -> dCtlDriver ;
  65.         
  66.         //    if the driver is RAM-based, dCtlDriver is really a handle
  67.         if ( pDCtlEntry -> dCtlFlags & dRAMBasedMask )
  68.         {
  69.             pDriver = * ( DRVRHeaderHandle ) pDriver ;
  70.         }
  71.         
  72.         //    extract driver "tag" from driver name (letters 2 to 5)
  73.         volumeKind = * ( OSType * ) ( & pDriver -> drvrName [ 2 ] ) ;
  74.     }
  75.     
  76.     return volumeKind ;
  77. }
  78.  
  79. static Boolean HasModernStandardFile ( void )
  80. {
  81.     SInt32 response ;
  82.     
  83.     return ( ( Gestalt ( gestaltStandardFileAttr, & response ) == noErr ) &&
  84.              ( response & ( 1L << gestaltStandardFileHasDynamicVolumeAllocation ) ) ) ;
  85. }
  86.  
  87. MenuRef BuildDirectoryPopup ( const FSSpec * inFileSpec )
  88. {
  89.     MenuRef popup = nil ;
  90.     FSSpec spec = * inFileSpec ;
  91.     Str255 trashName ;
  92.     SInt16 item ;
  93.     SInt16 icon ;
  94.     SInt32 desktopDirectory = 0 ;
  95.     SInt32 trashDirectory = 0 ;
  96.     SInt32 thisDirectory ;
  97.     SInt32 trashNameLength ;
  98.     SInt16 volume ;
  99.     OSType volumeKind ;
  100.     OSErr err ;
  101.     
  102.     //    find the IDs of the desktop and trash directories for the specified volume
  103.     FindFolder ( spec . vRefNum, kDesktopFolderType, kDontCreateFolder, & volume, & desktopDirectory ) ;
  104.     FindFolder ( spec . vRefNum, kTrashFolderType, kDontCreateFolder, & volume, & trashDirectory ) ;
  105.     
  106.     //    create an uninitialized menu from scratch
  107.     if ( ( popup = NewMenu ( kDirectoryPopupMenuID, "\px" ) ) == nil )
  108.     {
  109.         return popup ;
  110.     }
  111.     
  112.     item = 0 ;
  113.     thisDirectory = -1 ;
  114.     do
  115.     {
  116.         //    add a new item to the menu
  117.         item ++ ;
  118.         AppendMenu ( popup, "\px" ) ;
  119.         
  120.         //    find out which icon to use for this item
  121.         if ( item == 1 )
  122.         {
  123.             //    first item in the pop-up menu uses a document icon
  124.             icon = kGenericDocumentIconResource ;
  125.         }
  126.         else if ( spec . parID == fsRtParID )
  127.         {
  128.             //    use a disk icon for root level directory
  129.             //    default icon is the generic hard disk icon
  130.             icon = kGenericHardDiskIconResource ;
  131.             
  132.             //    find out volume kind
  133.             volumeKind = GetVolumeKind ( spec . vRefNum ) ;
  134.             
  135.             //    use special icons for floppy and file server volumes
  136.             if ( ( volumeKind == kVolumeKindFloppy ) || ( volumeKind == kVolumeKindDiskImage ) )
  137.             {
  138.                 icon = kFloppyIconResource ;
  139.             }
  140.             else if ( volumeKind == kVolumeKindFileServer )
  141.             {
  142.                 icon = kGenericFileServerIconResource ;
  143.             }
  144.             else if ( HasModernStandardFile ( ) )
  145.             {
  146.                 //    the Standard File package that comes with System 7.0 Update 3.0
  147.                 //    (built in System 7.5 and newer) has additional small icons
  148.                 //    for CD-ROM and RAM disk volumes
  149.                 if ( volumeKind == kVolumeKindCDROM )
  150.                 {
  151.                     icon = kGenericCDROMIconResource ;
  152.                 }
  153.                 else if ( volumeKind == kVolumeKindRAMDisk )
  154.                 {
  155.                     icon = kGenericRAMDiskIconResource ;
  156.                 }
  157.             }
  158.         }
  159.         else if ( thisDirectory == trashDirectory )
  160.         {
  161.             //    if this directory is the trash directory, use the trash icon
  162.             //    and the real trash name
  163.             icon = kTrashIconResource ;
  164.             GetIndString ( trashName, kStandardFileStrings, kIndTrashName ) ;
  165.             trashNameLength = StrLength ( trashName ) ;
  166.             if ( ( trashNameLength > 0 ) && ( trashNameLength <= 63 ) )
  167.             {
  168.                 BlockMoveData ( trashName, & spec . name, trashNameLength + 1 ) ;
  169.             }
  170.         }
  171.         else
  172.         {
  173.             //    in all other cases, use the open folder icon
  174.             icon = kOpenFolderIconResource ;
  175.         }
  176.         
  177.         //    set name and icon of current Finder object
  178.         SetMenuItemText ( popup, item, spec . name ) ;
  179.         SetItemIcon ( popup, item, icon - kFinderIconBaseID ) ;
  180.         SetItemCmd ( popup, item, kFinderIconIndicator ) ;
  181.         
  182.         //    break out if we have reached a desktop child or the trash directory
  183.         if ( ( spec . parID == desktopDirectory ) || ( thisDirectory == trashDirectory ) )
  184.         {
  185.             break ;
  186.         }
  187.         
  188.         //    otherwise, find the file specification of the parent directory
  189.         thisDirectory = spec . parID ;
  190.         err = FindParentSpec ( & spec ) ;
  191.     }
  192.     while ( err == noErr ) ;
  193.  
  194.     return popup ;
  195. }
  196.  
  197. Boolean TrackDirectoryPopup ( FSSpec * ioFileSpec, WindowRef inWindow, Point inHitPt )
  198. {
  199.     //    call this function when you detect a command-click in a window's drag bar
  200.     //    on entry, ioFileSpec points to the file associated with the window
  201.     //    on exit, ioFileSpec points to the selected folder (if a selection was made)
  202.     //    if this function determines that this click should show a directory
  203.     //    pop-up menu, it displays it and does all the mouse tracking.
  204.     //    It then returns true if a selection was made.
  205.     
  206.     RgnHandle structureRgn ;
  207.     SInt16 titleWidth ;
  208.     Rect r ;
  209.     Point popCorner ;
  210.     MenuRef popup ;
  211.     SInt16 menuChoice ;
  212.     
  213.     //    make sure inWindow is selected
  214.     if ( ! IsWindowHilited ( inWindow ) )
  215.     {
  216.         return false ;
  217.     }
  218.     
  219.     if ( ( structureRgn = NewRgn ( ) ) == nil )
  220.     {
  221.         return false ;    //    emergency exit
  222.     }
  223.     GetWindowStructureRgn ( inWindow, structureRgn ) ;
  224.     r = ( * structureRgn ) -> rgnBBox ;
  225.     DisposeRgn ( structureRgn ) ;
  226.     titleWidth = GetWindowTitleWidth ( inWindow ) ;
  227.     popCorner . v = r . top + 1 ;
  228.     popCorner . h = r . left + ( ( ( r . right - r . left ) - titleWidth + 1 ) / 2 ) - 23 ;
  229.     if ( ( inHitPt . h < popCorner . h + 16 ) || ( inHitPt . h > popCorner . h + titleWidth + 28 ) )
  230.     {
  231.         return false ;
  232.     }
  233.     
  234.     //    build the directory pop-up menu
  235.     if ( ( popup = BuildDirectoryPopup ( ioFileSpec ) ) == nil )
  236.     {
  237.         return false ;
  238.     }
  239.     
  240.     //    insert the menu into the hierarchical portion of the menu list
  241.     InsertMenu ( popup, -1 ) ;
  242.     
  243.     //    pop up the menu
  244.     menuChoice = ( SInt16 ) PopUpMenuSelect ( popup, popCorner . v, popCorner . h, 1 ) ;
  245.     
  246.     //    remove the pop-up menu from the menu list
  247.     DeleteMenu ( kDirectoryPopupMenuID ) ;
  248.     
  249.     //    dispose of the menu itself
  250.     DisposeMenu ( popup ) ;
  251.     
  252.     //    see if an item up in the hierarchy was selected
  253.     if ( menuChoice > 1 )
  254.     {
  255.         for ( ; menuChoice > 1 ; menuChoice -- )
  256.         {
  257.             FindParentSpec ( ioFileSpec ) ;
  258.         }
  259.         return true ;
  260.     }
  261.     
  262.     return false ;
  263. }
  264.