home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MyCleverAlerts.p < prev    next >
Encoding:
Text File  |  1997-04-09  |  12.4 KB  |  531 lines  |  [TEXT/CWIE]

  1. unit MyCleverAlerts;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types;
  7.     
  8.     procedure StartupCleverAlerts;
  9.     procedure ConfigureCleverAlerts(icon_id: integer; icon_ndx: integer);
  10.  
  11.     procedure CleverParamText(const param0,param1,param2,param3:Str255);
  12.     function CleverAlert(id:integer):integer;
  13.     procedure CleverNotifyAlert(id:integer);
  14.     
  15.     procedure CleverAlertTest;
  16.     
  17. { text format: 
  18. [SCN][B-][MSW](:button)...
  19. text of message
  20.  
  21. where S=Stop, C=Caution, N=Note; B=beep,-=dont; M=Main Screen,S=Parent Screen, W=Parent Window
  22. }
  23.  
  24. implementation
  25.  
  26.     uses
  27.         Resources, TextEdit, Fonts, LowMem, Memory, Quickdraw, QuickdrawText, 
  28.         Dialogs, Events, Windows, Controls, MixedMode, 
  29.         MyAssertions, MyStrH, MyDialogs,MyWindows, MyTypes, MyStrings, MyCursors, MyUtils, 
  30.         MyMemory, MyEvents, 
  31.         MyHandles, MyNotifier, MyMathUtils, MySystemGlobals, MyStartup, MyMovableModal;
  32.     
  33.     type
  34.         DelayedAlertRecord=record
  35.             id:integer;
  36.             params:StrHHandle;
  37.         end;    
  38.         
  39. {$ifc do_debug}
  40.     var
  41.         startup_check: integer;
  42. {$endc}
  43.  
  44.     var
  45.         param_text:StrHHandle;
  46.         delayed:HandleArray;
  47.         alert_icon_id, alert_icon_ndx:integer;
  48.         
  49.     const
  50.         alert_width = 432;
  51.         alert_icon_left = 20;
  52.         alert_icon_top = 10;
  53.         alert_text_left = 74;
  54.         alert_text_right = alert_width-10;
  55.         alert_text_top = 7;
  56.         alert_text_bottom = 40;
  57.         alert_text_minimum_height = 32;
  58.         alert_button_top = 30;
  59.         alert_button_height = 20;
  60.         alert_button_min_width = 58;
  61.         alert_button_first_separation = 14;
  62.         alert_button_separation = 10;
  63.         alert_button_left = alert_text_left;
  64.         alert_button_right = alert_text_right;
  65.         alert_button_extra_width = 22;
  66.         
  67.     const { If you reorder these, change NewDITL! }
  68.         o_useritem=1;
  69.         o_icon=2;
  70.         o_text=3;
  71.     
  72.     const
  73.         no_command_key = spc;
  74.         
  75.     procedure CleverParamText(const param0,param1,param2,param3:Str255);
  76.         var
  77.             junk: OSErr;
  78.     begin
  79.         AssertDidStartup( startup_check );
  80.         if param_text=nil then begin
  81.             param_text:=NewStrH;
  82.         end;
  83.         if param_text<>nil then begin
  84.             junk := SetIndStrH(param_text,1,param0);
  85.             junk := SetIndStrH(param_text,2,param1);
  86.             junk := SetIndStrH(param_text,3,param2);
  87.             junk := SetIndStrH(param_text,4,param3);
  88.         end;
  89.     end;
  90.     
  91.     procedure InsertParamateres(te:TEHandle; pt:StrHHandle);
  92.         var
  93.             s:Str255;
  94.             n:longint;
  95.     begin
  96.         n:=0;
  97.         while n<te^^.teLength-1 do begin
  98.             if (CharsHandle(te^^.hText)^^[n]='^') & (CharsHandle(te^^.hText)^^[n+1] in ['0'..'3']) then begin
  99.                 if pt=nil then begin
  100.                     s:='';
  101.                 end else begin
  102.                     s:=GetIndStrH(pt,ord(CharsHandle(te^^.hText)^^[n+1])-48+1);
  103.                 end;
  104.                 TESetSelect(n,n+2,te);
  105.                 TEDelete(te);
  106.                 TEInsert(@s[1],length(s),te);
  107.                 n:=n+length(s);
  108.             end else begin
  109.                 n:=n+1;
  110.             end;
  111.         end;
  112.     end;
  113.     
  114.     procedure GetFirstLine(data:Handle; var s:Str255);
  115.         var
  116.             n:integer;
  117.             found:boolean;
  118.     begin
  119.         s:='';
  120.         n:=0;
  121.         found:=false;
  122.         while (n<GetHandleSize(data)) & (n<255) & not found do begin
  123.             found:=(CharsHandle(data)^^[n]=cr);
  124.             if not found then begin
  125.                 n:=n+1;
  126.             end;
  127.         end;
  128.         if found then begin
  129.             BlockMoveData(data^,@s[1],n);
  130.             s[0]:=chr(n);
  131.         end;
  132.     end;
  133.     
  134.     procedure RemoveFirstLine(te:TEHandle);
  135.         var
  136.             s:Str255;
  137.     begin
  138.         GetFirstLine(te^^.hText,s);
  139.         TESetSelect(0,length(s)+1,te);
  140.         TEDelete(te);
  141.     end;
  142.     
  143.     function NewDITL(theline:Str255; var icon,buttons:integer; var cmdkeys:Str15):Handle;
  144.         var
  145.             list:Handle;
  146.         procedure AppendWord(n:integer);
  147.             var
  148.                 junk:OSErr;
  149.         begin
  150.             junk:=PtrAndHand(@n,list,SizeOf(n));
  151.         end;
  152.         procedure AppendByte(n:integer);
  153.             var
  154.                 junk:OSErr;
  155.         begin
  156.             n:=BAND(n,$00FF);
  157.             n:=BOR(BSL(n,8),n);
  158.             junk:=PtrAndHand(@n,list,1);
  159.         end;
  160.         procedure AppendLong(n:longint);
  161.             var
  162.                 junk:OSErr;
  163.         begin
  164.             junk:=PtrAndHand(@n,list,SizeOf(n));
  165.         end;
  166.         procedure AppendItem(top,left,bottom,right,kind,len:integer);
  167.         begin
  168.             AppendLong(0);
  169.             AppendWord(top);
  170.             AppendWord(left);
  171.             AppendWord(bottom);
  172.             AppendWord(right);
  173.             AppendByte(kind);
  174.             AppendByte(len);
  175.         end;
  176.         var
  177.             s:Str255;
  178.             i:integer;
  179.             junk:OSErr;
  180.             left,right:integer;
  181.             onleft:boolean;
  182.             width:integer;
  183.             pos:integer;
  184.             gp: GrafPort;
  185.     begin
  186.         OpenPort(@gp); { Need to set the font and size for StringWidth }
  187.         SetMyFont(MFT_System0);
  188.         cmdkeys:='';
  189.         buttons:=0;
  190.         for i:=1 to length(theline) do begin
  191.             if theline[i]=':' then begin
  192.                 buttons:=buttons+1;
  193.                 cmdkeys:=concat(cmdkeys,no_command_key);
  194.             end;
  195.         end;
  196.         if (buttons>=1) & (cmdkeys[1]=no_command_key) then begin
  197.             cmdkeys[1]:=cr;
  198.         end;
  199.         if (buttons>=2) & (cmdkeys[2]=no_command_key) then begin
  200.             cmdkeys[2]:='.';
  201.         end;
  202.         case theline[1] of
  203.             'S':begin
  204.                 icon:=stopIcon;
  205.             end;
  206.             'C':begin
  207.                 icon:=cautionIcon;
  208.             end;
  209.             'N':begin
  210.                 icon:=noteIcon;
  211.             end;
  212.             otherwise begin
  213.                 Assert(false);
  214.             end;
  215.         end;
  216.         junk := MNewHandle( list, 0 );
  217.         AppendWord(buttons+3-1);
  218.         SplitBy(theline,':',s,theline);
  219.         left:=alert_button_left;
  220.         right:=alert_button_right;
  221.         for i:=1 to buttons do begin
  222.             SplitBy(theline,':',s,theline);
  223.             onleft:=false;
  224.             if s[1]='-' then begin
  225.                 onleft:=true;
  226.                 Delete(s,1,1);
  227.             end;
  228.             if (length(s)>2) & (s[length(s)-1]='/') then begin
  229.                 cmdkeys[i]:=UpCaseChar(s[length(s)]);
  230.                 Delete(s,length(s)-1,2);
  231.             end;
  232.             width:=Max(StringWidth(s)+alert_button_extra_width,alert_button_min_width);
  233.             if onleft then begin
  234.                 pos:=left;
  235.                 left:=left+width+alert_button_separation;
  236.             end else begin
  237.                 pos:=right-width;
  238.                 if i=1 then begin
  239.                     right:=right-width-alert_button_first_separation;
  240.                 end else begin
  241.                     right:=right-width-alert_button_separation;
  242.                 end;
  243.             end;
  244.             AppendItem(0,pos,alert_button_height,pos+width,ctrlItem+btnCtrl,length(s));
  245.             junk:=PtrAndHand(@s[1],list,length(s));
  246.             if odd(length(s)) then begin
  247.                 AppendByte(0);
  248.             end;
  249.         end;
  250.         AppendItem(0,0,0,0,userItem+itemDisable,0);
  251.         AppendItem(alert_icon_top,alert_icon_left,alert_icon_top+32,alert_icon_left+32,iconItem+itemDisable,2);
  252.         AppendWord(icon);
  253.         AppendItem(alert_text_top,alert_text_left,alert_text_top+1000,alert_text_right,userItem+itemDisable,0);
  254.         ClosePort(@gp);
  255.         NewDITL:=list;
  256.     end;
  257.  
  258.     var
  259.         gTE:TEHandle;
  260.  
  261.     procedure DrawOurText(dlg:DialogPtr; item:integer);
  262.         var
  263.             bounds:Rect;
  264.     begin
  265.         GetDItemRect(dlg,item,bounds);
  266.         TEUpdate(bounds,gTE);
  267.     end;
  268.     
  269.     var
  270.         button_command_keys:Str15;
  271.         
  272.     function OurModalFilter (dlg: DialogPtr; var er: EventRecord; var item: integer): boolean;
  273.         var
  274.             ret:boolean;
  275.         procedure DoCommand(ch:Char);
  276.             var
  277.                 i:integer;
  278.                 found:boolean;
  279.         begin
  280.             ch:=UpCaseChar(ch);
  281.             i:=1;
  282.             found:=false;
  283.             while (i<=length(button_command_keys)) & not found do begin
  284.                 if button_command_keys[i]=ch then begin
  285.                     found:=true;
  286.                 end;
  287.                 if not found then begin
  288.                     i:=i+1;
  289.                 end;
  290.                 if found then begin
  291.                     item:=i;
  292.                     FlashDItem(dlg, item);
  293.                     ret:=true;
  294.                 end;
  295.             end;
  296.         end;
  297.     begin
  298.         ret := false;
  299.         if EventIsKeyDown( er ) then begin
  300.             if EventHasOK( er ) then begin
  301.                 DoCommand(cr);
  302.             end else if EventHasCancel( er ) then begin
  303.                 DoCommand('.');
  304.             end else if EventHasCommandKey( er ) then begin
  305.                 DoCommand( EventChar( er ) );
  306.             end;
  307.         end;
  308.         OurModalFilter:=ret;
  309.     end;
  310.  
  311.     function DisplayAlert(id:integer; pt:StrHHandle; may_sound:boolean):integer;
  312.         var
  313.             txt,styl:Handle;
  314.             dlg:DialogPtr;
  315.             bounds:Rect;
  316.             idealsize:Point;
  317.             theline:Str255;
  318.             i,button_count:integer;
  319.             itemlist:Handle;
  320.             icon:integer;
  321.             item:integer;
  322.             DrawOurTextProc:UniversalProcPtr;
  323.             OurModalFilterProc:UniversalProcPtr;
  324.             height:integer;
  325.             filter:UniversalProcPtr;
  326.             wpos:Point;
  327.             wrect:Rect;
  328.             fw:WindowPtr;
  329.             srect:Rect;
  330.             onmain:boolean;
  331.             savedport:GrafPtr;
  332.             movable: boolean;
  333.             proc: integer;
  334.             saved_state: Ptr;
  335.             title: Str255;
  336.     begin
  337.         movable := system7;
  338.         GetPort(savedport);
  339.         DrawOurTextProc:=NewUserItemProc(DrawOurText);
  340.         OurModalFilterProc:=NewModalFilterProc(OurModalFilter);
  341.         txt:=GetResource('TEXT',id);
  342.         Assert(txt<>nil);
  343.         styl:=GetResource('styl',id);
  344.         GetFirstLine(txt,theline);
  345.         SplitBy( theline, tab, theline, title );
  346.         itemlist:=NewDITL(theline,icon,button_count,button_command_keys);
  347.         SetRect(bounds,100,100,102,102); { Must have area or zoom code fails to find best monitor }
  348.         proc := Choose( movable, movableDBoxProc, dBoxProc );
  349.         if has_ColourQuickDraw then begin
  350.             dlg:=NewColorDialog(nil,bounds,title,false,proc,window_at_front,false,0,itemlist);
  351.         end else begin
  352.             dlg:=NewDialog(nil,bounds,title,false,proc,window_at_front,false,0,itemlist);
  353.         end;
  354.         SetPort(dlg);
  355.         SetMyFont(MFT_System0);
  356.         SetRect(bounds,alert_text_left,alert_text_top,alert_text_right,1000);
  357.         gTE:=TEStyleNew(bounds,bounds);
  358.         HLock(txt); 
  359.         if styl = nil then begin
  360.             TEInsert(txt^, GetHandleSize(txt), gTE);
  361.         end else begin
  362.             TEStyleInsert(txt^, GetHandleSize(txt), StScrpHandle(styl), gTE);
  363.             ReleaseResource(styl);
  364.         end;
  365.         ReleaseResource(txt);
  366.         RemoveFirstLine(gTE);
  367.         InsertParamateres(gTE,pt);
  368.         height:=alert_text_top + Max(TEGetHeight(gTE^^.teLength,0,gTE),alert_text_minimum_height) + alert_text_bottom;
  369.         SetPt(wpos,0,LMGetMBarHeight);
  370.         fw:=FrontWindow;
  371.         if fw<>nil then begin
  372.             GetWindowRect(fw,wrect);
  373.             case theline[3] of
  374.                 'M':begin
  375.                     { do nothing }
  376.                 end;
  377.                 'W':begin
  378.                     wpos.h:=wrect.left;
  379.                     wpos.v:=wrect.top;
  380.                 end;
  381.                 'S':begin
  382.                     GetBestScreenRect(wrect,srect,onmain);
  383.                     wpos:=srect.topLeft;
  384.                 end;
  385.                 otherwise begin
  386.                     Assert(false);
  387.                 end;
  388.             end;
  389.         end;
  390.         wpos.h:=wpos.h+40;
  391.         wpos.v:=wpos.v+20 + ord(movable)*20;
  392.         MoveWindow(dlg,wpos.h,wpos.v,true);
  393.         idealsize.h:=432;
  394.         idealsize.v:=height;
  395.         ZoomWindowOut (dlg,0,idealsize);
  396.         SetUserItemProc( dlg, button_count+o_text, DrawOurTextProc );
  397.         for i:=1 to button_count do begin
  398.             GetDItemRect(dlg,i,bounds);
  399.             OffsetRect(bounds,0,height-alert_button_top);
  400.             SetDItemRect(dlg,i,bounds);
  401.             MoveControl(GetDControlHandle(dlg,i),bounds.left,bounds.top);
  402.         end;
  403.         SetUpDefaultOutline(dlg,1,button_count+o_useritem, true);
  404.         if theline[2]='B' then begin
  405.             if may_sound then begin
  406.                 CallSoundProc(1,LMGetDABeeper);
  407.             end;
  408.         end else begin
  409.             Assert(theline[2]='-');
  410.         end;
  411.         ShowWindow(dlg);
  412.         if button_count>1 then begin
  413.             filter:=gCancelModalFilterProc;
  414.         end else begin
  415.             filter:=gStandardModalFilterProc;
  416.         end;
  417.         CursorSetArrow;
  418.         CursorSetProcessing (false);
  419.         if movable then begin
  420.             DisableMenuBar( saved_state, -1 );
  421.         end;
  422.         repeat
  423.             if movable then begin
  424.                 MovableModalDialog( OurModalFilterProc, item );
  425.             end else begin
  426.                 ModalDialog( OurModalFilterProc, item );
  427.             end;
  428.         until (1<=item) & (item<=button_count);
  429.         if movable then begin
  430.             ReEnableMenuBar( saved_state );
  431.         end;
  432.         DisposeDialog(dlg);
  433.         DisplayAlert:=item;
  434.         DisposeRoutineDescriptor(OurModalFilterProc);
  435.         DisposeRoutineDescriptor(DrawOurTextProc);
  436.         SetPort(savedport);
  437.     end;
  438.     
  439.     function CleverAlert(id:integer):integer;
  440.     begin
  441.         AssertDidStartup( startup_check );
  442.         CleverAlert:=DisplayAlert(id,param_text,true);
  443.         MDisposeStrH(param_text);
  444.     end;
  445.     
  446.     procedure CleverNotifyAlert(id:integer);
  447.         var
  448.             dr:DelayedAlertRecord;
  449.             junk:OSErr;
  450.             a:integer;
  451.     begin
  452.         AssertDidStartup( startup_check );
  453.         if InForeground then begin
  454.             a:=CleverAlert(id);
  455.         end else begin
  456.             dr.params:=param_text;
  457.             dr.id:=id;
  458.             junk:=HandleArrayAppend(delayed,@dr);
  459.             param_text:=nil;
  460.             Notify( notify_mark, notify_no_sound, alert_icon_id, alert_icon_ndx, notify_no_string, 1, notify_no_display );
  461.         end;
  462.     end;
  463.  
  464.     procedure IdleCleverAlert;
  465.         var
  466.             dr:DelayedAlertRecord;
  467.             a:integer;
  468.     begin
  469.         if InForeground then begin
  470.             while (HandleArrayCount(delayed)>0) do begin
  471.                 HandleArrayGet(delayed,1,@dr);
  472.                 HandleArrayDelete(delayed,1);
  473.                 a:=DisplayAlert(dr.id,dr.params,false);
  474.                 MDisposeStrH(param_text);
  475.             end;
  476.         end;
  477.     end;
  478.     
  479.     procedure CleverAlertTest;
  480.         var
  481.             i:integer;
  482.             txt:Handle;
  483.             id:integer;
  484.             typ:ResType;
  485.             name:Str255;
  486.             a:integer;
  487.             er:EventRecord;
  488.             dummy:boolean;
  489.     begin
  490.         for i:=1 to Count1Resources('TEXT') do begin
  491.             txt:=Get1IndResource('TEXT',i);
  492.             GetResInfo(txt,id,typ,name);
  493.             ReleaseResource(txt);
  494.             CleverParamText('Param1','Param2','Param3','Param4');
  495.             a:=CleverAlert(id);
  496.             dummy:=OSEventAvail(everyEvent,er);
  497.             if EventHasOptionKey( er ) then begin
  498.                 leave;
  499.             end;
  500.         end;
  501.     end;
  502.     
  503.     function InitCleverAlerts(var msg: integer): OSStatus;
  504.     begin
  505. {$unused(msg)}
  506.         DidStartup( startup_check );
  507.         param_text:=nil;
  508.         InitCleverAlerts := HandleArrayCreate(delayed, SizeOf(DelayedAlertRecord));
  509.     end;
  510.     
  511.     procedure ConfigureCleverAlerts(icon_id: integer; icon_ndx: integer);
  512.     begin
  513.         StartupCleverAlerts;
  514.         alert_icon_id:=icon_id;
  515.         alert_icon_ndx:=icon_ndx;
  516.     end;
  517.     
  518.     procedure FinishCleverAlerts;
  519.     begin
  520.         MDisposeStrH(    param_text)
  521.     end;    
  522.  
  523.     procedure StartupCleverAlerts;
  524.     begin
  525.         StartupDialogs;
  526.         StartupCursors;
  527.         StartupNotifier;
  528.         SetStartup(InitCleverAlerts, IdleCleverAlert, 15, FinishCleverAlerts);
  529.     end;
  530.     
  531. end.