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