home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / Hsoi's App Shell Source / HASPreferences.c < prev    next >
Encoding:
Text File  |  1997-01-28  |  60.7 KB  |  2,206 lines  |  [TEXT/CWIE]

  1. /*
  2.     HASPreferences.c from Hsoi's App Shell © 1995-1997 John C. Daub.  All rights reserved.
  3.         
  4.     This file contains all the stuff to deal with preferences:  setting them up,
  5.     reading them in, writing them out.  Plus, it contains the "registration"
  6.     dialog stuff.
  7. */
  8.  
  9.  
  10.  
  11. // to give credit where credit is due, my preferences code was based upon/derrived from
  12. // inspried by, etc, John Norstad's prefs code that he used in NewsWatcher.  I highly
  13. // recommend getting the source to NewsWatcher (espcially if you use NewsWatcher, but
  14. // get it anyway) and looking it over.  You'll learn a LOT.
  15.  
  16. // also, some of this prefs code (notably the print prefs and it's releated code, such
  17. // as HsoiDoArrowUpDown) is derrived upon work by Tom Bender from his Tex-Edit+ 1.6.3 source.
  18. // it started out being directly Tom's work (just translated from Pascal to C), but due to
  19. // some things in Tom's code that just can't translate too easily (plus some difficulties
  20. // Tom had in handling longer decimals (things out past the tenths place)), the code has
  21. // changed a fair amount to be what it is now.  Of course, I just wish my modifications didn't
  22. // require the #inclusion of ANSI C headers and needing to link in the ANSI libraries....oh well.
  23.  
  24. // and the function HsoiGetDoubleItem() was given to me by Scott Pogorelc (scottp@cais.cais.com)
  25. // and i updated it for use with the new Universal Headers.  Thanx Scott!
  26.  
  27. // NOTE:  There is one bug in the prefs code that i know of: the topic popup menu "truncates"
  28. // to just a short arrow menu when the new dialog is brought up....this bug made itself
  29. // known after i added in the printing prefs...I'm not sure why it's happening, but I'm
  30. // not really going to pursue it.  In a future release of HAS, I want to throw out this
  31. // prefs code anyways in place of another technique.  Instead of using a popup menu, I'd
  32. // like to have an "icon driven" prefs dialog...like the CW prefs dialog.  So, much of
  33. // this will soon be moot as I'll sooner or later be trashing it.  But, if you happen to
  34. // find out why this bug is happening, please let me know!
  35.  
  36. // and there is one other bug in the prefs code...in the Text prefs pane, do this:
  37. // in the font size edit box, enter an odd size (like 13...just something that's not a
  38. // value already in the size popup menu).  now, click-hold on the size popup menu.
  39. // select this odd font size (it'll be the first item) and let go of the mouse.  the
  40. // value in the size edit box should revert to 9 (or whatever the size/number that's
  41. // the first item in the popup).  i know why this is happening, but i can't quite
  42. // figure out how to fix it...i'm sure it's a problem that leaked in as i butchered
  43. // Norstad's original code...I do need to fix this...but it can wait for right now.
  44.  
  45. #pragma mark ••• #includes •••
  46.  
  47. #ifndef _WASTE_
  48. #include "WASTE.h"
  49. #endif
  50. #include "HASGlobals.h"
  51. #ifndef __HSOIS_APP_SHELL__
  52. #include "HASMain.h"
  53. #endif
  54. #include "HASUtilDialogs.h"
  55. #include "HASDialogs.h"
  56. #include "HASPreferences.h"
  57. #include "HASUtilPStrings.h"
  58. #include "HASUtilities.h"
  59.  
  60. #include "WASTE_Objects.h"
  61.  
  62. #ifndef __LOWMEM__
  63. #include <LowMem.h>
  64. #endif
  65.  
  66. #pragma mark -
  67. #pragma mark ••• Constants •••
  68.  
  69. // can't enum this since it's a floating point value, but just needed a nice constant
  70.  
  71. const double kMaxMargin = 6.00;
  72.  
  73. #pragma mark -
  74. #pragma mark ••• Globalss •••
  75.  
  76. // various static globals to help us keep track of things..
  77.  
  78. static    short        sCurRadio = 0;
  79. static    short        sDefaultFontID = 0;
  80. static    short        sDefaultSize = 0;
  81. static    short        curDlgNum = rPrefsGeneralDLOG;  // start out on the "first page"
  82. static    Str255        sFontSize = NIL_STRING;
  83. static    Boolean        sNewPrefs = 0;    // true: create prefs file so do registration dlog, false: pref file
  84.                                     // already exists, don't do registration dlog
  85. static    UserItemUPP    frameItemsUPP = nil;
  86.  
  87.  
  88. #pragma mark -
  89. #pragma mark ••• Utils •••
  90.  
  91. /*    some utility functions */
  92.  
  93. short     HsoiSetPopupValue (ControlRef ctl, Str255 str, Boolean    isNumber)
  94. {
  95.     PopupPrivateDataHandle data;
  96.     long                 checkVal, itemVal;
  97.     MenuRef             menu;
  98.     short                 numItems, item;
  99.     Str255                 tempStr;
  100.  
  101.     //COPLAND - the following line breaks under STRICT macros since .contrlData isn't
  102.     // a member of an OpaqueControlReference
  103.  
  104.     // get the popup data
  105.     
  106.     data = (PopupPrivateDataHandle)(*ctl)->contrlData;
  107.     
  108.     // if the string is a number, convert it
  109.     
  110.     if (isNumber)
  111.         StringToNum(str, &checkVal);
  112.     
  113.     // get the menuref from the popup data
  114.     
  115.     menu = (*data)->mHandle;
  116.  
  117.     // see how many items are in the menu
  118.     
  119.     numItems = CountMenuItems(menu);
  120.     
  121.     // and loop through the menu looking for a menu item that matches "str"
  122.     
  123.     for (item = 1; item <= numItems; item++)
  124.     {
  125.         // get the menu text
  126.         
  127.         GetMenuItemText(menu, item, tempStr);
  128.         
  129.         // if it's a number we're looking for...
  130.         
  131.         if (isNumber)
  132.         {
  133.             // ...convert the menu item to a number...
  134.             
  135.             StringToNum(tempStr, &itemVal);
  136.             
  137.             // ...if they're equal...
  138.             
  139.             if (checkVal == itemVal)
  140.             {
  141.                 // ...then set the value of the control
  142.                 
  143.                 SetControlValue(ctl, item);
  144.                 return item;
  145.             }
  146.         }
  147.         // ..else if we're instead looking for a string..
  148.         
  149.         else if (EqualString(str, tempStr, false, true))
  150.         {
  151.             //...if we have a match, set the value
  152.             
  153.             SetControlValue(ctl, item);
  154.             return item;
  155.         }
  156.     }
  157.     return 0;
  158. }
  159.  
  160. // returns a pascal type string from a popup menu
  161.  
  162. void    HsoiGetPopupPString (ControlRef ctl, short item, Str255 str)
  163. {
  164.     PopupPrivateDataHandle data;
  165.     
  166.     // get the popup menu
  167.     
  168.     //COPLAND - the following line breaks under STRICT macros since .controlData
  169.     // isn't a member of an OpaqueControlReference
  170.     data = (PopupPrivateDataHandle)(*ctl)->contrlData;
  171.     
  172.     // readjust the value of "item" if necessary
  173.     
  174.     if (item == kCurrentPopupItem)
  175.         item = GetControlValue(ctl);
  176.     
  177.     // and then get the text of the menu item
  178.     
  179.     GetMenuItemText((*data)->mHandle, item, str);
  180. }
  181.  
  182. // this will set the style a menu item's text is drawn in
  183.  
  184. void HsoiSetPopupItemStyle (ControlRef ctl, short item, short style)
  185. {
  186.     PopupPrivateDataHandle data;
  187.     
  188.     //COPLAND - the following line breaks under STRICT macros since .contrlData
  189.     // isn't a member of an OpaqueControlReference
  190.     data = (PopupPrivateDataHandle)(*ctl)->contrlData;
  191.     if (item == kCurrentPopupItem)
  192.         item = GetControlValue(ctl);
  193.     SetItemStyle((*data)->mHandle, item, style);
  194. }
  195.  
  196.  
  197. // used in our prefs dialog filter to track popup menu usage
  198.  
  199. short     HsoiTrackPopup (ControlRef ctl, Point where, Str255 checkItem, Boolean isNumber)
  200. {
  201.     PopupPrivateDataHandle data;
  202.     MenuRef menu;
  203.     long checkVal;
  204.     short itemsAdded, part, newValue, oldValue;
  205.     Str255 tempStr;
  206.     register short i;
  207.  
  208.     //COPLAND - the following line breaks under STRICT macros since .controlData
  209.     // isn't a member of an OpaqueControlReference
  210.  
  211.     // get the popup menu data from the control
  212.     
  213.     data = (PopupPrivateDataHandle)(*ctl)->contrlData;
  214.  
  215.     // get the menuref
  216.     
  217.     menu = (*data)->mHandle;
  218.     
  219.     // reset itemsAdded to zero (cause we haven't added anything)
  220.     
  221.     itemsAdded = 0;
  222.     
  223.     // if we have a string and it's not nil...
  224.     
  225.     if (checkItem && *checkItem)
  226.     {
  227.  
  228.         // set the popup value
  229.         
  230.         oldValue = HsoiSetPopupValue(ctl, checkItem, isNumber);
  231.         
  232.         
  233.         if (oldValue == 0)
  234.         {
  235.             // if it's a number...
  236.             
  237.             if (isNumber)
  238.             {
  239.                 // convert to a string then insert into the menu
  240.                 
  241.                 StringToNum(checkItem, &checkVal);
  242.                 NumToString(checkVal, tempStr);
  243.                 InsertMenuItem(menu, tempStr, 0);
  244.             }
  245.             else
  246.             {
  247.                 // it's a number, just insert it
  248.                 
  249.                 InsertMenuItem(menu, checkItem, 0);
  250.             }
  251.             
  252.             // insert a spacer menu item
  253.             
  254.             InsertMenuItem(menu, "\p(-", 1);
  255.             
  256.             // readjust the oldValue
  257.             
  258.             oldValue = 1;
  259.             
  260.             // we added 2 items (the menu item and the spacer)
  261.             
  262.             itemsAdded = 2;
  263.             
  264.             // and set the control value as such
  265.             
  266.             SetControlValue(ctl, oldValue);
  267.         }
  268.     }
  269.     else // we don't have a string and/or it's nil
  270.     {
  271.         oldValue = 0;
  272.     }
  273.  
  274.     // track the popup menu (toolbox does this)
  275.     
  276.     part = TrackControl(ctl, where, (ControlActionUPP)-1);
  277.  
  278.     // get the new value of the controls
  279.     
  280.     newValue = GetControlValue(ctl);
  281.  
  282.     // readjust the new value of the control
  283.     
  284.     if (part != 0 && oldValue != newValue)
  285.     {
  286.         newValue = newValue - itemsAdded;
  287.     }
  288.     else
  289.     {
  290.         newValue = 0;
  291.     }
  292.     
  293.     // if we added anything to the popup menu, remove it before we return
  294.     
  295.     if (itemsAdded)
  296.     {
  297.         for (i = 0; i < itemsAdded; i++)
  298.         {
  299.             DeleteMenuItem(menu, 1);
  300.         }
  301.         SetControlValue(ctl, newValue);
  302.     }
  303.     return newValue;
  304. }
  305.  
  306.  
  307. // this goes through the font popup menu in the prefs dialog and adjusts
  308. // the look and value of the popup
  309.  
  310. static void HsoiSetNewFont (DialogRef dlg, short fontNum)
  311. {
  312.     short             numItems, i;
  313.     Str255             itemStr, fontName;
  314.     ControlRef         ctl;
  315.     long             size;
  316.  
  317.     // Select the right font in the font popup menu.
  318.     
  319.     ctl = HsoiDlgGetControl(dlg, iPrefsTextFontPopup );
  320.     GetFontName(fontNum, fontName);
  321.     HsoiSetPopupValue(ctl, fontName, false);
  322.     
  323.     // Adjust the size popup so the nice sizes are outlined.
  324.  
  325.     // get the control
  326.     
  327.     ctl = HsoiDlgGetControl(dlg, iPrefsTextSizePopup);
  328.     
  329.     // find the number of items in the popup
  330.     
  331.     numItems = GetControlMaximum(ctl);
  332.     
  333.     // and loop through the list...depending on the fontName (the font),
  334.     // draw the size popup items in plain or outline style to signify
  335.     // a supported size
  336.     
  337.     for (i = 1; i <= numItems; i++)
  338.     {
  339.         HsoiGetPopupPString(ctl, i, itemStr);
  340.         StringToNum(itemStr, &size);
  341.         if (RealFont(fontNum, (short)size))
  342.         {
  343.             HsoiSetPopupItemStyle(ctl, i, outline);
  344.         }
  345.         else
  346.         {
  347.             HsoiSetPopupItemStyle(ctl, i, 0);
  348.         }
  349.     }
  350.  
  351.     return;
  352. }
  353.  
  354. // from the font popup menu, get the selected font's ID number
  355.  
  356. static short    HsoiFontIDFromPopup( DialogRef dlg, short item )
  357. {
  358.     ControlRef            ctl;
  359.     short                fontNum;
  360.     Str255                fontName;
  361.     
  362.     ctl = HsoiDlgGetControl( dlg, item );
  363.     HsoiGetPopupPString( ctl, kCurrentPopupItem, fontName );
  364.     GetFNum( fontName, &fontNum );
  365.     
  366.     return fontNum;
  367. }
  368.  
  369. // adjust the radio button group in the prefs dialog.
  370.  
  371. void    HsoiSetPrefsRadioButton( DialogRef dlg, short buttonNumber )
  372. {
  373.     // if the buttonNumber is the currently selected button, don't bother.
  374.     
  375.     if ( buttonNumber != sCurRadio )
  376.     {
  377.         // and if it's another button, first turn off the current button
  378.         // and then turn on the new button
  379.         
  380.         if ( sCurRadio != 0 )
  381.             HsoiSetDialogItemState( dlg, sCurRadio, false );
  382.         
  383.         sCurRadio = buttonNumber;
  384.         
  385.         if ( (sCurRadio >= kPrefsTextFirstRadio ) && ( sCurRadio <= kPrefsTextLastRadio ) )
  386.             HsoiSetDialogItemState( dlg, sCurRadio, true );
  387.     }
  388.  
  389.     return;
  390. }
  391.  
  392. // this puts a little frame around the color swatch in the text prefs dialog
  393. // (just a nice cosmetic effect)
  394.  
  395. void    HsoiFrameColorRect( DialogRef dlg, HASPreferences *prefs )
  396. {
  397. #pragma unused( prefs )
  398.  
  399.     Rect     borderRect;
  400.     
  401.     // get the item rect
  402.     
  403.     HsoiGetDialogItemRect( dlg, iPrefsTextGetColor, &borderRect );
  404.     
  405.     // grow out from that rect 2 pixels
  406.     
  407.     InsetRect(&borderRect, -2, -2);
  408.     
  409.     // normal the pen
  410.     
  411.     PenNormal();
  412.     
  413.     // make sure the pen size is just 1 x 1 pixel
  414.     
  415.     PenSize(1, 1);
  416.     
  417.     // frame it
  418.     
  419.     FrameRect(&borderRect );
  420.     
  421.     // and again make sure the size is 1x1 for other drawing operations
  422.     
  423.     PenSize(1, 1);
  424.  
  425.  
  426.     return;
  427. }
  428.  
  429. // fill something into the color user item rect in the text prefs dialog
  430. // (nice user feedback as to which color is selected)
  431.  
  432. void    HsoiPaintColorRect( DialogRef dlg, HASPreferences *prefs )
  433. {
  434.     RGBColor        oldForeColor, newForeColor;
  435.     GrafPtr            oldPort;
  436.     Rect            colorRect;
  437.     
  438.     // set up the port
  439.     
  440.     GetPort( &oldPort );
  441.     SetGrafPortOfDialog( dlg );
  442.     
  443.     // draw the frame around the rect
  444.     
  445.     HsoiFrameColorRect( dlg, prefs );
  446.  
  447.     // get the original color
  448.     
  449.     GetForeColor( &oldForeColor );
  450.     
  451.     // get the new color from the prefs
  452.     
  453.     newForeColor = prefs->defColor;
  454.     
  455.     // set the fore color
  456.     
  457.     RGBForeColor( &newForeColor );
  458.     
  459.     // get the rect
  460.         
  461.     HsoiGetDialogItemRect( dlg, iPrefsTextGetColor, &colorRect );
  462.     
  463.     // and paint it in the new color
  464.     
  465.     PaintRect( &colorRect );
  466.     
  467.     // restore the old color and port
  468.     
  469.     RGBForeColor( &oldForeColor );
  470.     SetPort( oldPort );
  471.     
  472.     return;
  473. }            
  474.  
  475.  
  476. #pragma mark -
  477. #pragma mark ••• Prefs Pane Handlers •••
  478.  
  479. //    the function/procedures to handle each dialog box
  480.  
  481. // this takes care of the general prefs dialog
  482.  
  483.  
  484. static void HsoiGeneralPrefs( HASPreferences *prefs, DialogRef dlg, short item )
  485. {
  486.     switch ( item )
  487.     {
  488.     
  489.         // intialization (called before the dialog is brought up
  490.         
  491.         case kInit:
  492.         
  493.             // set the checkmarks based upon the prefs setting
  494.             
  495.             HsoiDlgSetCheck( dlg, iPrefsGenCreateWIND, prefs->createWindow );
  496.             HsoiDlgSetCheck( dlg, iPrefsGenHelpSound, prefs->playHelpSound );
  497.             HsoiDlgSetCheck( dlg, iPrefsGenDoSplash, prefs->doSplashScreen );
  498.             
  499.             // the speech stuff is dependant if they have the speech manager or
  500.             // not.  if they have it, make sure the item is enalbed and then
  501.             // set the check according to the prefs setting
  502.             
  503.             if ( gHasSpeechManager )
  504.             {
  505.                 // make sure it's enabled
  506.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsGenStartupSpeech ), kCtlActive );
  507.                 HsoiDlgSetCheck( dlg, iPrefsGenStartupSpeech, prefs->doStartupSpeech );
  508.             }
  509.             else // no speech manager, make sure the dialog item is disabled, and of course
  510.                  // set the item to be unchecked since they can't use it
  511.             {
  512.                 // make sure it's disabled
  513.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsGenStartupSpeech ), kCtlInactive );
  514.                 HsoiDlgSetCheck( dlg, iPrefsGenStartupSpeech, 0 );
  515.             }
  516.             
  517.         break; // end: case kInit
  518.     
  519.         
  520.         // what to do when the dialog is "brought down"
  521.         
  522.         case kTerm:
  523.         
  524.             // just save the checkmark settings/values in the prefs
  525.             
  526.             prefs->createWindow = HsoiDlgGetCheck( dlg, iPrefsGenCreateWIND );
  527.             prefs->playHelpSound = HsoiDlgGetCheck( dlg, iPrefsGenHelpSound );
  528.             prefs->doSplashScreen = HsoiDlgGetCheck( dlg, iPrefsGenDoSplash );
  529.             prefs->doStartupSpeech = HsoiDlgGetCheck( dlg, iPrefsGenStartupSpeech );
  530.  
  531.         break; // end: case kTerm
  532.         
  533.         // now, during the dialog, what to do
  534.         
  535.         // in this dialog, whatever they select, just toggle the checkmark
  536.         
  537.         case iPrefsGenCreateWIND:
  538.         case iPrefsGenHelpSound:
  539.         case iPrefsGenDoSplash:
  540.         case iPrefsGenStartupSpeech:
  541.         
  542.             HsoiDlgToggleCheck( dlg, item );
  543.         
  544.         break;  // end case kPrefsGenXXXX
  545.         
  546.     
  547.     } // end: switch ( item )
  548.     
  549.     return;
  550. }
  551.  
  552. // the handler for the text prefs dialog
  553.  
  554.  
  555. static void HsoiTextPrefs( HASPreferences *prefs, DialogRef dlg, short item )
  556. {
  557.     short            radio;
  558.     Boolean            hasFace, hasFeature;
  559.     Str255            tempStr;
  560.     long            num;
  561.     Boolean            checked;
  562.     short            i;    
  563.     
  564.     switch ( item )
  565.     {
  566.  
  567.         // what to do at initalization, before the dialog is brought up
  568.         
  569.         case kInit:
  570.             
  571.             // set up the font popup and size popup and edittext item
  572.                     
  573.             GetFNum(prefs->defFont, &sDefaultFontID);
  574.             sDefaultSize = prefs->defSize;
  575.             HsoiSetNewFont(dlg, sDefaultFontID);
  576.             HsoiDlgSetNumber(dlg, iPrefsTextSizeEditBox, sDefaultSize);
  577.             SelectDialogItemText(dlg, iPrefsTextSizeEditBox, 0, MAXSHORT);            
  578.             
  579.             // set up the text face/style checkboxes
  580.             
  581.             // if the defFace == 0, it's plain style, so just check that one
  582.             // and be sure all the rest are unchecked
  583.             
  584.             if ( prefs->defFace == 0 )
  585.             {
  586.                 HsoiDlgSetCheck( dlg, iPrefsTextPlainCheck, true );
  587.                 HsoiDlgSetCheck( dlg, iPrefsTextBoldCheck, false );
  588.                 HsoiDlgSetCheck( dlg, iPrefsTextItalicCheck, false );
  589.                 HsoiDlgSetCheck( dlg, iPrefsTextUnderlineCheck, false );
  590.                 HsoiDlgSetCheck( dlg, iPrefsTextOutlineCheck, false );
  591.                 HsoiDlgSetCheck( dlg, iPrefsTextShadowCheck, false );
  592.                 HsoiDlgSetCheck( dlg, iPrefsTextCondenseCheck, false );
  593.                 HsoiDlgSetCheck( dlg, iPrefsTextExtendCheck, false );
  594.             }
  595.             else
  596.             // it's not 0 (plain style), so we can be sure this needs to be unchecked
  597.                 HsoiDlgSetCheck( dlg, iPrefsTextPlainCheck, false );
  598.             
  599.             // check the defFace for style attributes.  depending if it's
  600.             // there or not (hasFace is a Boolean), the checkbox will
  601.             // be checked appropriately
  602.             
  603.             hasFace = prefs->defFace & bold;
  604.             HsoiDlgSetCheck( dlg, iPrefsTextBoldCheck, hasFace );
  605.             
  606.             hasFace = prefs->defFace & italic;
  607.             HsoiDlgSetCheck( dlg, iPrefsTextItalicCheck, hasFace );
  608.             
  609.             hasFace = prefs->defFace & underline;
  610.             HsoiDlgSetCheck( dlg, iPrefsTextUnderlineCheck, hasFace );
  611.             
  612.             hasFace = prefs->defFace & outline;
  613.             HsoiDlgSetCheck( dlg, iPrefsTextOutlineCheck, hasFace );
  614.             
  615.             hasFace = prefs->defFace & shadow;
  616.             HsoiDlgSetCheck( dlg, iPrefsTextShadowCheck, hasFace );
  617.             
  618.             hasFace = prefs->defFace & condense;
  619.             HsoiDlgSetCheck( dlg, iPrefsTextCondenseCheck, hasFace );
  620.             
  621.             hasFace = prefs->defFace & extend;
  622.             HsoiDlgSetCheck( dlg, iPrefsTextExtendCheck, hasFace );
  623.             
  624.             // set up the little color rect
  625.             // doesn't really work here, unfortuneately, due to updating stuff, so
  626.             // this call is really handled in HsoiDoPrefsDialog() right after ShowWindow()
  627.             
  628.             // i probably could install this as a UserItemUPP to make it easier.....
  629.             
  630.             HsoiPaintColorRect( dlg, prefs );
  631.             
  632.             // set up the radio buttons
  633.             
  634.             sCurRadio = 0;
  635.             
  636.             if ( prefs->defAlign == weFlushLeft )
  637.                 radio = iPrefsTextLeftRadio;
  638.             else if ( prefs->defAlign == weFlushRight )
  639.                 radio = iPrefsTextRightRadio;
  640.             else if ( prefs->defAlign == weFlushDefault )
  641.                 radio = kPrefsTextDefaultRadio;
  642.             else if ( prefs->defAlign == weCenter )
  643.                 radio = iPrefsTextCenterRadio;
  644.             else if ( prefs->defAlign == weJustify )
  645.                 radio = iPrefsTextFullRadio;
  646.             else
  647.                 radio = kPrefsTextDefaultRadio;
  648.                 
  649.             HsoiSetPrefsRadioButton( dlg, radio );
  650.             
  651.             // set up the features flags
  652.             
  653.             HsoiDlgSetCheck( dlg, iPrefsTextTabHooks, prefs->useTabHooks );
  654.             
  655.             // if tab hooks are used, they can only be used with left alignment/justification
  656.             // therefore, if this check box becomes marked we must 1. make sure the left
  657.             // alignment button gets turned on, 2. all the alignnment radio buttons get dimmed
  658.             // (cuase they cannot select anything without messing up tab hooks).  And if tab
  659.             // hooks becomes unchecked, make sure to enable the radio buttons, but no need
  660.             // to select a new alignment style
  661.             
  662.             checked = HsoiDlgGetCheck( dlg, iPrefsTextTabHooks );
  663.             
  664.             if ( checked )
  665.             {
  666.                 HsoiSetPrefsRadioButton( dlg, iPrefsTextLeftRadio );
  667.                 for ( i = kPrefsTextFirstRadio; i <= kPrefsTextLastRadio; i++ )
  668.                 {
  669.                     HiliteControl( HsoiDlgGetControl( dlg, i ), kCtlInactive );
  670.                 }
  671.             }
  672.             else
  673.             {
  674.                 for ( i = kPrefsTextFirstRadio; i <= kPrefsTextLastRadio; i++ )
  675.                 {
  676.                     HiliteControl( HsoiDlgGetControl( dlg, i ), kCtlActive );
  677.                 }
  678.             }
  679.         
  680.             
  681.             // and cycle through the defFeatures to see what to have and not to have
  682.             // (works the same as the face stuff above)
  683.             
  684.             hasFeature = BTST( prefs->defFeatures, weFAutoScroll );
  685.             HsoiDlgSetCheck( dlg, iPrefsTextAutoScroll, hasFeature );
  686.             
  687.             hasFeature = BTST( prefs->defFeatures, weFOutlineHilite );
  688.             HsoiDlgSetCheck( dlg, iPrefsTextOutlineHilite, hasFeature );
  689.             
  690.             hasFeature = BTST( prefs->defFeatures, weFReadOnly );
  691.             HsoiDlgSetCheck( dlg, iPrefsTextReadOnly, hasFeature );
  692.                         
  693.             hasFeature = BTST( prefs->defFeatures, weFIntCutAndPaste );
  694.             HsoiDlgSetCheck( dlg, iPrefsTextIntCutAndPaste, hasFeature );
  695.             
  696.             // if the user's computer doesn't have drag and drop support, we shouldn't
  697.             // allow them to set this bit
  698.             
  699.             if ( gHasDragAndDrop )
  700.             {
  701.                 // make sure it's enabled
  702.                 
  703.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsTextDragAndDrop ), kCtlActive );
  704.                 
  705.                 // set the check mark
  706.                 
  707.                 hasFeature = BTST( prefs->defFeatures, weFDragAndDrop );
  708.                 HsoiDlgSetCheck( dlg, iPrefsTextDragAndDrop, hasFeature );                
  709.             }
  710.             else
  711.             {
  712.                 // make sure it's disabled
  713.                 
  714.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsTextDragAndDrop ), kCtlInactive );
  715.                 
  716.                 // make sure it has no check mark
  717.                 
  718.                 HsoiDlgSetCheck( dlg, iPrefsTextDragAndDrop, false );
  719.                 
  720.             }
  721.             
  722.             hasFeature = BTST( prefs->defFeatures, weFDrawOffscreen );
  723.             HsoiDlgSetCheck( dlg, iPrefsTextOffscreenDrawing, hasFeature );
  724.             
  725.             // install the frame rect proc for the user items (it's nice and cosmetic!)
  726.         
  727.             HsoiSetDialogItemProc( dlg, iPrefsTextStyleUserItem, frameItemsUPP );
  728.             HsoiSetDialogItemProc( dlg, iPrefsTextAlignUserItem, frameItemsUPP );
  729.             HsoiSetDialogItemProc( dlg, iPrefsTextFeaturesUserItem, frameItemsUPP ); 
  730.         
  731.         
  732.         break;  // case kInit
  733.         
  734.         // what to do when the dialog is brought down....
  735.         
  736.         case kTerm:
  737.             
  738.             // get the font and size data
  739.             
  740.             GetFontName( sDefaultFontID, prefs->defFont );
  741.             prefs->defSize = sDefaultSize;
  742.             
  743.             // get the text style/face info
  744.             
  745.             prefs->defFace = 0; // initialize it to zero to allow proper addition
  746.             
  747.             if ( HsoiDlgGetCheck( dlg, iPrefsTextPlainCheck ) )
  748.                 prefs->defFace = 0;
  749.             else // plain isn't checked
  750.             {
  751.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextBoldCheck ) )
  752.                     prefs->defFace += bold;
  753.                 
  754.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextItalicCheck ) )
  755.                     prefs->defFace += italic;
  756.                 
  757.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextUnderlineCheck ) )
  758.                     prefs->defFace += underline;
  759.                 
  760.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextOutlineCheck ) )
  761.                     prefs->defFace += outline;
  762.                 
  763.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextShadowCheck ) )
  764.                     prefs->defFace += shadow;
  765.                 
  766.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextCondenseCheck ) )
  767.                     prefs->defFace += condense;
  768.                 
  769.                 if ( HsoiDlgGetCheck( dlg, iPrefsTextExtendCheck ) )
  770.                     prefs->defFace += extend;
  771.             
  772.             } // end: else plain isn't checked
  773.         
  774.             // the color value is gotten in "case iPrefsTextGetColor" below
  775.             
  776.             // get the radio button setting
  777.             
  778.             if ( HsoiDlgGetRadio( dlg, iPrefsTextLeftRadio ) )
  779.                 prefs->defAlign = weFlushLeft;
  780.             else if ( HsoiDlgGetRadio( dlg, iPrefsTextRightRadio ) )
  781.                 prefs->defAlign = weFlushRight;
  782.             else if ( HsoiDlgGetRadio( dlg, iPrefsTextCenterRadio ) )
  783.                 prefs->defAlign = weCenter;
  784.             else if ( HsoiDlgGetRadio( dlg, iPrefsTextFullRadio ) )
  785.                 prefs->defAlign = weJustify;
  786.             // add a "else if kPrefsTextDefaultRadio" in here when defaults are added
  787.             
  788.             else // just in case nothing comes up right, set it to the default
  789.                 prefs->defAlign = weFlushDefault;
  790.         
  791.             // and now the features
  792.             
  793.             prefs->useTabHooks = HsoiDlgGetCheck( dlg, iPrefsTextTabHooks );
  794.             
  795.             // set the features to 0 to start out...
  796.             
  797.             prefs->defFeatures = 0;
  798.             
  799.             if ( HsoiDlgGetCheck( dlg, iPrefsTextAutoScroll ) )
  800.                 BSET( prefs->defFeatures, weFAutoScroll );
  801.             
  802.             if ( HsoiDlgGetCheck( dlg, iPrefsTextOutlineHilite ) )
  803.                 BSET( prefs->defFeatures, weFOutlineHilite );
  804.             
  805.             if ( HsoiDlgGetCheck( dlg, iPrefsTextReadOnly ) )
  806.                 BSET( prefs->defFeatures, weFReadOnly );
  807.             
  808.             if ( HsoiDlgGetCheck( dlg, iPrefsTextIntCutAndPaste ) )
  809.                 BSET( prefs->defFeatures, weFIntCutAndPaste );
  810.             
  811.             if ( HsoiDlgGetCheck( dlg, iPrefsTextDragAndDrop ) )
  812.                 BSET( prefs->defFeatures, weFDragAndDrop );
  813.             
  814.             if ( HsoiDlgGetCheck( dlg, iPrefsTextOffscreenDrawing ) )
  815.                 BSET( prefs->defFeatures, weFDrawOffscreen );
  816.         
  817.         break; // case kTerm
  818.         
  819.         // and now handle things during the dialog
  820.         
  821.         case iPrefsTextFontPopup:
  822.         
  823.             sDefaultFontID = HsoiFontIDFromPopup( dlg, item );
  824.             HsoiSetNewFont( dlg, sDefaultFontID );
  825.         
  826.         break;
  827.         
  828.         case iPrefsTextSizePopup:
  829.  
  830.             HsoiGetPopupPString( HsoiDlgGetControl( dlg, item ), kCurrentPopupItem, tempStr );
  831.             HsoiDlgSetPString( dlg, iPrefsTextSizeEditBox, tempStr );
  832.             SelectDialogItemText( dlg, iPrefsTextSizeEditBox, 0, MAXSHORT );
  833.             
  834.             // fall through!!
  835.             
  836.         case iPrefsTextSizeEditBox:
  837.         
  838.             HsoiDlgGetPString( dlg, iPrefsTextSizeEditBox, tempStr );
  839.             StringToNum( tempStr, &num );
  840.             if ( num != 0 && num != sDefaultSize )
  841.                 sDefaultSize = num;
  842.             
  843.         break;
  844.         
  845.         case iPrefsTextPlainCheck:
  846.             HsoiDlgToggleCheck( dlg, item );
  847.             HsoiDlgSetCheck( dlg, iPrefsTextBoldCheck, false );
  848.             HsoiDlgSetCheck( dlg, iPrefsTextItalicCheck, false );
  849.             HsoiDlgSetCheck( dlg, iPrefsTextUnderlineCheck, false );
  850.             HsoiDlgSetCheck( dlg, iPrefsTextOutlineCheck, false );
  851.             HsoiDlgSetCheck( dlg, iPrefsTextShadowCheck, false );
  852.             HsoiDlgSetCheck( dlg, iPrefsTextCondenseCheck, false );
  853.             HsoiDlgSetCheck( dlg, iPrefsTextExtendCheck, false );
  854.         break;
  855.         
  856.         case iPrefsTextBoldCheck:
  857.         case iPrefsTextItalicCheck:
  858.         case iPrefsTextUnderlineCheck:
  859.         case iPrefsTextOutlineCheck:
  860.         case iPrefsTextShadowCheck:
  861.         case iPrefsTextCondenseCheck:
  862.         case iPrefsTextExtendCheck:
  863.         
  864.             HsoiDlgToggleCheck( dlg, item );
  865.             HsoiDlgSetCheck( dlg, iPrefsTextPlainCheck, false );
  866.             
  867.         break;
  868.         
  869.         
  870.         case iPrefsTextGetColor:
  871.         {
  872.             Boolean        newColorSelected;
  873.             Str255        prompt;
  874.             Point        where = { -1, -1 };
  875.             RGBColor    oldColor;
  876.             RGBColor    newColor;
  877.             
  878.             oldColor = prefs->defColor;
  879.             
  880.             // get the prompt string
  881.             
  882.             GetIndString( prompt, rGetColorStrings, strDefaultTextColor );
  883.             
  884.             // get the color (we ought to change this to PickColor to take advantage
  885.             // of the new color picker)
  886.             
  887.             newColorSelected = GetColor( where, prompt, &oldColor, &newColor );
  888.             
  889.             if ( newColorSelected )
  890.                 prefs->defColor = newColor;
  891.  
  892.             // now redraw the color rect
  893.             
  894.             HsoiPaintColorRect( dlg, prefs );
  895.             
  896.         }
  897.         break;
  898.         
  899.             
  900.         case iPrefsTextLeftRadio:
  901.         case iPrefsTextRightRadio:
  902.         case iPrefsTextCenterRadio:
  903.         case iPrefsTextFullRadio:
  904.         
  905.             HsoiSetPrefsRadioButton( dlg, item );
  906.         
  907.         break;
  908.         
  909.         case iPrefsTextTabHooks:
  910.         {
  911.             Boolean        checked;
  912.             short        i;
  913.             
  914.             HsoiDlgToggleCheck( dlg, item );
  915.             
  916.             // if tab hooks are used, they can only be used with left alignment/justification
  917.             // therefore, if this check box becomes marked we must 1. make sure the left
  918.             // alignment button gets turned on, 2. all the alignnment radio buttons get dimmed
  919.             // (cuase they cannot select anything without messing up tab hooks).  And if tab
  920.             // hooks becomes unchecked, make sure to enable the radio buttons, but no need
  921.             // to select a new alignment style
  922.             
  923.             checked = HsoiDlgGetCheck( dlg, item ); // remember, item == iPrefsTextTabHooks
  924.             
  925.             if ( checked )
  926.             {
  927.                 HsoiSetPrefsRadioButton( dlg, iPrefsTextLeftRadio );
  928.                 for ( i = kPrefsTextFirstRadio; i <= kPrefsTextLastRadio; i++ )
  929.                 {
  930.                     HiliteControl( HsoiDlgGetControl( dlg, i ), kCtlInactive );
  931.                 }
  932.             }
  933.             else
  934.             {
  935.                 for ( i = kPrefsTextFirstRadio; i <= kPrefsTextLastRadio; i++ )
  936.                 {
  937.                     HiliteControl( HsoiDlgGetControl( dlg, i ), kCtlActive );
  938.                 }
  939.             }
  940.             
  941.         
  942.         }
  943.         break;
  944.             
  945.         case iPrefsTextAutoScroll:
  946.         case iPrefsTextOutlineHilite:
  947.         case iPrefsTextReadOnly:
  948.         case iPrefsTextIntCutAndPaste:
  949.         case iPrefsTextDragAndDrop:
  950.         case iPrefsTextOffscreenDrawing:
  951.         
  952.             HsoiDlgToggleCheck( dlg, item );
  953.         
  954.         break;
  955.     
  956.     } // end: switch ( item )
  957.  
  958.     return;
  959. }
  960.  
  961. // take care of notification manager prefs.  this is pretty straight forward (similar
  962. // to the general prefs dialog handler in it's function)
  963.  
  964. static void HsoiNMPrefs( HASPreferences *prefs, DialogRef dlg, short item )
  965. {
  966.     switch ( item )
  967.     {
  968.         case kInit:
  969.         {
  970.             if ( gHasNotification )
  971.             {
  972.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMIcon ), kCtlActive );
  973.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMDiamond ), kCtlActive );
  974.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMSound ), kCtlActive );
  975.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMAlert ), kCtlActive );
  976.                 
  977.                 HsoiDlgSetCheck( dlg, iPrefsNMIcon, prefs->useIconNM );
  978.                 HsoiDlgSetCheck( dlg, iPrefsNMDiamond, prefs->useDiamondNM );
  979.                 HsoiDlgSetCheck( dlg, iPrefsNMSound, prefs->useSoundNM );
  980.                 HsoiDlgSetCheck( dlg, iPrefsNMAlert, prefs->useAlertNM );
  981.             }
  982.             else
  983.             {
  984.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMIcon ), kCtlInactive );
  985.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMDiamond ), kCtlInactive );
  986.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMSound ), kCtlInactive );
  987.                 HiliteControl( HsoiDlgGetControl( dlg, iPrefsNMAlert ), kCtlInactive );
  988.                 
  989.                 HsoiDlgSetCheck( dlg, iPrefsNMIcon, 0 );
  990.                 HsoiDlgSetCheck( dlg, iPrefsNMDiamond, 0 );
  991.                 HsoiDlgSetCheck( dlg, iPrefsNMSound, 0 );
  992.                 HsoiDlgSetCheck( dlg, iPrefsNMAlert, 0 );
  993.             }
  994.                 
  995.         }
  996.         break; // end:  case kInit
  997.         
  998.         case kTerm:
  999.             prefs->useIconNM = HsoiDlgGetCheck( dlg, iPrefsNMIcon );
  1000.             prefs->useDiamondNM = HsoiDlgGetCheck( dlg, iPrefsNMDiamond );
  1001.             prefs->useSoundNM = HsoiDlgGetCheck( dlg, iPrefsNMSound );
  1002.             prefs->useAlertNM = HsoiDlgGetCheck( dlg, iPrefsNMAlert );
  1003.         
  1004.         break; // end: case kTerm
  1005.         
  1006.         
  1007.         case iPrefsNMIcon:
  1008.         case iPrefsNMDiamond:
  1009.         case iPrefsNMSound:
  1010.         case iPrefsNMAlert:
  1011.         
  1012.             HsoiDlgToggleCheck( dlg, item );
  1013.         
  1014.         break;
  1015.     
  1016.     
  1017.     } // end: switch ( item )
  1018.  
  1019.     return;
  1020. }
  1021.  
  1022. // handle the print prefs dialog
  1023.  
  1024. static void HsoiPrintPrefs( HASPreferences *prefs, DialogRef dlg, short item )
  1025. {
  1026.     Boolean        legal;
  1027.     double        xx;
  1028.  
  1029.     switch ( item )
  1030.     {
  1031.         case kInit:
  1032.         {            
  1033.             // set up the checkboxes
  1034.                         
  1035.             HsoiDlgSetCheck( dlg, iPrefsPrintPageNum, prefs->printPageNumbers );
  1036.             HsoiDlgSetCheck( dlg, iPrefsPrintDblSpace, prefs->printDoubleSpaced );
  1037.             
  1038.             // set the margin edit text's to the proper sizes
  1039.             
  1040.             SetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextTop ), prefs->printTopMargin );
  1041.             SetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextBottom ), prefs->printBottomMargin );
  1042.             SetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextLeft), prefs->printLeftMargin );
  1043.             SetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextRight), prefs->printRightMargin );
  1044.  
  1045.             // and install our framing proc
  1046.             
  1047.             HsoiSetDialogItemProc( dlg, iPrefsPrintLineItem, frameItemsUPP );
  1048.             HsoiSetDialogItemProc( dlg, iPrefsPrintMarginFrame, frameItemsUPP );
  1049.             
  1050.             // and go ahead and select all the text in the first edit text
  1051.  
  1052.             SelectDialogItemText( dlg, iPrefsPrintTextTop, 0, MAXSHORT );
  1053.         }
  1054.         break; // end:  case kInit
  1055.         
  1056.         case kTerm:
  1057.  
  1058.             // get the values of the check boxes
  1059.             
  1060.             prefs->printPageNumbers = HsoiDlgGetCheck( dlg, iPrefsPrintPageNum );
  1061.             prefs->printDoubleSpaced = HsoiDlgGetCheck( dlg, iPrefsPrintDblSpace );
  1062.             
  1063.             // get the margin settings
  1064.             
  1065.             GetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextTop ), prefs->printTopMargin );
  1066.             GetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextBottom ), prefs->printBottomMargin );
  1067.             GetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextLeft ), prefs->printLeftMargin );
  1068.             GetDialogItemText( HsoiGetDialogItemHandle( dlg, iPrefsPrintTextRight), prefs->printRightMargin );
  1069.             
  1070.         break; // end: case kTerm
  1071.         
  1072.         
  1073.         case iPrefsPrintPageNum:
  1074.         case iPrefsPrintDblSpace:
  1075.         
  1076.             HsoiDlgToggleCheck( dlg, item );
  1077.         
  1078.         break;
  1079.         
  1080.         case iPrefsPrintTopUpUserItem:
  1081.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextTop, 0.00, kMaxMargin, &legal, &xx );
  1082.             HsoiDoArrowUpDown( dlg, iPrefsPrintTopUpUserItem, iPrefsPrintTextTop, iPrefsPrintTopArrowIcon, 0.01, 0.00, kMaxMargin, true, &xx );
  1083.         break;
  1084.         
  1085.         case iPrefsPrintTopDownUserItem:
  1086.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextTop, 0.00, kMaxMargin, &legal, &xx );
  1087.             HsoiDoArrowUpDown( dlg, iPrefsPrintTopDownUserItem, iPrefsPrintTextTop, iPrefsPrintTopArrowIcon, -0.01, 0.00, kMaxMargin, true, &xx );
  1088.         break;
  1089.         
  1090.         case iPrefsPrintBotUpUserItem:
  1091.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextBottom, 0.00, kMaxMargin, &legal, &xx );
  1092.             HsoiDoArrowUpDown( dlg, iPrefsPrintBotUpUserItem, iPrefsPrintTextBottom, iPrefsPrintBotArrowIcon, 0.01, 0.00, kMaxMargin, true, &xx );
  1093.         break;
  1094.         
  1095.         case iPrefsPrintBotDownUserItem:
  1096.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextBottom, 0.00, kMaxMargin, &legal, &xx );
  1097.             HsoiDoArrowUpDown( dlg, iPrefsPrintBotDownUserItem, iPrefsPrintTextBottom, iPrefsPrintBotArrowIcon, -0.01, 0.00, kMaxMargin, true, &xx );
  1098.         break;
  1099.         
  1100.         case iPrefsPrintLeftUpUserItem:
  1101.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextLeft, 0.00, kMaxMargin, &legal, &xx );
  1102.             HsoiDoArrowUpDown( dlg, iPrefsPrintLeftUpUserItem, iPrefsPrintTextLeft, iPrefsPrintLeftArrowIcon, 0.01, 0.00, kMaxMargin, true, &xx );
  1103.         break;
  1104.         
  1105.         case iPrefsPrintLeftDownUserItem:
  1106.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextLeft, 0.00, kMaxMargin, &legal, &xx );
  1107.             HsoiDoArrowUpDown( dlg, iPrefsPrintLeftDownUserItem, iPrefsPrintTextLeft, iPrefsPrintLeftArrowIcon, -0.01, 0.00, kMaxMargin, true, &xx );
  1108.         break;
  1109.         
  1110.         case iPrefsPrintRightUpUserItem:
  1111.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextRight, 0.00, kMaxMargin, &legal, &xx );
  1112.             HsoiDoArrowUpDown( dlg, iPrefsPrintRightUpUserItem, iPrefsPrintTextRight, iPrefsPrintRightArrowIcon, 0.01, 0.00, kMaxMargin, true, &xx );
  1113.         break;
  1114.         
  1115.         case iPrefsPrintRightDownUserItem:
  1116.             HsoiGetDialogItemValue( dlg, iPrefsPrintTextRight, 0.00, kMaxMargin, &legal, &xx );
  1117.             HsoiDoArrowUpDown( dlg, iPrefsPrintRightDownUserItem, iPrefsPrintTextRight, iPrefsPrintRightArrowIcon, -0.01, 0.00, kMaxMargin, true, &xx );
  1118.         break;
  1119.     
  1120.     } // end: switch ( item )
  1121.  
  1122.     return;
  1123. }
  1124.  
  1125.  
  1126. #pragma mark -
  1127. #pragma mark ••• Prefs Dialog •••
  1128.  
  1129.  
  1130.  
  1131. /*    the prefs dialog filter */
  1132.  
  1133. pascal Boolean hsoiPrefsDialogFilter( DialogRef theDialog, EventRecord *theDialogEvent, short *theDialogItem )
  1134. {
  1135. #pragma unused( theDialogItem )
  1136.  
  1137.     Boolean            retval;
  1138.     short            part;
  1139.     WindowRef        theWindow;
  1140.     Point            where;
  1141.     short            itemNumber;
  1142.     Str255            str;
  1143.     Boolean            numeric;
  1144.     ControlRef        popupCtl;
  1145.     extern short    curDlgNum;
  1146.     GrafPtr            oldPort;
  1147.     char            theKey;
  1148.     
  1149.     GetPort( &oldPort );
  1150.     SetGrafPortOfDialog( theDialog );
  1151.     
  1152.     retval = false;
  1153.     
  1154.     // Norstad handles tracking the cursor here...we don't cause we just call
  1155.     // SetDialogTrackCursor() back in DoPrefsDialog() to track the cursor. Luv System 7
  1156.     
  1157.     // but, let's track the mouseDown events just in case they depress the popup menus
  1158.     
  1159.     if ( theDialogEvent->what == mouseDown )
  1160.     {
  1161.         part = FindWindow( theDialogEvent->where, &theWindow );
  1162.         
  1163.         if ( (part == inContent) && ( theWindow == GetDialogWindow(theDialog) ) )
  1164.         {
  1165.             where = theDialogEvent->where;
  1166.             GlobalToLocal( &where );
  1167.             itemNumber = FindDialogItem( theDialog, where );
  1168.             itemNumber += 1; // gotta add 1 to it, see TN 112
  1169.             
  1170.             // this is really skanky...
  1171.             
  1172.             if ( itemNumber > 0 )
  1173.             {
  1174.                 if ( ( curDlgNum == rPrefsTextDLOG ) && ( itemNumber == iPrefsTextSizePopup ) )
  1175.                 {
  1176.                 
  1177.                     SelectDialogItemText( theDialog, iPrefsTextSizeEditBox, 0, MAXSHORT );
  1178.                     HsoiDlgGetPString( theDialog, iPrefsTextSizeEditBox, str );
  1179.                     popupCtl = HsoiDlgGetControl( theDialog, itemNumber );
  1180.                     numeric = 1;
  1181.                     
  1182.                     if ( HsoiTrackPopup( popupCtl, where, str, numeric ) )
  1183.                     {
  1184.                         *theDialogItem = itemNumber;
  1185. //                        SetDialogItemText( HsoiGetDialogItemHandle(theDialog, iPrefsTextSizeEditBox), str );
  1186.                         retval = true;
  1187.                     }
  1188.                     else
  1189.                     {
  1190.                         retval = false;
  1191.                     }
  1192.                 }
  1193.             }
  1194.         }
  1195.     }
  1196.     
  1197.     // now, let's handle some keydown stuff...you could filter all keys out if you want to,
  1198.     // but the really important part is in the text dialog.  the edit text field in there
  1199.     // is for font size, which should only accept certain values (numerics, and not a lot
  1200.     // of them...don't want 40000000 point size now do we).  So, this will filter things out
  1201.     
  1202.     if ( (( theDialogEvent->what == keyDown ) || ( theDialogEvent->what == autoKey )) &&
  1203.             ( curDlgNum == rPrefsTextDLOG ) )
  1204.     {
  1205.         theKey = theDialogEvent->message & charCodeMask;
  1206.         
  1207.         // the first line of this "if" is the important one to filter out non-numeric keys,
  1208.         // however, that also filters out a lot of important keys, like return/enter, esc,
  1209.         // and editing keys - keys necessary for regular dialog stuff.  so, we must make exceptions.
  1210.         
  1211.         if ( !(theKey > 0x2F && theKey < 0x3A) &&    // it's not a number
  1212.                 ( theKey != kEnterKey ) &&            // it's not the Enter key
  1213.                 ( theKey != kReturnKey ) &&            // it's not the return key
  1214.                 ( theKey != kEscKey ) &&            // it's not the escape key
  1215.                 ( theKey != kBackSpace ) &&            // it's not backspace
  1216.                 ( theKey != kDeleteKey ) &&            // it's not delete
  1217.                 ( theKey != kLeftArrow ) &&            // it's not an arrow key (for editing)
  1218.                 ( theKey != kRightArrow ) &&
  1219.                 ( theKey != kUpArrow ) &&
  1220.                 ( theKey != kDownArrow ) )
  1221.         {
  1222.             // not a kosher key..let's complain
  1223.             
  1224.             SysBeep( 1 );
  1225.             retval = true; // we handled it so no passing to the DM
  1226.         }
  1227.         else // it's a kosher keypress
  1228.             retval = false; // let the DM handle it
  1229.             
  1230.             
  1231.         // now an additional bit of filtering.  we wouldn't want the user to be able to
  1232.         // enter a font size greater (or less) than the sizes we're supporting (in this case,
  1233.         // from 1 to 500 inclusive).  So, we must make sure they don't do it.  You can see one
  1234.         // way to handle this in the OtherFontSize dialog, but this is another, and due to
  1235.         // the complexity of the prefs, we'll go with this alternative method.
  1236.         // the jist:  if a kosher key, if a number (cause there are other kosher keys than just
  1237.         // numerics), and if the dialog is the text one (redundant to do this), then we'll
  1238.         // see if the keypress would make a number that would give us an invalid font size.
  1239.         // if it would, vomit, if not let the keypress fall to the DM
  1240.         
  1241.         // unfortunately, this is INCOMPLETE right now...there's a catch..i forgot about what
  1242.         // could happen if there was a selection range and/or the insertion point wasn't at
  1243.         // the end of the text....those present all other sorts of problems...
  1244.         // if you can figure out a way to handle all this, great!  tell me! :)  Otherwise,
  1245.         // for now, it'll just sit and wait....
  1246.         
  1247.         if ( (retval == false) && (theKey > 0x2F && theKey < 0x3A) && (curDlgNum == rPrefsTextDLOG) )
  1248.         {
  1249.             Str255        editText;
  1250.             long        fontSize;
  1251.             short        strLength;
  1252.             
  1253.             // now, since we know it's the prefs text dialog, we can "hard code" a few things
  1254.             // (like we know exactly the item number in the DITL for the edit box...if you wanted
  1255.             // to make this more flexible, you'd have to add a lot of programmer-defined data
  1256.             // structures, etc to keep track of things...i don't wanna bother cause i really
  1257.             // don't need it here).  it'd be a good learning exercise for ya :)
  1258.             
  1259.             // first, we get the currently existing text in the edit text item:
  1260.             
  1261.             GetDialogItemText( HsoiGetDialogItemHandle( theDialog, iPrefsTextSizeEditBox ), editText );
  1262.             
  1263.             // now the fun part:  since the existing text doesn't have the new key on the end of
  1264.             // it, we'll append it there ourselves to check if it'd make a (in)valid size.
  1265.         
  1266.             strLength = editText[0]; // get the length of the string
  1267.             
  1268.             // now append the key (cause we have it via the charCodeMask) to the end:
  1269.             
  1270.             editText[ strLength + 1] = theKey;
  1271.             
  1272.             // convert to a number
  1273.             
  1274.             StringToNum( editText, &fontSize );
  1275.             
  1276.             // and now choose to vomit...
  1277.             
  1278.             // as you can tell, this little part of the dialog filter isn't finished yet...
  1279.             
  1280.         }
  1281.             
  1282.     
  1283.     }
  1284.     
  1285.     // due to these lovely system 7 functions, there really isn't much for us to have
  1286.     // to handle in the filter, except to 
  1287.     
  1288.     if ( !retval )
  1289.         retval = hsoiMyStandardDialogFilter( theDialog, theDialogEvent, theDialogItem );
  1290.  
  1291.  
  1292.     // however, we will need to put something in here to filter things out...i think the
  1293.     // only keydown's that need to get filtered out...well, hmm...i guess any and all
  1294.     // keydown's ought to get filtered out...except if the text prefs is up, then there
  1295.     // is one edit text box, and then they should only be allowed to enter numerics
  1296.     
  1297.     // on that note...we can just duplicate the otherFontSizeDialogFilter for this, but
  1298.     // in both this one and in otherFontSizeDialogFilter, we ought to see about adding
  1299.     // in stuff to limit the text size entered...like up to 3 characters...plus, we'll
  1300.     // need to check the cut and paste stuff...first, cannot paste stuff longer than
  1301.     // 3 characters, but also, cannot paste anything but pure numbers!  boy, this'll
  1302.     // be a fun filter, eh?
  1303.     
  1304.     SetPort( oldPort );
  1305.     
  1306.     return retval;
  1307. }
  1308.  
  1309. /*     where it all begins... */
  1310.  
  1311.  
  1312. void    HsoiDoPrefsDialog( void )
  1313. {
  1314.     typedef void (*prefsFuncPtr) ( HASPreferences *prefs, DialogRef dlg, short item );
  1315.     
  1316.     static prefsFuncPtr prefsFuncPtrs[] = {
  1317.                                             HsoiGeneralPrefs,
  1318.                                             HsoiTextPrefs,
  1319.                                             HsoiNMPrefs,
  1320.                                             HsoiPrintPrefs
  1321.                                           };
  1322.     
  1323.     short                newDlgNum;
  1324.     prefsFuncPtr        theFunc;
  1325.     HASPreferences        *prefs;
  1326.     DialogRef            curDlg;
  1327.     DialogRef            prevDlg = nil;
  1328.     short                item;
  1329.     OSErr                err;
  1330.     Handle                controlH;
  1331.     ModalFilterUPP        prefsDialogFilterProc;
  1332.  
  1333.     // if we have a sound playing, stop it
  1334.     
  1335.     if ( SoundIsPlaying() )
  1336.         StopCurrentSound();
  1337.  
  1338.     // create a working prefs instance
  1339.     
  1340.     prefs = (HASPreferences *)NewPtrClear( sizeof( HASPreferences ) );
  1341.     err = MemError();
  1342.     if ( err != noErr )
  1343.     {
  1344.         // stick some error handling in here
  1345.         
  1346.         prefs = nil;
  1347.         
  1348.         // probably ought to return err or something here too.
  1349.         
  1350.         // or, just impliment Norstad's method of memory handling, etc.
  1351.     }
  1352.     
  1353.     *prefs = gMyPrefs;
  1354.     
  1355.     // get our frame item UPP (get it now, but use it only in the text prefs
  1356.     // (it gets installed in HsoiTextPrefs)
  1357.     
  1358.     if ( frameItemsUPP == nil )
  1359.         frameItemsUPP = NewUserItemProc( HsoiDrawGroupBox );
  1360.     
  1361.     while ( true )
  1362.     {
  1363.         // get the dialog
  1364.         curDlg = GetNewDialog( curDlgNum, nil, MOVE_TO_FRONT );
  1365.             
  1366.         // set the topic popup menu to the initial dialog
  1367.         
  1368.         controlH = HsoiGetDialogItemHandle( curDlg, iPrefsTopicPopup );
  1369.         SetControlValue( (ControlRef)controlH, curDlgNum - rPrefsGeneralDLOG + 1 );
  1370.         
  1371.         // set the proper function callback routine
  1372.         
  1373.         theFunc = prefsFuncPtrs[ curDlgNum - rPrefsGeneralDLOG ];
  1374.         
  1375.         // call that proper function callback to set it to it's initial values
  1376.         
  1377.         (*theFunc)(prefs, curDlg, kInit );
  1378.             
  1379.         // show the dialog
  1380.         
  1381.         ShowWindow( GetDialogWindow(curDlg) );
  1382.         
  1383.         // if curDlgNum is the text prefs dialog, paint the "default" text color
  1384.         // setting rect
  1385.         
  1386.         if ( curDlgNum == rPrefsTextDLOG )
  1387.             HsoiPaintColorRect( curDlg, prefs );
  1388.             
  1389.         // if need be, get rid of the previous dialog box
  1390.         
  1391.         if ( prevDlg != nil )
  1392.             DisposeDialog( prevDlg );
  1393.         
  1394.         // get the modal filter proc
  1395.         
  1396.         prefsDialogFilterProc = NewModalFilterProc( hsoiPrefsDialogFilter );
  1397.         
  1398.         // let the system know to track the cursor movement
  1399.         // don't need to call SetDialogDefault/CancelItem() at all cause that's
  1400.         // handled in the filter via HsoiMyStandardDialogFilter()
  1401.         
  1402.         SetDialogTracksCursor( curDlg, true );
  1403.         
  1404.         // do the dialog
  1405.         
  1406.         while ( true )
  1407.         {
  1408.             ModalDialog( prefsDialogFilterProc, &item );
  1409.             
  1410.             if ( item == cancel )
  1411.                 break;
  1412.                             
  1413.             if ( item == ok )
  1414.             {
  1415.                 if ( curDlgNum == rPrefsTextDLOG )
  1416.                 {
  1417.                     Str255        editText;
  1418.                     long        fontSize;
  1419.                     
  1420.                     // check for illegal font sizes in the prefs text dialog
  1421.                     
  1422.                     GetDialogItemText( HsoiGetDialogItemHandle( curDlg, iPrefsTextSizeEditBox ), editText );
  1423.                     StringToNum( editText, &fontSize );
  1424.             
  1425.                     if ( (fontSize > kMaxFontSize) || (fontSize < kMinFontSize) )
  1426.                     {
  1427.                         HsoiDoIllegalFontSize();
  1428.                         SelectDialogItemText( curDlg, iPrefsTextSizeEditBox, 0, MAXSHORT );
  1429.                         
  1430.                         continue;
  1431.                     }
  1432.                     else
  1433.                         break;
  1434.                 }
  1435.                 else
  1436.                     break;
  1437.             }
  1438.             
  1439.             
  1440.             if ( item == iPrefsTopicPopup )
  1441.             {
  1442.                 controlH = HsoiGetDialogItemHandle( curDlg, iPrefsTopicPopup );
  1443.                 newDlgNum = GetControlValue( (ControlRef)controlH ) + rPrefsGeneralDLOG - 1;
  1444.                 
  1445.                 if ( newDlgNum == curDlgNum )
  1446.                     continue;
  1447.                 
  1448.                 // check for illegal font sizes if they try to leave the text dialog....
  1449.                 
  1450.                 if ( (curDlgNum == rPrefsTextDLOG) && (newDlgNum != rPrefsTextDLOG) )
  1451.                 {
  1452.                     Str255        editText;
  1453.                     long        fontSize;
  1454.                     
  1455.                     GetDialogItemText( HsoiGetDialogItemHandle( curDlg, iPrefsTextSizeEditBox ), editText );
  1456.                     StringToNum( editText, &fontSize );
  1457.                     
  1458.                     if ( (fontSize > kMaxFontSize) || (fontSize < kMinFontSize) )
  1459.                     {
  1460.                         HsoiDoIllegalFontSize();
  1461.                         
  1462.                         // we need to set the popup back to the text prefs
  1463.                         
  1464.                         SetControlValue( (ControlRef)controlH, 2 );
  1465.                         
  1466.                         // and select the edit text
  1467.                         
  1468.                         SelectDialogItemText( curDlg, iPrefsTextSizeEditBox, 0, MAXSHORT );
  1469.                         
  1470.                         continue;
  1471.                     }
  1472.                     else
  1473.                         break;
  1474.                 }
  1475.                 
  1476.                 break;
  1477.             } // end if ( item == iPrefsTopicPopup )
  1478.             
  1479.             // not a "special" case, so let the individual dialog pane functions
  1480.             // handle the item hit
  1481.             
  1482.             (*theFunc)(prefs, curDlg, item);
  1483.         }
  1484.         
  1485.         // call the termination stuff
  1486.         
  1487.         (*theFunc)(prefs, curDlg, kTerm);
  1488.         
  1489.         // and if ok or cancel, break out of this loop
  1490.         
  1491.         if ( item == ok || item == cancel )
  1492.             break;
  1493.         
  1494.         // reset the dlg stuff so we know what's current
  1495.         
  1496.         curDlgNum = newDlgNum;
  1497.         prevDlg = curDlg;
  1498.     
  1499.     } // end:  while ( true )
  1500.  
  1501.     // dump our routine descriptors
  1502.     
  1503.     DisposeRoutineDescriptor( prefsDialogFilterProc );
  1504.     DisposeRoutineDescriptor( frameItemsUPP );
  1505.     
  1506.     // dump the dialog
  1507.     DisposeDialog( curDlg );
  1508.     
  1509.     if ( item == ok )
  1510.     {
  1511.         // notify of any possible messages (e.g. changes take effect on next restart)
  1512.         
  1513.         // set the global prefs in memory to the changes made in here
  1514.         
  1515.         gMyPrefs = *prefs;
  1516.         
  1517.         // most likely we have new prefs settings so schedule the new prefs to be
  1518.         // written out to file
  1519.         
  1520.         gWritePrefs = true;
  1521.     }
  1522.     
  1523.     // don't need to write out a new prefs file since nothing changed (we hope)
  1524.     
  1525.     if ( item == cancel )
  1526.         gWritePrefs = false;
  1527.     
  1528.     // remember to chuck this so we don't have a memory leak
  1529.     
  1530.     DisposePtr( (Ptr)prefs );
  1531.  
  1532.     return;
  1533. }
  1534.  
  1535. #pragma mark -
  1536. #pragma mark ••• Prefs File Handlers •••
  1537.  
  1538. /*
  1539.  * Now to deal with other preference related things, like reading and writing the prefs file
  1540.  * and other stuff like that there
  1541.  */
  1542.  
  1543.  
  1544.  
  1545. // let's initialize the prefs related things.  we do a few things here:
  1546. // 1.  we try to find where the prefs file is  2.  if there was no prefs file found, we'll
  1547. // have to create a new prefs file, so let's do the registration dialog.  3. read the
  1548. // prefs into memory.
  1549.  
  1550. void    HsoiInitPrefs( void )
  1551. {
  1552.     Boolean        readOK;
  1553.     
  1554.     HsoiLocatePrefsFile();
  1555.     
  1556.     if ( sNewPrefs )
  1557.     {
  1558.         gWritePrefs = true;
  1559.         HsoiDoRegistration();
  1560.     }
  1561.     
  1562.     readOK = HsoiReadPrefs();
  1563.     
  1564.     return;
  1565. }
  1566.  
  1567. // try to find the prefs file
  1568.  
  1569. void     HsoiLocatePrefsFile( void )
  1570. {
  1571.     OSErr             err;
  1572.     FInfo             fndrInfo;
  1573.     FSSpec             oldFile;
  1574.     FCBPBRec         pBlock;
  1575.     FSSpec             prefsFolder;
  1576.     CInfoPBRec         pb;
  1577.     
  1578.     sNewPrefs = false; // assume we don't need new prefs
  1579.     
  1580.     // check to see if there is a prefs file in the same folder as the application.
  1581.     // if so, use that prefs file
  1582.     
  1583.     pBlock.ioNamePtr = nil;
  1584.     pBlock.ioVRefNum = 0;
  1585.     pBlock.ioRefNum = LMGetCurApRefNum();
  1586.     pBlock.ioFCBIndx = 0;
  1587.     err = PBGetFCBInfoSync(&pBlock );
  1588.     if (err == noErr)
  1589.     {
  1590.         err = FSMakeFSSpec(pBlock.ioFCBVRefNum, pBlock.ioFCBParID, PREF_FILE_NAME, &gPrefsFileSpec);
  1591.         if ( err == fnfErr )
  1592.             sNewPrefs = true;
  1593.         if (err == noErr)
  1594.         {
  1595.             err = FSpGetFInfo(&gPrefsFileSpec, &fndrInfo);
  1596.             if (err == noErr)
  1597.             {
  1598.                 sNewPrefs = false;
  1599.                 goto exit;
  1600.             }
  1601.         }
  1602.     }
  1603.  
  1604.     
  1605.     //    Construct gPrefsFileSpec = FSSpec for "Hsoi's App Shell Demo Prefs" file
  1606.     //    in Preferences folder.
  1607.  
  1608.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  1609.                         &gPrefsFileSpec.vRefNum, &gPrefsFileSpec.parID);
  1610.     if (err != noErr)
  1611.     {
  1612.         // do some better error handling...
  1613.         SysBeep(1);
  1614.         SysBeep(2);
  1615.         ExitToShell();
  1616.     }
  1617.  
  1618.     HsoipStringCopy( PREF_FILE_NAME, gPrefsFileSpec.name );
  1619.     
  1620.     // Check to see if "Hsoi's App Shell Demo Prefs" exists in the Preferences
  1621.     // folder. If it does exist, use that one. 
  1622.        
  1623.     err = FSpGetFInfo(&gPrefsFileSpec, &fndrInfo);
  1624.     if ( err == fnfErr )
  1625.         sNewPrefs = true;
  1626.     if (err == noErr)
  1627.     {
  1628.         sNewPrefs = false;
  1629.         goto exit;
  1630.     }
  1631.     
  1632.     // If "Hsoi's App Shell Demo Prefs" does not exist in the Preferences
  1633.     // folder, next try "HAS Demo Preferences" in the Preferences folder. If that
  1634.     // exists, rename it "Hsoi's App Shell Demo Prefs".
  1635.        
  1636.     err = FSMakeFSSpec(gPrefsFileSpec.vRefNum, gPrefsFileSpec.parID, PREF_FILE_NAME_OLD, &oldFile);
  1637.     if ( err == fnfErr )
  1638.         sNewPrefs = true;
  1639.     if (err == noErr)
  1640.     {
  1641.         sNewPrefs = false;
  1642.         FSpRename(&oldFile, PREF_FILE_NAME);
  1643.         return;
  1644.     }
  1645.     
  1646.     // If this fails, next try "HAS Demo Preferences" in the System folder. If that
  1647.     // exists, move it to the Preferences folder and rename it "Hsoi's App Shell Demo Prefs".
  1648.        
  1649.     err = FindFolder(kOnSystemDisk, kSystemFolderType, kCreateFolder, &oldFile.vRefNum,
  1650.                         &oldFile.parID);
  1651.     if (err != noErr)
  1652.         return;
  1653.         
  1654.     pb.dirInfo.ioNamePtr = prefsFolder.name;
  1655.     pb.dirInfo.ioVRefNum = gPrefsFileSpec.vRefNum;
  1656.     pb.dirInfo.ioFDirIndex = -1;
  1657.     pb.dirInfo.ioDrDirID = gPrefsFileSpec.parID;
  1658.  
  1659.     err = PBGetCatInfoSync( &pb );
  1660.     if (err != noErr)
  1661.         return;
  1662.  
  1663.     prefsFolder.vRefNum = pb.dirInfo.ioVRefNum;
  1664.     prefsFolder.parID = pb.dirInfo.ioDrParID;
  1665.  
  1666.     err = FSpCatMove(&oldFile, &prefsFolder);
  1667.     if ( err == fnfErr )
  1668.         sNewPrefs = true;
  1669.     if (err != noErr)
  1670.         return;
  1671.     
  1672.     oldFile.vRefNum = gPrefsFileSpec.vRefNum;
  1673.     oldFile.parID = gPrefsFileSpec.parID;
  1674.     
  1675.     err = FSpRename(&oldFile, PREF_FILE_NAME);
  1676.     if (err != noErr)
  1677.         return;
  1678.     
  1679.     err = FSpGetFInfo(&gPrefsFileSpec, &fndrInfo);
  1680.     if (err != noErr)
  1681.         return;
  1682.  
  1683.     fndrInfo.fdFlags &= ~(1 << 8);    /* clear hasBeenInited to force Finder to
  1684.                                          assign new icon location */
  1685.     FSpSetFInfo(&gPrefsFileSpec, &fndrInfo);
  1686.     sNewPrefs = false;
  1687.     
  1688.     return;
  1689.     
  1690. exit:
  1691.  
  1692.     if (fndrInfo.fdCreator == PREF_CREATOR_TYPE && fndrInfo.fdType == TYPE_PREFERENCES)
  1693.         return;
  1694.  
  1695.     // else we hit an error...bad error handling here, but eh...
  1696.     
  1697.     SysBeep(1);SysBeep(2);SysBeep(3);
  1698.     ExitToShell();
  1699.  
  1700. }
  1701.  
  1702. /*
  1703.     this reads in the prefs settings from the prefs file.  one neat thing it does (and
  1704.     you can see this same philosophy in the way all the prefs releated stuff is set up)
  1705.     is allow for compatability between releases. here's how it works.
  1706.     
  1707.     you make your application, you release it to the world and a lot of people start to
  1708.     use it.  you continue to work on the app, and in a future release, you added more
  1709.     prefs settings.  The way things are designed in HAS allows you to seemlessly update
  1710.     things.  Old prefs files (from previous versions of your app) will still be read
  1711.     in and those settings utilized, and any new features you have get initialized to
  1712.     your default settings.
  1713.     
  1714.     if you'd like to see this in action, go down to the line where the APP_VERS_STR
  1715.     is copied into the gMyPrefs variable.  change APP_VERS_STR to a previous version
  1716.     of HAS (like "\p0.9a3"...i.e. HsoipStringCopy( "\p0.9a3", gMyPrefs.prefVers );)
  1717.  
  1718.     Now, trash your prefs file, launch the HAS Demo (you'll obviously have to compile
  1719.     things again), then quit (to get the prefs to write out).  Now come back into
  1720.     the code and change that line back to APP_VERS_STR.
  1721.     
  1722.     oh, and you might want to throw something in in the
  1723.         if ( need10a1Defaults )
  1724.     statement like: DebugStr( "\pNeeded 1.0a1 defaults" );  to really watch things
  1725.     happen.
  1726.     
  1727.     you should see things kick in.
  1728.     
  1729.     get it?  look over the code and as you add prefs and stuff, you'll get the
  1730.     idea.
  1731.  
  1732.     for an even better view of seeing this in some heavy action, check out the
  1733.     source code to John Norstad's NewsWatcher (upon which all this prefs stuff
  1734.     was derrived).
  1735.     
  1736.     As a side note, in all this backwards compatability, if you remove some
  1737.     prefs feature, don't remove it's struct member.  for example, if i no
  1738.     longer wished to use the notification manager, you'd think to remove all
  1739.     the NM stuff from the prefs struct.  do NOT do this...else in backwards
  1740.     compatability, when reading in the struct (see how FSRead is done), values
  1741.     will get assigned to god knows what....be careful!  just allow them to be
  1742.     read in, but ignore them....
  1743.     
  1744. */
  1745.  
  1746. Boolean        HsoiReadPrefs( void )
  1747. {
  1748.     OSErr            err;
  1749.     short            fRefNum = 0;
  1750.     long            prefRecSize;
  1751.     Boolean            need09a2Defaults = true;
  1752.     Boolean            need09a3Defaults = true;
  1753.     Boolean            need10a1Defaults = true;
  1754.     Boolean            need10a2Defaults = true;
  1755.     Boolean            need10a3Defaults = true;
  1756.     Boolean            haveFont;
  1757.     short            fontNum;
  1758.     
  1759.     // open the prefs file
  1760.     
  1761.     err = FSpOpenDF( &gPrefsFileSpec, fsRdPerm, &fRefNum );
  1762.  
  1763.     if ( err == noErr )
  1764.     {
  1765.         // get the size of the prefs rec
  1766.         
  1767.         prefRecSize = sizeof( HASPreferences );
  1768.         
  1769.         // read all the file in in one big chunk
  1770.         
  1771.         err = FSRead( fRefNum, &prefRecSize, (Ptr)&gMyPrefs );
  1772.         if ( (err == noErr) && (prefRecSize == sizeof( HASPreferences )) )
  1773.         {
  1774.             // if it succeeded, we obviously don't need 0.9a2 defaults (cause
  1775.             // that was the first version to use prefs)
  1776.             
  1777.             need09a2Defaults = false;
  1778.             
  1779.             // now cycle through, checking the version number to find what
  1780.             // version the prefs are
  1781.             
  1782.             if ( EqualString( gMyPrefs.prefVers, "\p0.9a3", false, false ) )
  1783.             {
  1784.                 need09a3Defaults = false;
  1785.             }
  1786.             
  1787.             if ( EqualString( gMyPrefs.prefVers, "\p1.0a1", false, false ) )
  1788.             {
  1789.                 need09a3Defaults = false;
  1790.                 need10a1Defaults = false;
  1791.             }
  1792.             
  1793.             if ( EqualString( gMyPrefs.prefVers, "\p1.0a2", false, false ) )
  1794.             {
  1795.                 need09a3Defaults = false;
  1796.                 need10a1Defaults = false;
  1797.                 need10a2Defaults = false;
  1798.             }
  1799.             
  1800.             if ( EqualString( gMyPrefs.prefVers, "\p1.0a3", false, false ) )
  1801.             {
  1802.                 need09a3Defaults = false;
  1803.                 need10a1Defaults = false;
  1804.                 need10a2Defaults = false;
  1805.                 need10a3Defaults = false;
  1806.             }
  1807.                         
  1808.             /* and you could continue this with subsequent versions like this:
  1809.             
  1810.             else if ( EqualString( gMyPrefs.prefVers, "\p1.0a4", false, false ) )
  1811.             {
  1812.                 need09a3Defaults = false;
  1813.                 need10a1Defaults = false;
  1814.                 need10a2Defaults = false;
  1815.                 need10a3Defaults = false;
  1816.                 need10a4Defaults = false;
  1817.             }
  1818.             else if ( EqualString( gMyPrefs.prefVers, "\p1.0b1", false, false ) ||
  1819.                     ( EqualString( gMyPrefs.prefVers, "\p1.0r1", false, false ) ) ) // prefs struct didn't change between these versions
  1820.             {
  1821.                 need09a3Defaults = false;
  1822.                 need10a1Defaults = false;
  1823.                 need10a2Defaults = false;
  1824.                 need10a3Defaults = false;
  1825.                 need10b1Defaults = false;
  1826.                 need10r1Defaults = false;
  1827.             }
  1828.             */
  1829.         }
  1830.         else // if ( err == noErr && count == sizeof( HASPrefernces ) )
  1831.         {
  1832.             FSClose( fRefNum );
  1833.             fRefNum = 0;
  1834.         }
  1835.     }
  1836.     else // if err == noErr
  1837.     {
  1838.         fRefNum = 0;
  1839.     }
  1840.     
  1841.     // now, depending on what defaults we need, assign them to our prefs struct instance
  1842.     // so we have some default values
  1843.     
  1844.     if ( need09a2Defaults )
  1845.     {
  1846.         // version string
  1847.         
  1848.         HsoipStringCopy( APP_VERS_STR, gMyPrefs.prefVers );
  1849.     
  1850.         // default user name and user org
  1851.         // handled in the HsoiInitPrefs() stuff
  1852.         
  1853. //        HsoipStringCopy( DEFAULT_USERNAME, gMyPrefs.userName );
  1854. //        HsoipStringCopy( DEFAULT_ORGANIZATION, gMyPrefs.userOrg );
  1855.         
  1856.         // default text stuff
  1857.         
  1858.         HsoipStringCopy( "\pGeneva", gMyPrefs.defFont );
  1859.         gMyPrefs.defFace = normal;
  1860.         gMyPrefs.defSize = 12;
  1861.         gMyPrefs.defColor.red = 0x0000;
  1862.         gMyPrefs.defColor.green = 0x0000;
  1863.         gMyPrefs.defColor.blue = 0x0000;
  1864.         gMyPrefs.defAlign = weFlushLeft;
  1865.         
  1866.     
  1867.         // set the features
  1868.         
  1869.         gMyPrefs.useTabHooks = false;
  1870.         BSET( gMyPrefs.defFeatures, weFAutoScroll );
  1871.         BSET( gMyPrefs.defFeatures, weFOutlineHilite );
  1872.         BSET( gMyPrefs.defFeatures, weFIntCutAndPaste );
  1873.         BSET( gMyPrefs.defFeatures, weFDragAndDrop );
  1874.         BSET( gMyPrefs.defFeatures, weFDrawOffscreen );
  1875.         
  1876.         // set the notification manager stuff
  1877.         
  1878.         if ( gHasNotification )
  1879.         {
  1880.             gMyPrefs.useIconNM = true;
  1881.             gMyPrefs.useDiamondNM = true;
  1882.             gMyPrefs.useSoundNM = true;
  1883.             gMyPrefs.useAlertNM = true;
  1884.         }
  1885.         else
  1886.         {
  1887.             gMyPrefs.useIconNM = false;
  1888.             gMyPrefs.useDiamondNM = false;
  1889.             gMyPrefs.useSoundNM = false;
  1890.             gMyPrefs.useAlertNM = false;
  1891.         }
  1892.         
  1893.         // and the general prefs
  1894.         
  1895.         gMyPrefs.createWindow = true;
  1896.         gMyPrefs.playHelpSound = true;
  1897.         gMyPrefs.doSplashScreen = true;
  1898.         gMyPrefs.doStartupSpeech = gHasSpeechManager;
  1899.         
  1900.         // make sure the prefs will be written out when we quit
  1901.         
  1902.         gWritePrefs = true;
  1903.     }
  1904.     
  1905.     if ( need09a3Defaults )
  1906.     {
  1907.         // nothing really to add, but just make sure we have the
  1908.         // new version string
  1909.  
  1910.         HsoipStringCopy( APP_VERS_STR, gMyPrefs.prefVers );
  1911.         gWritePrefs = true;
  1912.     }
  1913.     
  1914.     if ( need10a1Defaults )
  1915.     {
  1916.         // nothing really to add, but just make sure we have the
  1917.         // new version string
  1918.  
  1919.         HsoipStringCopy( APP_VERS_STR, gMyPrefs.prefVers );
  1920.         gWritePrefs = true;
  1921.     }
  1922.     
  1923.     if ( need10a2Defaults )
  1924.     {
  1925.         gMyPrefs.printPageNumbers = true;
  1926.         HsoipStringCopy( "\p1.0", gMyPrefs.printLeftMargin );
  1927.         HsoipStringCopy( "\p1.0", gMyPrefs.printRightMargin );
  1928.         HsoipStringCopy( "\p1.0", gMyPrefs.printTopMargin );
  1929.         HsoipStringCopy( "\p1.0", gMyPrefs.printBottomMargin );
  1930.         gMyPrefs.printDoubleSpaced = true;
  1931.         HsoipStringCopy( "\p", gMyPrefs.sVoiceStr );
  1932.         gMyPrefs.sVoiceRate = 0;
  1933.         gMyPrefs.sVoiceMod = 0;
  1934.         gMyPrefs.sVoicePitch = 0;
  1935.  
  1936.         HsoipStringCopy( APP_VERS_STR, gMyPrefs.prefVers );
  1937.         gWritePrefs = true;
  1938.  
  1939.     }
  1940.     
  1941.     if ( need10a3Defaults )
  1942.     {
  1943.         // nothing really to add, but just make sure we have the
  1944.         // new version string
  1945.  
  1946.         HsoipStringCopy( APP_VERS_STR, gMyPrefs.prefVers );
  1947.         gWritePrefs = true;
  1948.     }
  1949.     
  1950.     /* and if you had more things...
  1951.     
  1952.     if ( need10a4Defaults )
  1953.     {
  1954.         gMyPrefs.newFeature = false;
  1955.         gMyPrefs.anotherThing = -1;
  1956.     }
  1957.     
  1958.     etc...
  1959.     */
  1960.     
  1961.     // make sure the prefVers is set right...it should already be set by the
  1962.     // above stuff, but hey...we'll make sure (good for sanity checking and
  1963.     // debugging purposes).
  1964.     
  1965.     HsoipStringCopy( APP_VERS_STR, gMyPrefs.prefVers );
  1966.     
  1967.     // make sure we have the desired font on the system (it might have been deleted, not available,
  1968.     // the user might use a font manager like Suitcase therefore it's not around right now, etc)
  1969.     
  1970.     haveFont = HsoiGetFontNumber( gMyPrefs.defFont, &fontNum );
  1971.     
  1972.     if ( !haveFont )
  1973.     {
  1974.         ParamText( "\pThe font", gMyPrefs.defFont, "\pdoes not exist on this system.",
  1975.                     "\pGeneva will be used instead" );
  1976.         
  1977.         NoteAlert( rPrefsErrorAlert, HsoiGetMyStandardDialogFilter() );
  1978.         
  1979.         HsoipStringCopy( "\pGeneva", gMyPrefs.defFont );
  1980.     }
  1981.     
  1982.     if ( fRefNum == 0 )
  1983.         return true;
  1984.     
  1985.     FSClose( fRefNum );
  1986.  
  1987.     return true;
  1988.     
  1989. exit:
  1990.     
  1991.     if ( fRefNum != 0 )
  1992.         FSClose( fRefNum );
  1993.         
  1994.     return false;
  1995. }
  1996.  
  1997. // simply enough, write the prefs to the file
  1998.  
  1999. void    HsoiWritePrefs( void )
  2000. {
  2001.     OSErr        err;
  2002.     short        fRefNum = 0, resRefNum = 0;
  2003.     long        count;
  2004.     Str255        numString;
  2005.     Handle        strHandle;
  2006.     short        strID;
  2007.     ResType        strType;
  2008.     Str255        strName;
  2009.     Boolean        newPrefs = false;
  2010.     
  2011.     // open the prefs file
  2012.     
  2013.     err = FSpOpenDF( &gPrefsFileSpec, fsRdWrPerm, &fRefNum );
  2014.     
  2015.     // if it doesn't exist, create it
  2016.     
  2017.     if (err == fnfErr)
  2018.     {
  2019.         FSpCreateResFile(&gPrefsFileSpec, PREF_CREATOR_TYPE, TYPE_PREFERENCES, smSystemScript );
  2020.         err = ResError();
  2021.         if ( err != noErr )
  2022.             goto exit;
  2023.         else
  2024.         {
  2025.             // created it, open it
  2026.             
  2027.             err = FSpOpenDF( &gPrefsFileSpec, fsRdWrPerm, &fRefNum );
  2028.             newPrefs = true;
  2029.         }
  2030.     }
  2031.     if (err != noErr)
  2032.         goto exit;
  2033.  
  2034.     // write the prefs settings in one big block to the file
  2035.     
  2036.     count = sizeof( HASPreferences );
  2037.     err = FSWrite(fRefNum, &count, &gMyPrefs);
  2038.     if (err != noErr)
  2039.         goto exit;
  2040.     
  2041.         
  2042.     FSClose(fRefNum);
  2043.     
  2044.     if ( newPrefs )
  2045.     {
  2046.         // now add the message string resource to the file (if they click on the prefs file,
  2047.         // it'll give them this message instead of something generic and/or launching your app
  2048.         
  2049.         resRefNum = FSpOpenResFile( &gPrefsFileSpec, fsRdWrPerm );
  2050.         err = ResError();
  2051.         if ( err != noErr )
  2052.             goto exit;
  2053.         
  2054.         // the following is pretty much taken directly from IM: Toolbox Essentials, 7-29 and is
  2055.         // similar to what i use in HsoiWriteTextFile() to add the name string resource
  2056.         
  2057.         
  2058.         UseResFile( gAppResourceFork );
  2059.         
  2060.         strHandle = GetResource( 'STR ', strMessageString );
  2061.         
  2062.         if ( strHandle != nil )
  2063.         {
  2064.             GetResInfo( strHandle, &strID, &strType, strName );
  2065.             DetachResource( strHandle );
  2066.             
  2067.             UseResFile( resRefNum );
  2068.             AddResource( strHandle, strType, -16397, strName );
  2069.             
  2070.             if ( ResError() == noErr )
  2071.                 WriteResource( strHandle );
  2072.         }
  2073.         
  2074.         CloseResFile( resRefNum );
  2075.     }
  2076.         
  2077.     FlushVol( nil, gPrefsFileSpec.vRefNum);
  2078.     return;
  2079.     
  2080. exit:
  2081.  
  2082.     // we should only get here if there was an error...
  2083.     
  2084.     if (fRefNum != 0)
  2085.         FSClose(fRefNum);
  2086.     if ( resRefNum != 0 )
  2087.         CloseResFile( resRefNum );
  2088.     FlushVol(nil, gPrefsFileSpec.vRefNum);
  2089.     NumToString( err, numString );
  2090.     ParamText( "\pAn error occured while attempting to write to the preferences file",
  2091.                 NIL_STRING, "\pError =", numString );
  2092.     StopAlert( rPrefsErrorAlert, HsoiGetMyStandardDialogFilter() );
  2093.     
  2094.     return;
  2095. }
  2096.  
  2097. #pragma mark -
  2098. #pragma mark ••• Registration •••
  2099.  
  2100. // does our registration dialog
  2101.  
  2102. void    HsoiDoRegistration( void )
  2103. {
  2104.     DialogRef        regDialog;
  2105.     short            itemHit;
  2106.     Handle            editTextH;
  2107.     Str255            tempStr;
  2108.     StringHandle    appName;
  2109.     
  2110.     // get the dialog
  2111.     
  2112.     regDialog = GetNewDialog( rRegistrationDialog, nil, MOVE_TO_FRONT );
  2113.     
  2114.     if ( regDialog == nil )
  2115.     {
  2116.         // if it messed up, just make the user and org names the "defaults"
  2117.         
  2118.         HsoipStringCopy( DEFAULT_USERNAME, gMyPrefs.userName );
  2119.         HsoipStringCopy( DEFAULT_ORGANIZATION, gMyPrefs.userOrg );
  2120.  
  2121.         return;
  2122.     }
  2123.     
  2124.     // set the tracking
  2125.     
  2126.     SetDialogDefaultItem( regDialog, ok );
  2127.     SetDialogCancelItem( regDialog, cancel );
  2128.     SetDialogTracksCursor( regDialog, true );
  2129.     
  2130.     // get the app name
  2131.     
  2132.     appName = GetString( strAppNameString );
  2133.     DetachResource( (Handle)appName );
  2134.     ParamText( *appName, NIL_STRING, NIL_STRING, NIL_STRING );
  2135.     
  2136.     // set the user name field to some default setting
  2137.     
  2138.     editTextH = HsoiGetDialogItemHandle( regDialog, iRegDialogUserName );
  2139.     HLock( editTextH );
  2140.     SetDialogItemText( editTextH, DEFAULT_USERNAME );
  2141.     HUnlock( editTextH );
  2142.     
  2143.     // set the org field to the default
  2144.     
  2145.     editTextH = HsoiGetDialogItemHandle( regDialog, iRegDialogOrgName );
  2146.     HLock( editTextH );
  2147.     SetDialogItemText( editTextH, DEFAULT_ORGANIZATION );
  2148.     HUnlock( editTextH );
  2149.     
  2150.     // select the text to look nice
  2151.     
  2152.     SelectDialogItemText( (DialogRef)regDialog, iRegDialogUserName, 0, MAXSHORT );
  2153.     
  2154.     // show the window
  2155.     
  2156.     ShowWindow( GetDialogWindow(regDialog) );
  2157.     
  2158.     // do modal dialog
  2159.     
  2160.     do
  2161.     {
  2162.         ModalDialog( HsoiGetMyStandardDialogFilter(), &itemHit );
  2163.     } while ( (itemHit != ok) && (itemHit != cancel) );
  2164.     
  2165.     // if they hit ok...
  2166.     
  2167.     if ( itemHit == ok )
  2168.     {
  2169.         // get the text.
  2170.         
  2171.         // when getting the text, just in case the entered nothing, we'll copy in
  2172.         // some defaults just so there's something there.
  2173.         
  2174.         // do the user
  2175.         
  2176.         editTextH = HsoiGetDialogItemHandle( regDialog, iRegDialogUserName );
  2177.         GetDialogItemText( editTextH, tempStr );
  2178.         if ( tempStr[0] == 0 ) // they entered nothing
  2179.             HsoipStringCopy( DEFAULT_USERNAME, gMyPrefs.userName );
  2180.         else
  2181.             HsoipStringCopy( tempStr, gMyPrefs.userName );
  2182.         
  2183.         // do the org
  2184.         
  2185.         editTextH = HsoiGetDialogItemHandle( regDialog, iRegDialogOrgName );
  2186.         GetDialogItemText( editTextH, tempStr );
  2187.         if ( tempStr[0] == 0 )
  2188.             HsoipStringCopy( DEFAULT_ORGANIZATION, gMyPrefs.userOrg );
  2189.         else
  2190.             HsoipStringCopy( tempStr, gMyPrefs.userOrg );
  2191.     }
  2192.     
  2193.     // if they canceled, copy the default settings in...again, so something is there
  2194.     
  2195.     if (itemHit == cancel )
  2196.     {
  2197.         HsoipStringCopy( DEFAULT_USERNAME, gMyPrefs.userName );
  2198.         HsoipStringCopy( DEFAULT_ORGANIZATION, gMyPrefs.userOrg );
  2199.     }
  2200.  
  2201.     // dump the dialog
  2202.         
  2203.     DisposeDialog( regDialog );
  2204.  
  2205.     return;
  2206. }