home *** CD-ROM | disk | FTP | other *** search
/ CLIX - Fazer Clix Custa Nix / CLIX-CD.cdr / mac / lib / Mac / Dialogs.pm < prev    next >
Text File  |  1998-04-13  |  19KB  |  855 lines

  1. =head1 NAME
  2.  
  3. Mac::Dialogs - Macintosh Toolbox Interface to Dialog Manager
  4.  
  5. =head1 SYNOPSIS
  6.  
  7.  
  8. =head1 DESCRIPTION
  9.  
  10. Access to Inside Macintosh is essential for proper use of these functions.
  11. Explanations of terms, processes and procedures are provided there.
  12. Any attempt to use these functions without guidance can cause severe errors in 
  13. your machine, including corruption of data. B<You have been warned.>
  14.  
  15. =cut
  16.  
  17. use strict;
  18.  
  19. package Mac::Dialogs;
  20.  
  21. BEGIN {
  22.     use Exporter   ();
  23.     use DynaLoader ();
  24.     use Carp;
  25.     use Mac::Events;
  26.     use Mac::Events qw(DispatchEvent $CurrentEvent @SavedEvents @Event);
  27.     use Mac::Windows;
  28.     use Mac::Controls qw(HiliteControl GetControlValue SetControlValue);
  29.     
  30.     use vars qw(@ISA @EXPORT @EXPORT_OK %Dialog %DialogUserItem);
  31.     
  32.     @ISA = qw(Exporter DynaLoader);
  33.     @EXPORT = qw(
  34.         NewDialog
  35.         GetNewDialog
  36.         DisposeDialog
  37.         ParamText
  38.         ModalDialog
  39.         IsDialogEvent
  40.         DialogSelect
  41.         DrawDialog
  42.         UpdateDialog
  43.         Alert
  44.         StopAlert
  45.         NoteAlert
  46.         CautionAlert
  47.         GetDialogItem
  48.         GetDialogItemControl
  49.         SetDialogItem
  50.         SetDialogItemProc
  51.         HideDialogItem
  52.         ShowDialogItem
  53.         SelectDialogItemText
  54.         GetDialogItemText
  55.         SetDialogItemText
  56.         FindDialogItem
  57.         NewColorDialog
  58.         GetAlertStage
  59.         ResetAlertStage
  60.         DialogCut
  61.         DialogPaste
  62.         DialogCopy
  63.         DialogDelete
  64.         SetDialogFont
  65.         AppendDITL
  66.         CountDITL
  67.         ShortenDITL
  68.         StdFilterProc
  69.         SetDialogDefaultItem
  70.         SetDialogCancelItem
  71.         SetDialogTracksCursor
  72.     
  73.         kControlDialogItem
  74.         kButtonDialogItem
  75.         kCheckBoxDialogItem
  76.         kRadioButtonDialogItem
  77.         kResourceControlDialogItem
  78.         kStaticTextDialogItem
  79.         kEditTextDialogItem
  80.         kIconDialogItem
  81.         kPictureDialogItem
  82.         kUserDialogItem
  83.         kItemDisableBit
  84.         kStdOkItemIndex
  85.         kStdCancelItemIndex
  86.         kStopIcon
  87.         kNoteIcon
  88.         kCautionIcon
  89.         kOkItemIndex
  90.         kCancelItemIndex
  91.         overlayDITL
  92.         appendDITLRight
  93.         appendDITLBottom
  94.     );
  95.     
  96.     @EXPORT_OK = qw(
  97.         %Dialog
  98.         %DialogUserItem
  99.     );
  100. }
  101.  
  102. =head2 Constants
  103.  
  104. =item kControlDialogItem
  105.  
  106. =item kButtonDialogItem
  107.  
  108. =item kCheckBoxDialogItem
  109.  
  110. =item kRadioButtonDialogItem
  111.  
  112. =item kResourceControlDialogItem
  113.  
  114. =item kStaticTextDialogItem
  115.  
  116. =item kEditTextDialogItem
  117.  
  118. =item kIconDialogItem
  119.  
  120. =item kPictureDialogItem
  121.  
  122. =item kUserDialogItem
  123.  
  124. =item kItemDisableBit
  125.  
  126. Dialog item types.
  127.  
  128. =cut
  129. sub kControlDialogItem ()          {          4; }
  130. sub kButtonDialogItem ()           {          4; }
  131. sub kCheckBoxDialogItem ()         {          5; }
  132. sub kRadioButtonDialogItem ()      {          6; }
  133. sub kResourceControlDialogItem ()  {          7; }
  134. sub kStaticTextDialogItem ()       {          8; }
  135. sub kEditTextDialogItem ()         {         16; }
  136. sub kIconDialogItem ()             {         32; }
  137. sub kPictureDialogItem ()          {         64; }
  138. sub kUserDialogItem ()             {          0; }
  139. sub kItemDisableBit ()             {        128; }
  140.  
  141.  
  142. =item kStopIcon
  143.  
  144. =item kNoteIcon
  145.  
  146. =item kCautionIcon
  147.  
  148. Standard icons.
  149.  
  150. =cut
  151. sub kStopIcon ()                   {          0; }
  152. sub kNoteIcon ()                   {          1; }
  153. sub kCautionIcon ()                {          2; }
  154.  
  155.  
  156. =item kStdOkItemIndex
  157.  
  158. =item kStdCancelItemIndex
  159.  
  160. Standard button numbers.
  161.  
  162. =cut
  163. sub kStdOkItemIndex ()             {          1; }
  164. sub kStdCancelItemIndex ()         {          2; }
  165.  
  166.  
  167. =item overlayDITL
  168.  
  169. =item appendDITLRight
  170.  
  171. =item appendDITLBottom
  172.  
  173. Options for C<AppendDITL>.
  174.  
  175. =cut
  176. sub overlayDITL ()                 {          0; }
  177. sub appendDITLRight ()             {          1; }
  178. sub appendDITLBottom ()            {          2; }
  179.  
  180. =back
  181.  
  182. =cut
  183. #
  184. # _ModalFilter - call a modal filter procedure
  185. #
  186. sub _ModalFilter {
  187.     no strict qw(refs);
  188.     
  189.     my($proc, $dialog, $event) = @_;
  190.     push @SavedEvents, $CurrentEvent;
  191.     $CurrentEvent = $event;
  192.     my($res) = &$proc($dialog, $event);
  193.     $CurrentEvent = pop @SavedEvents;
  194.     $res;
  195. }
  196.  
  197. #
  198. # _DefaultModalFilter - simply do the right thing; handle nonlocal updates, drags,
  199. # zooms, grows & the like.
  200. #
  201. sub _DefaultModalFilter {
  202.     my($dialog, $ev) = @_;
  203.     if ($ev->what == updateEvt && ${$ev->window} != $$dialog) {
  204.         DispatchEvent $ev;
  205.         $ev->what(nullEvent);
  206.         
  207.         return 0;
  208.     } elsif ($ev->what == mouseDown) {
  209.         my($code,$win) = FindWindow($ev->where);
  210.         if ($win && $$win == $$dialog && $code != inContent) {
  211.             DispatchEvent $ev;
  212.             $ev->what(nullEvent);
  213.             
  214.             return 0;
  215.         }
  216.     } 
  217.     StdFilterProc($dialog, $ev);
  218. }
  219.  
  220. #
  221. # _UserItem - draw an user item
  222. #
  223. sub _UserItem {
  224.     my($dialog, $item) = @_;
  225.     my($proc) = $DialogUserItem{$$dialog}->[$item-1];
  226.     
  227.     $proc and &$proc($dialog, $item);
  228. }
  229.  
  230. bootstrap Mac::Dialogs;
  231.  
  232. =include Dialogs.xs
  233.  
  234. =cut
  235. #
  236. # The dialog creation procedures can take a WDEF written in Perl, but to
  237. # concentrate that code in one place, we'll redirect that option to
  238. # Mac::Windows.
  239. #
  240. sub NewDialog {
  241.     my($bounds, $visible, $title, $proc) = @_;
  242.     if (!ref($proc) && (!$proc || $proc != 0)) {
  243.         _NewDialog(@_); # Numeric WDEF
  244.     } else {
  245.         my $dlg = _NewDialog($bounds, 0, $title, zoomDocProc, @_[4..$#_]);
  246.         $dlg->windowDefProc($proc);
  247.         ShowWindow($dlg) if ($visible);
  248.         $dlg;
  249.     }
  250. }
  251.  
  252. sub NewColorDialog {
  253.     my($bounds, $visible, $title, $proc) = @_;
  254.     if (!ref($proc) && (!$proc || $proc != 0)) {
  255.         _NewColorDialog(@_);    # Numeric WDEF
  256.     } else {
  257.         my $dlg = _NewColorDialog($bounds, 0, $title, zoomDocProc, @_[4..$#_]);
  258.         $dlg->windowDefProc($proc);
  259.         ShowWindow($dlg) if ($visible);
  260.         $dlg;
  261.     }
  262. }
  263.  
  264. =item TEXT = GetDialogItemText DIALOG, ITEM
  265.  
  266. =item TEXT = GetDialogItemText ITEMHANDLE
  267.  
  268. Returns the text of a dialog item.
  269.  
  270. =cut
  271. sub GetDialogItemText {
  272.     my($variant) = @_;
  273.     my($itemhandle,$dialog,$item);
  274.     if (ref($variant) eq "GrafPtr") {
  275.         ($dialog,$item) = @_;
  276.         $itemhandle = (GetDialogItem($dialog, $item))[1];
  277.     } else {
  278.         $itemhandle = @_;
  279.     }
  280.     _GetDialogItemText($itemhandle);
  281. }
  282.  
  283. =item SetDialogItemText DIALOG, ITEM, TEXT
  284.  
  285. =item SetDialogItemText ITEMHANDLE, TEXT
  286.  
  287. Sets the text of a dialog item.
  288.  
  289. =cut
  290. sub SetDialogItemText {
  291.     my($variant) = @_;
  292.     my($itemhandle,$dialog,$item,$text);
  293.     if (ref($variant) eq "GrafPtr") {
  294.         ($dialog,$item,$text) = @_;
  295.         $itemhandle = (GetDialogItem($dialog, $item))[1];
  296.     } else {
  297.         ($itemhandle, $text) = @_;
  298.     }
  299.     _SetDialogItemText($itemhandle, $text);
  300. }
  301.  
  302. =item SetDialogItemProc DIALOG, ITEM, PROC
  303.  
  304. Set up a drawing procedure for a dialog item.
  305.  
  306. =cut
  307. sub SetDialogItemProc {
  308.     my($dialog, $item, $proc) = @_;
  309.     $DialogUserItem{$$dialog}->[$item-1] = $proc;
  310.     _SetDialogItemProc($dialog, $item);
  311. }
  312.  
  313. =item PROC = GetDialogItemProc DIALOG, ITEM
  314.  
  315. Returns the drawing procedure for a dialog item.
  316.  
  317. =cut
  318. sub GetDialogItemProc {
  319.     my($dialog, $item) = @_;
  320.     $DialogUserItem{$$dialog}->[$item-1];
  321. }
  322.  
  323. =item DisposeDialog DIALOG
  324.  
  325. Delete the dialog.
  326.  
  327. =cut
  328. sub DisposeDialog {
  329.     my($dialog) = @_;
  330.     delete $DialogUserItem{$$dialog};
  331.     _DisposeDialog($dialog);
  332. }
  333.  
  334. =back
  335.  
  336. =head2 MacDialog - The Object Interface
  337.  
  338. Correctly handling a Mac dialog requires quite a bit of event management. The
  339. C<MacDialog> class relieves you of most of these duties.
  340.  
  341. =over 4
  342.  
  343. =cut
  344. package MacDialog;
  345.  
  346. BEGIN {
  347.     use Mac::Windows qw(%Window);
  348.     import Mac::Dialogs;
  349.     import Mac::Dialogs qw(%Dialog %DialogUserItem);
  350.     use Mac::Events qw($CurrentEvent);
  351.     use Mac::Controls qw(HiliteControl GetControlValue SetControlValue);
  352.     use Carp;
  353.     
  354.     use vars qw(@ISA);
  355.     
  356.     @ISA = qw(MacWindow);
  357. }
  358.  
  359. =item new MacDialog PORT
  360.  
  361. =item new MacDialog ID [, BEHIND]
  362.  
  363. =item new MacDialog BOUNDS, TITLE, VISIBLE, PROC, GOAWAY, ITEMS, [, REFCON [, BEHIND]]
  364.  
  365. =item new MacDialog BOUNDS, TITLE, VISIBLE, PROC, GOAWAY, ITEMLIST, [, REFCON [, BEHIND]]
  366.  
  367. Register a new dialog. In the first form, registers an existing dialog. In the
  368. second form, calls C<GetNewDialog>. In the third form, calls C<NewDialog>. In
  369. the fourth form, takes items as a dialogitemlist.
  370.  
  371. =cut
  372. sub new {
  373.     my($class) = shift @_;
  374.     my($type) = @_;
  375.     my($port);
  376.     
  377.     if (ref($type) eq "Rect") {
  378.         if (ref($_[5]) eq "ARRAY") { # Item list
  379.             my @items = splice(@_, 5);
  380.             my @rest;
  381.             while (ref($items[$#items]) ne "ARRAY") {
  382.                 unshift @rest, shift(@items);
  383.             }
  384.             push @_, (new MacDialogItems @items)->get, @rest;
  385.         }
  386.         $port = NewDialog(@_) or croak "NewDialog failed";
  387.     } elsif (!ref($type)) {
  388.         $port = GetNewDialog(@_) or croak "GetNewDialog failed";
  389.     } else {
  390.         $port = $type;
  391.     }
  392.     my($my) = MacWindow::new($class, $port);
  393.     $Dialog{$$port} = $my;
  394. }
  395.  
  396. =item dispose 
  397.  
  398. Unregisters and disposes the dialog.
  399.  
  400. =cut
  401. sub dispose {
  402.     my($my) = @_;
  403.     return unless $my->{port};
  404.     defined($_[0]->callhook("dispose", @_)) and return;
  405.     delete $Window{${$my->{port}}};
  406.     delete $Dialog{${$my->{port}}};
  407.     DisposeDialog($my->{port});
  408.     $my->{port} = "";
  409. }
  410.  
  411. sub _dialogselect {
  412.     my($my) = @_;
  413.     my($event) = $CurrentEvent;
  414.     
  415.     $event && IsDialogEvent($event) or return 0;
  416.     
  417.     my($itemhit) = StdFilterProc($my->{port}, $event);
  418.     unless ($itemhit) {
  419.         my($dialog);
  420.         ($dialog, $itemhit) = DialogSelect($event);
  421.     
  422.         croak("Weirdness in DialogSelect") 
  423.             if $itemhit && $$dialog != ${$my->{port}};
  424.     }
  425.     
  426.     $my->hit($itemhit) if $itemhit;
  427.     
  428.     1;
  429. }
  430.  
  431. =item activate ACTIVE, SUSPEND
  432.  
  433. Handle activation of the window, which is already set to the current port.
  434. By default doesn't do anything. Override as necessary.
  435.  
  436. The parameters distinguish the four cases:
  437.  
  438.    Event      ACTIVE  SUSPEND
  439.    
  440.    Activate      1       0
  441.    Deactivate    0       0
  442.    Suspend       0       1
  443.    Resume        1       1
  444.  
  445. =cut
  446. sub activate {
  447.     defined($_[0]->callhook("activate", @_)) and return;
  448.     _dialogselect(@_);
  449. }
  450.  
  451. =item update 
  452.  
  453. Handle update events. 
  454.  
  455. =cut
  456. sub update {
  457.     defined($_[0]->callhook("update", @_)) and return;
  458.     _dialogselect(@_);
  459. }
  460.  
  461. =item key KEY
  462.  
  463. Handle a keypress and return 1 if the key was handled.
  464.  
  465. =cut
  466. sub key {
  467.     my($handled);
  468.     defined($handled = $_[0]->callhook("key", @_)) and return $handled;
  469.     _dialogselect(@_);
  470. }
  471.  
  472. =item click PT
  473.  
  474. Handle a mouse click and return 1 if the click was handled.
  475.  
  476. =cut
  477. sub click {
  478.     my($handled);
  479.     defined($handled = $_[0]->callhook("click", @_)) and return 1;
  480.     _dialogselect(@_);
  481. }
  482.  
  483. =item modal [FILTER]
  484.  
  485. Run dialog modally.
  486.  
  487. =cut
  488. sub modal {
  489.     $_[0]->callhook("modal", @_) and return;
  490.     
  491.     my($my) = shift @_;
  492.     my($itemhit) = ModalDialog(@_);
  493.     
  494.     $my->hit($itemhit) if $itemhit;
  495. }
  496.  
  497. =item hit ITEM
  498.  
  499. Handle a "hit" of an enabled item. Usually dispatches to hook.
  500.  
  501. =cut
  502. sub hit {
  503.     $_[0]->callhook("hit", @_) and return;
  504.     
  505.     my($my, $itemhit) = @_;
  506.     my($proc) = $my->{items}->[$itemhit-1];
  507.     
  508.     &$proc($my, $itemhit) if $proc;
  509. }
  510.  
  511. =item idle 
  512.  
  513. Handle idle (null) events. 
  514.  
  515. =cut
  516. sub idle {
  517.     #
  518.     # MacPerl 5.1.9r4 and earlier failed to propagate null events, so
  519.     # we'll make mouse moved events honorary null events (luckily these
  520.     # versions also generated too many mouse moved events :-)
  521.     #
  522.     my($savedwhat) = $CurrentEvent->what;
  523.     $CurrentEvent->what(0);
  524.     &_dialogselect;
  525.     $CurrentEvent->what($savedwhat);
  526.     &MacWindow::idle;
  527. }
  528.  
  529. =item KIND = item_kind ITEM
  530.  
  531. =item item_kind ITEM, KIND
  532.  
  533. Get/Set item kind.
  534.  
  535. =cut
  536. sub item_kind {
  537.     my($my, $item, $kind) = @_;
  538.     
  539.     my($ikind,$ihandle,$ibox) = GetDialogItem($my->{port}, $item);
  540.     
  541.     defined($kind) ? 
  542.         SetDialogItem($my->{port}, $item, $kind, $ihandle, $ibox) 
  543.       : $ikind;
  544. }
  545.  
  546. =item item_handle ITEM
  547.  
  548. =item item_handle ITEM, HANDLE
  549.  
  550. Get/Set item handle.
  551.  
  552. =cut
  553. sub item_handle {
  554.     my($my, $item, $handle) = @_;
  555.     
  556.     my($ikind,$ihandle,$ibox) = GetDialogItem($my->{port}, $item);
  557.     
  558.     defined($handle) ? 
  559.         SetDialogItem($my->{port}, $item, $ikind, $handle, $ibox) 
  560.       : $ihandle;
  561. }
  562.  
  563. =item item_control ITEM
  564.  
  565. Get item control (You should never have a reason to set it).
  566.  
  567. =cut
  568. sub item_control {
  569.     my($my, $item) = @_;
  570.     
  571.     GetDialogItemControl($my->{port}, $item);
  572. }
  573.  
  574. =item item_box ITEM
  575.  
  576. =item item_box ITEM, BOX
  577.  
  578. Get/Set item boundaries.
  579.  
  580. =cut
  581. sub item_box {
  582.     my($my, $item, $box) = @_;
  583.     
  584.     my($ikind,$ihandle,$ibox) = GetDialogItem($my->{port}, $item);
  585.     
  586.     defined($box) ? 
  587.         SetDialogItem($my->{port}, $item, $ikind, $ihandle, $box) 
  588.       : $ibox;
  589. }
  590.  
  591. =item item_draw ITEM
  592.  
  593. =item item_draw ITEM, PROC
  594.  
  595. Get/Set procedure to draw item.
  596.  
  597. =cut
  598. sub item_draw {
  599.     my($my, $item, $proc) = @_;
  600.     
  601.     defined($proc) ? 
  602.         SetDialogItemProc($my->{port}, $item, $proc) 
  603.       : GetDialogItemProc($my->{port}, $item);
  604. }
  605.  
  606. =item TEXT = item_text ITEM
  607.  
  608. =item item_text ITEM, TEXT
  609.  
  610. Get/Set text of dialog item.
  611.  
  612. =cut
  613. sub item_text {
  614.     my($my, $item, $text) = @_;
  615.     
  616.     defined($text) ? 
  617.         SetDialogItemText($my->{port}, $item, $text) 
  618.       : GetDialogItemText($my->{port}, $item);
  619. }
  620.  
  621. =item item_hit ITEM
  622.  
  623. =item item_hit ITEM, PROC
  624.  
  625. Get/Set handler for item hit.
  626.  
  627. =cut
  628. sub item_hit {
  629.     my($my, $item, $proc) = @_;
  630.     
  631.     defined($proc) ? 
  632.         ($my->{items}->[$item-1] = $proc)
  633.       : $my->{items}->[$item-1];
  634. }
  635.  
  636. =item item_hilite ITEM, HILITE
  637.  
  638. Set item hilite value.
  639.  
  640. =cut
  641. sub item_hilite {
  642.     my($my, $item, $value) = @_;
  643.     
  644.     HiliteControl($my->item_control($item), $value);
  645. }
  646.  
  647. =item item_value ITEM
  648.  
  649. =item item_value ITEM, PROC
  650.  
  651. Get/Set control value for item.
  652.  
  653. =cut
  654. sub item_value {
  655.     my($my, $item, $value) = @_;
  656.     
  657.     defined($value) ? 
  658.         SetControlValue($my->item_control($item), $value) :
  659.         GetControlValue($my->item_control($item));
  660. }
  661.  
  662. =back
  663.  
  664. =head2 MacColorDialog - The Object Interface
  665.  
  666. A C<MacColorDialog> is a colorful version of a C<MacDialog>.
  667.  
  668. =over 4
  669.  
  670. =cut
  671. package MacColorDialog;
  672.  
  673. BEGIN {
  674.     import Mac::Dialogs;
  675.     use Carp;
  676. }
  677.  
  678. =item new MacColorDialog PORT
  679.  
  680. =item new MacColorDialog ID [, BEHIND]
  681.  
  682. =item new MacColorDialog BOUNDS, TITLE, VISIBLE, PROC, GOAWAY, ITEMS, [, REFCON [, BEHIND]]
  683.  
  684. =item new MacColorDialog BOUNDS, TITLE, VISIBLE, PROC, GOAWAY, ITEMLIST, [, REFCON [, BEHIND]]
  685.  
  686. Register a new color dialog. The first two forms are just forwarded to MacDialog,
  687. the third and fourth forms create actual color dialogs.
  688.  
  689. =cut
  690. sub new {
  691.     my($class) = shift @_;
  692.     my($type) = @_;
  693.     my($port);
  694.     
  695.     if (ref($type) eq "Rect") {
  696.         if (ref($_[5]) eq "ARRAY") { # Item list
  697.             my @items = splice(@_, 5);
  698.             my @rest;
  699.             while (ref($items[$#items]) ne "ARRAY") {
  700.                 unshift @rest, shift(@items);
  701.             }
  702.             push @_, (new MacDialogItems @items)->get, @rest;
  703.         }
  704.         $port = NewColorDialog(@_) or croak "NewColorDialog failed";
  705.     } elsif (!ref($type)) {
  706.         $port = GetNewDialog(@_) or croak "GetNewDialog failed";
  707.     } else {
  708.         $port = $type;
  709.     }
  710.     new MacDialog $port;
  711. }
  712.  
  713. =back
  714.  
  715. =head2 MacDialogItems - Handle a dialog item list
  716.  
  717. The C<MacDialogItems> class is a wrapper for dialog item lists.
  718.  
  719. =over 4
  720.  
  721. =cut
  722. package MacDialogItems;
  723.  
  724. BEGIN {
  725.     use Mac::Memory ();
  726.     import Mac::Dialogs;
  727. }
  728.  
  729. =item new MacDialogItems
  730.  
  731. =item new MacDialogItems HANDLE
  732.  
  733. =item new MacDialogItems ITEMLIST
  734.  
  735. Construct a dialog item list; either an empty one, one derived from an existing
  736. item list, or one constructed from a list of array references.
  737.  
  738. =cut
  739. sub new {
  740.     my($class) = shift @_;
  741.     my($type) = @_;
  742.     
  743.     my($my) = bless [], $class;
  744.     
  745.     if (ref($type) eq "Handle") {   # Construct from existing item list
  746.         my($data)  = $type->get;
  747.         my($count,$length) = unpack("s", $data);
  748.         $data = substr($data, 2);
  749.         while ($count-- >= 0) {
  750.             ($type,$length) = unpack("CC", substr($data, 12, 2));
  751.             $type &= 127;
  752.             if ($type == kUserDialogItem) {
  753.                 $length = 14;
  754.             } elsif ($type == 1) {  # Help items
  755.                 $length += 14;
  756.             } elsif ($type == kResourceControlDialogItem || $type >= kIconDialogItem) {
  757.                 $length = 16;
  758.             } else {
  759.                 $length += 14 + ($length & 1);
  760.             }
  761.             push @$my, substr($data, 0, $length);
  762.             $data = substr($data, $length);
  763.         }
  764.     } else {
  765.         for (@_) {
  766.             $my->add_item(@$_);
  767.         }
  768.     }
  769.     $my;
  770. }
  771.  
  772. =item add_item TYPE, ...
  773.  
  774. Add another dialog item.
  775.  
  776. =cut 
  777. sub add_item {
  778.     my($my,$type) = splice(@_, 0, 2);
  779.     my($kind) = $type & 127;
  780.     if ($type == kUserDialogItem) {
  781.         my($r) = @_;
  782.         push @$my, pack("x4 a8 C x", $$r, $type);
  783.     } elsif ($type == 1) {  # Help items
  784.         my($htype,$id,$item) = @_;
  785.         if ($htype == 8) {
  786.             push @$my, pack("x4 x8 C C s s s", $type, 6, $htype, $id, $item);
  787.         } else {
  788.             push @$my, pack("x4 x8 C C s s", $type, 4, $htype, $id);
  789.         }
  790.     } elsif ($type == kResourceControlDialogItem || $type >= kIconDialogItem) {
  791.         my($r, $id) = @_;
  792.         push @$my, pack("x4 a8 C x s", $$r, $id);
  793.     } else {
  794.         my($r, $text) = @_;
  795.         my($len) = length($text);
  796.         $len += $len&1;
  797.         push @$my, pack("x4 a8 C C a$len", $$r, $type, length($text), $text);
  798.     }   
  799. }
  800.  
  801. =item (TYPE, ...) = get_item ITEM
  802.  
  803. =cut
  804. sub get_item {
  805.     my($my, $item) = @_;
  806.     return () unless $item = $$my[$item];
  807.     my($type) = unpack("C", substr($item, 12, 1));
  808.     $type &= 127;
  809.     if ($type == kUserDialogItem) {
  810.         my($r,$type) = unpack("x4 a8 C x", $item);
  811.         return ($type, bless($r, "Rect"));
  812.     } elsif ($type == 1) {  # Help items
  813.         my($type,$htype,$id,$item) = unpack("x4 x8 C x s s s", $item);
  814.         if ($htype == 8) {
  815.             return ($type, $htype, $id, $item);
  816.         } else {
  817.             return ($type, $htype, $id);
  818.         }
  819.     } elsif ($type == kResourceControlDialogItem || $type >= kIconDialogItem) {
  820.         my($r, $type, $id) = unpack("x4 a8 C x s", $item);
  821.         return ($type, bless($r, "Rect"), $id);
  822.     } else {
  823.         my($r, $type, $len) = unpack("x4 a8 C C", $item);
  824.         my($text) = substr($item, 14, $len);
  825.         return ($type, bless($r, "Rect"), $text);
  826.     }   
  827. }
  828.  
  829. =item HANDLE = get
  830.  
  831. Get dialog item list handle.
  832.  
  833. =cut
  834. sub get {
  835.     my($my) = @_;
  836.     
  837.     new Handle(pack("s", scalar(@$my)-1) . join("", @$my));
  838. }
  839.  
  840. =back
  841.  
  842. =head1 BUGS/LIMITATIONS
  843.  
  844. =head1 FILES
  845.  
  846. =head1 AUTHOR(S)
  847.  
  848. Matthias Ulrich Neeracher <neeri@iis.ee.ethz.ch> 
  849.  
  850. =cut
  851.  
  852. 1;
  853.  
  854. __END__
  855.