File Coverage

blib/lib/Tk/IconCanvas.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Tk::IconCanvas;
2              
3 1     1   2631 use Tk;
  0            
  0            
4             use Tk::Scrollbar;
5             use Tk::Frame;
6              
7             use vars qw ($VERSION $SERIAL_NUMBER @COPYLIST $DRAGDROP $ICON_DEFAULTS);
8             use base qw (Tk::Derived Tk::Frame Tk::Widget);
9             use strict;
10             use Carp;
11              
12             $SERIAL_NUMBER = 0;
13             $VERSION = '0.02';
14             @COPYLIST = ();
15             $DRAGDROP = 0;
16              
17             $ICON_DEFAULTS =
18             {
19             '-font' => '-adobe-times-medium-r-normal--17-*-*-*-*-*-*-*',
20             '-title' => '(Untitled)',
21             '-pixmap' => undef,
22             '-attach' => undef,
23             '-menu' => undef,
24             '-x' => 50,
25             '-y' => 50,
26             };
27              
28             Tk::Widget->Construct ('IconCanvas');
29              
30             sub Populate
31             {
32             my $this = shift;
33              
34             my $l_Frame = $this->Frame();
35              
36             my $l_Canvas = $l_Frame->Scrolled
37             (
38             'Canvas',
39             '-scrollbars' => 'osoe',
40             '-scrollregion' => [0, 0, 300, 200],
41             );
42              
43             $l_Frame->pack
44             (
45             '-fill' => 'both',
46             '-expand' => 'true',
47             );
48              
49             $l_Canvas->pack
50             (
51             '-fill' => 'both',
52             '-expand' => 'true',
53             );
54              
55             $l_Canvas = $this->{m_Canvas} = $l_Canvas->Subwidget ('scrolled');
56              
57             $this->{'m_NormalCursor'} = $this->cget ('-cursor');
58              
59             $this->ConfigSpecs
60             (
61             'DEFAULT' => [$l_Canvas],
62             '-background' => [[$l_Canvas], 'background', 'backGround', 'white'],
63             '-normalcolor' => [['PASSIVE'], 'normalcolor', 'normalColor', 'black'],
64             '-selectcolor' => [['PASSIVE'], 'selectcolor', 'selectColor', 'red'],
65             '-iconspacing' => [['PASSIVE'], 'iconspacing', 'iconSpacing', 20],
66             '-dragallowed' => [['PASSIVE'], 'dragallowed', 'dragAllowed', 1],
67             '-autoadjust' => [['METHOD'], 'autoadjust', 'autoAdjust', 1],
68             '-bg' => [[$l_Canvas], 'bg', 'bg', 'white'],
69             '-menuselection' => ['METHOD'],
70             '-command' => ['CALLBACK'],
71             '-selection' => ['METHOD'],
72             '-items' => ['METHOD'],
73             '-selected' => ['METHOD'],
74             '-opaque' => ['PASSIVE'],
75             '-attach' => ['METHOD'],
76             '-detach' => ['METHOD'],
77             '-menu' => ['PASSIVE'],
78             );
79              
80             $this->Delegates
81             (
82             'DEFAULT' => $l_Canvas,
83             );
84              
85             $this->SUPER::Populate (@_);
86              
87             $this->Tk::bind ('' => sub {$this->ArrangeItems() if ($this->cget ('-autoadjust'));});
88              
89             $l_Canvas->Tk::bind ('' => sub {$this->SelectionEvent ('', $l_Canvas);});
90             $l_Canvas->Tk::bind ('' => sub {$this->MenuEvent (@_);});
91             $l_Canvas->Tk::bind ('' => sub {$this->MenuEvent (@_);});
92             $l_Canvas->Tk::bind ('' => sub {$this->DropEvent (@_);});
93              
94             unless (defined ($ICON_DEFAULTS->{'-pixmap'}))
95             {
96             if (defined ($ICON_DEFAULTS->{'-pixmap'} = $this->GetPixmap ('folder')))
97             {
98             $ICON_DEFAULTS->{'-pixmap'}->{'m_PixmapSource'} = 'folder';
99             }
100             }
101              
102             $this->GeometryRequest (300, 200);
103             $this->configure ('-opaque' => 0);
104             return $this;
105             }
106              
107             sub Icon
108             {
109             my ($this, %p_Parameters) = @_;
110              
111             my $l_ID = 'Icon_'.++$SERIAL_NUMBER;
112             my $l_Canvas = $this->{m_Canvas};
113             my $l_Pixmap;
114             my $l_Name;
115              
116             foreach my $l_Key (keys %{$ICON_DEFAULTS})
117             {
118             $p_Parameters {$l_Key} = $ICON_DEFAULTS->{$l_Key} unless (defined ($p_Parameters {$l_Key}));
119             }
120              
121             if (ref ($l_Pixmap = $p_Parameters {'-pixmap'}) ne 'Tk::Pixmap')
122             {
123             $l_Pixmap = $p_Parameters {'-pixmap'} = $this->GetPixmap ($l_Name = $p_Parameters {'-pixmap'});
124             $l_Pixmap->{'m_PixmapSource'} = $l_Name if (defined ($l_Pixmap));
125             }
126              
127             if (ref ($p_Parameters {'-pixmap'}) ne 'Tk::Pixmap')
128             {
129             $l_Pixmap = $p_Parameters {'-pixmap'} = $ICON_DEFAULTS->{'-pixmap'};
130             }
131              
132             my $l_Menu = $p_Parameters {'-menu'};
133             my $l_X = $p_Parameters {'-x'};
134             my $l_Y = $p_Parameters {'-y'};
135              
136             my $l_PictureItem = $l_Canvas->create
137             (
138             'image',
139             $l_X,
140             $l_Y,
141             -image => $l_Pixmap,
142             );
143              
144             my $l_TextItem = $l_Canvas->create
145             (
146             'text',
147             $l_X,
148             $l_Y,
149             '-fill' => $this->cget ('-normalcolor'),
150             '-text' => $p_Parameters {'-title'},
151             '-font' => $p_Parameters {'-font'},
152             );
153              
154             $l_Canvas->move
155             (
156             $l_TextItem,
157             (($l_Canvas->bbox ($l_PictureItem)) [2] - ($l_Canvas->bbox ($l_TextItem)) [2]) / 4,
158             $l_Pixmap->height() / 2 + 5,
159             );
160              
161             $l_Canvas->delete ($l_ID);
162             $l_Canvas->addtag ($l_ID, 'withtag', $l_TextItem);
163             $l_Canvas->addtag ($l_ID, 'withtag', $l_PictureItem);
164             $l_Canvas->addtag ('IconImage', 'withtag', $l_PictureItem);
165             $l_Canvas->addtag ('IconText', 'withtag', $l_TextItem);
166             $l_Canvas->addtag ('Icon', 'withtag', $l_ID);
167             $l_Canvas->raise ($l_ID, 'all');
168              
169             $l_Canvas->bind ($l_ID, '' => sub {$this->SelectionEvent ($l_ID, @_, 'shifted');});
170              
171             if (defined ($l_Menu))
172             {
173             $l_Canvas->bind ($l_ID, '' => sub {$this->MenuEvent ($l_Canvas, $l_ID, $l_Menu, @_);});
174             $l_Canvas->bind ($l_ID, '' => sub {$this->MenuEvent ($l_Canvas, $l_ID, $l_Menu, @_);});
175             }
176              
177             $l_Canvas->bind ($l_ID, '' => sub {$this->LaunchEvent ($l_ID, @_);});
178             $l_Canvas->bind ($l_ID, '' => sub {$this->ReleaseEvent ($l_ID, @_);});
179             $l_Canvas->bind ($l_ID, '' => sub {$this->SelectionEvent ($l_ID, @_);});
180             $l_Canvas->bind ($l_ID, '' => sub {$this->DragEvent ($l_ID, @_);});
181              
182             $this->LineAttach ($l_ID, $p_Parameters {'-attach'}) if (defined ($p_Parameters {'-attach'}));
183             $this->ArrangeItems() if ($this->cget ('-autoadjust'));
184             $this->ItemMove ($l_ID, 0, 0);
185             return ($l_ID);
186             }
187              
188             #=========================================================================================
189             # Event Handlers
190             #=========================================================================================
191             sub MenuEvent
192             {
193             my ($this, $p_Canvas, $p_Item, $p_Menu) = (shift, @_);
194              
195             if (Exists ($p_Menu = defined ($p_Menu) ? $p_Menu : $this->cget ('-menu')) && ! $this->{m_MenuActive})
196             {
197             my $l_Event = $p_Canvas->XEvent();
198              
199             ($p_Menu->{m_Canvas} = $this)->{m_MenuSelection} = $p_Item;
200             $this->{m_MenuActive} = 1;
201              
202             $p_Menu->Popup() if ($Tk::VERSION < 800.005);
203              
204             $p_Menu->post
205             (
206             $l_Event->x() + $p_Canvas->rootx(),
207             $l_Event->y() + $p_Canvas->rooty(),
208             );
209             }
210              
211             $this->{m_MenuActive} = defined ($p_Item);
212             }
213              
214             sub LaunchEvent
215             {
216             return
217             (
218             defined ($_[0]->cget ('-command')) ?
219             &{$_[0]->cget ('-command')} ($_[1], $_[0], $_[2]) :
220             undef
221             );
222             }
223              
224             sub SelectionEvent
225             {
226             my ($this, $p_Item, $p_Canvas) = (shift, @_);
227              
228             if ($p_Item ne '')
229             {
230             my $l_Event = $p_Canvas->XEvent();
231             $this->SelectItem ($p_Item, $_[-1] eq 'shifted');
232             $p_Canvas->raise ($p_Item, 'all');
233             $this->{m_SelectionActive} = 1;
234             $this->{m_X} = $l_Event->x();
235             $this->{m_Y} = $l_Event->y();
236             }
237             else
238             {
239             $this->DeselectItem() unless ($this->{m_SelectionActive});
240             $this->{m_SelectionActive} = 0;
241             }
242             }
243              
244             sub DragEvent
245             {
246             my ($this, $p_Item, $p_Canvas) = (shift, @_);
247              
248             if ($this->cget ('-dragallowed'))
249             {
250             my $l_Opaque = $this->cget ('-opaque') && $this->cget ('-opaque') ne 'false';
251             my $l_PositionX = $this->pointerx() - $this->rootx();
252             my $l_PositionY = $this->pointery() - $this->rooty();
253             my $l_Event = $p_Canvas->XEvent();
254             my @l_DeleteList = ();
255             my @l_NewList = ();
256              
257             foreach my $l_Item ($this->cget ('-selection'))
258             {
259             if ($l_PositionX < 0 || $l_PositionY < 0 || $l_PositionX > $this->width() || $l_PositionY > $this->height())
260             {
261             push (@l_DeleteList, $l_Item);
262             $DRAGDROP = 1;
263             }
264             else
265             {
266             push (@l_NewList, $l_Item);
267             }
268              
269             if ($l_Opaque)
270             {
271             $this->move ($l_Item, $l_Event->x() - $this->{m_X}, $l_Event->y() - $this->{m_Y});
272             }
273             }
274              
275             $this->delete (@l_DeleteList) if ($#l_DeleteList > -1);
276             $this->configure ('-cursor' => 'hand1');
277             $this->{'m_Selection'} = [@l_NewList];
278              
279             if ($l_Opaque)
280             {
281             $this->{m_X} = $l_Event->x();
282             $this->{m_Y} = $l_Event->y();
283             }
284             }
285             }
286              
287             sub ReleaseEvent
288             {
289             my ($this, $p_Item, $p_Canvas) = (shift, @_);
290              
291             $this->configure ('-cursor' => $this->{'m_NormalCursor'});
292              
293             if ($this->cget ('-dragallowed'))
294             {
295             my $l_Event = $p_Canvas->XEvent();
296              
297             foreach my $l_Item ($this->cget ('-selection'))
298             {
299             $this->move ($l_Item, $l_Event->x() - $this->{m_X}, $l_Event->y() - $this->{m_Y});
300             $p_Canvas->raise ($l_Item, 'all');
301             $this->CancelDrag();
302             }
303             }
304              
305             if ($this->cget ('-autoadjust'))
306             {
307             $this->ArrangeItems();
308             }
309              
310             $p_Canvas->raise ($p_Item, 'all');
311             }
312              
313             sub DropEvent
314             {
315             my $this = shift;
316             $this->paste() if ($DRAGDROP);
317             $this->CancelDrag();
318             }
319              
320             sub CancelDrag
321             {
322             my $this = shift;
323             $this->configure ('-cursor' => $this->{'m_NormalCursor'});
324             $DRAGDROP = 0;
325             }
326              
327             #=========================================================================================
328             # Item Manipulation Methods
329             #=========================================================================================
330             sub SelectItem
331             {
332             my ($this, $p_Item, $p_Shifted) = (shift, @_);
333              
334             if ($this->IsItemSelected ($p_Item))
335             {
336             $this->DeselectItem ($p_Item) if ($p_Shifted);
337             return;
338             }
339              
340             my $l_TextID = $this->GetIconComponent ('text', $p_Item);
341             $this->DeselectItem() if (! $p_Shifted);
342             $this->itemconfigure ($l_TextID, '-fill' => $this->cget ('-selectcolor'));
343             push (@{$this->{m_Selection}}, $p_Item);
344             return $p_Item;
345             }
346              
347             sub DeselectItem
348             {
349             my ($this, @p_Items) = (shift, @_);
350             my %l_Hash;
351              
352             foreach my $l_Item ($#p_Items == -1 ? $this->find ('withtag', 'Icon') : @p_Items)
353             {
354             my ($l_Tag) = (grep (/^Icon_/, $this->gettags ($l_Item)));
355             $l_Hash {$l_Tag} = 1;
356             }
357              
358             foreach my $l_Item (keys %l_Hash)
359             {
360             if (defined (my $l_TextItem = $this->GetIconComponent ('text', $l_Item)))
361             {
362             @{$this->{m_Selection}} = grep (!/^$l_Item$/, @{$this->{m_Selection}});
363             $this->itemconfigure ($l_TextItem, '-fill' => 'black');
364             }
365             }
366             }
367              
368             sub ItemMove
369             {
370             my ($this, $p_Item, $p_X, $p_Y) = (shift, @_);
371             my $l_Canvas = $this->{m_Canvas};
372             my @l_Scroll = @{$l_Canvas->cget ('scrollregion')};
373             my %l_Hash;
374              
375             foreach my $l_Attachment ($this->FindAttachmentInList ($p_Item, keys %{$this->{m_Attachments}}))
376             {
377             $l_Hash {${${$this->{m_Attachments}}{$l_Attachment}}[0]} = 1;
378             }
379              
380             $l_Hash {$p_Item} = 1;
381              
382             foreach my $l_Item (keys %l_Hash)
383             {
384             $l_Canvas->move ($l_Item, $p_X, $p_Y);
385             }
386              
387             @l_Scroll [2..3] = ($l_Canvas->bbox ('all')) [2..3];
388             $l_Canvas->configure ('-scrollregion' => [@l_Scroll]);
389             $this->LineAdjust();
390             }
391              
392             sub delete
393             {
394             my ($this, @p_Parameters) = @_;
395              
396             $this->copy (@p_Parameters);
397              
398             foreach my $l_ID (@p_Parameters)
399             {
400             $this->LineDetach ($l_ID);
401             $this->{m_Canvas}->delete ($l_ID);
402             }
403             }
404              
405             #======================================================================================
406             # Do not override the following two methods in the subclass, they may potentially get
407             # lists of items which we don't want to have to handle. The overrideable ones are
408             # shown afterwards.
409             #======================================================================================
410             sub copy
411             {
412             my ($this, @p_Parameters) = @_;
413              
414             @COPYLIST = ();
415              
416             foreach my $l_ID (@p_Parameters)
417             {
418             push (@COPYLIST, $this->CopyInstance ($l_ID));
419             }
420             }
421              
422             sub paste
423             {
424             my ($this, @p_Parameters) = @_;
425              
426             foreach my $l_ID (@COPYLIST)
427             {
428             $this->PasteInstance ($l_ID);
429             }
430              
431             $this->CancelDrag();
432             }
433              
434             #======================================================================================
435             # Here, these are the overrideable cut & paste methods. Note that they return a
436             # reference to the hash table so that any downline methods can modify or replace it
437             # the hash contains the information used to reinstantiate the icon
438             #======================================================================================
439             sub CopyInstance
440             {
441             my ($this, $p_Item) = @_;
442              
443             return unless defined ($p_Item);
444              
445             my $l_ImageItem = $this->GetIconComponent ('image', $p_Item);
446             my $l_TextItem = $this->GetIconComponent ('text', $p_Item);
447             my $l_Pixmap = $this->itemcget ($l_ImageItem, '-image');
448             my $l_Text = $this->itemcget ($l_TextItem, '-text');
449             my $l_Font = $this->itemcget ($l_TextItem, '-font');
450              
451             my $l_HashRef =
452             {
453             '-pixmap' => $l_Pixmap->{'m_PixmapSource'},
454             '-title' => $l_Text,
455             '-font' => $l_Font,
456             };
457              
458             return $l_HashRef;
459             }
460              
461             sub PasteInstance
462             {
463             my ($this, $p_HashRef) = @_;
464              
465             my $l_Return = undef;
466              
467             if (ref ($p_HashRef) eq 'HASH')
468             {
469             $l_Return = $this->Icon
470             (
471             -x => $this->pointerx() - $this->rootx(),
472             -y => $this->pointery() - $this->rooty(),
473             %{$p_HashRef},
474             );
475              
476             #====================================================================
477             # I'm not really sure if we should be deleting keys that are specific
478             # to this class, but it protects the higher layers from having to
479             # concern themselves with avoiding them.
480             #====================================================================
481             delete $p_HashRef->{'-pixmap'};
482             delete $p_HashRef->{'-title'};
483             delete $p_HashRef->{'-font'};
484             }
485              
486             return $l_Return; # This gets passed upwards so that reimplementations can modify it
487             }
488              
489             sub ArrangeItems
490             {
491             my ($this) = (shift, @_);
492              
493             my $l_Canvas = $this->{m_Canvas};
494             my %l_Hash;
495              
496             foreach my $l_Item ($this->find ('withtag', 'Icon'))
497             {
498             my ($l_Tag) = (grep (/^Icon_/, $this->gettags ($l_Item)));
499             $l_Hash {$l_Tag} = 1;
500             }
501              
502             my @l_Frame = ($this->width(), $this->height());
503             my @l_Region = @{$l_Canvas->cget ('scrollregion')};
504             my $l_DefaultSpacing = $this->cget ('-iconspacing');
505             my ($l_X, $l_Y, $l_MaxY) = (10, 10, 0, 0);
506              
507             foreach my $l_Object (keys %l_Hash)
508             {
509             my (@l_Bounds) = $l_Canvas->bbox ($l_Object);
510             my ($l_DeltaX, $l_DeltaY) = ($l_X - $l_Bounds [0], $l_Y - $l_Bounds [1]);
511             $this->move ($l_Object, $l_DeltaX, $l_DeltaY);
512             @l_Bounds = $l_Canvas->bbox ($l_Object);
513             $l_X = $l_Bounds [2] + $l_DefaultSpacing;
514             $l_MaxY = ($l_Bounds [3] > $l_MaxY ? $l_Bounds [3] + 10 : $l_MaxY);
515              
516             if ($l_X > $l_Frame [0] - 64)
517             {
518             $l_Y = $l_MaxY;
519             $l_MaxY = 0;
520             $l_X = 10;
521             }
522             }
523             }
524              
525             sub IsItemSelected
526             {
527             return (defined $_[1] && grep (/^$_[1]$/, @{$_[0]->{m_Selection}}) > 0);
528             }
529              
530             #=========================================================================================
531             # Component Collection Handling
532             #=========================================================================================
533             sub GetIconComponent
534             {
535             my ($this, $p_Which, $p_Item) = (shift, @_);
536             my @l_List = $this->find ('withtag', $p_Item);
537             my $l_Return = undef;
538              
539             for (my $l_Index = 0; $l_Index <= $#l_List && ! defined ($l_Return); ++$l_Index)
540             {
541             $l_Return = $l_List [$l_Index] if ($this->type ($l_List [$l_Index]) eq $p_Which);
542             }
543              
544             return $l_Return;
545             }
546              
547             sub GetPixmap
548             {
549             my $this = shift;
550              
551             my $l_Name = undef;
552              
553             my @l_List =
554             (
555             Tk->findINC ($_[0].'.xpm'),
556             Tk->findINC ($_[0]),
557             'icon/'.$_[0].'.xpm',
558             'icon/'.$_[0],
559             $_[0].'.xpm',
560             $_[0],
561             );
562              
563             for (my $l_Index = 0; $l_Index <= $#l_List && ! defined ($l_Name); ++$l_Index)
564             {
565             $l_Name = $l_List [$l_Index] if (-f $l_List [$l_Index]);
566             }
567              
568             return
569             (
570             defined ($this->{'m_PixmapCache'}->{$l_Name}) ? $this->{'m_PixmapCache'}->{$l_Name} :
571             (
572             -f $l_Name ?
573             $this->{'m_PixmapCache'}->{$l_Name} = $this->toplevel()->Pixmap ('-file' => $l_Name) :
574             undef
575             )
576             );
577             }
578              
579             #=========================================================================================
580             # Attachment Manipulation
581             #=========================================================================================
582             sub LineAttach
583             {
584             my ($this, $p_From, $p_To) = (shift, @_);
585              
586             ($p_From, $p_To) = @{$p_From} if (ref ($p_From) eq 'ARRAY');
587              
588             return unless (defined ($p_From) && defined ($p_To));
589              
590             return if (defined ($this->FindAttachmentByAttachment ($p_From, $p_To)));
591              
592             my $l_Canvas = $this->{m_Canvas};
593             my @l_FromBox = $l_Canvas->bbox ($this->GetIconComponent ('image', $p_From));
594             my @l_ToBox = $l_Canvas->bbox ($this->GetIconComponent ('image', $p_To));
595              
596             my $l_ID = $l_Canvas->create
597             (
598             'line',
599             0,0,0,0,
600             -fill => 'black',
601             -width => '2.0',
602             );
603              
604             $this->{m_Attachments}->{$l_ID} = [$p_From, $p_To];
605              
606             #---------------------------------------------------------------
607             # Something strange happens here sometimes. It may be something
608             # to do with the cut/paste mechanism, I don't really know. It
609             # manifests itself as a "phantom" attachment selection. The
610             # attachment selection includes an "invisible" object above the
611             # upper left corner of the canvas.
612             #---------------------------------------------------------------
613             # foreach my $l_Key (keys %{$this->{m_Attachments}})
614             # {
615             # printf ("Attached [%s] to [%s]\n", $l_Key, @{$this->{m_Attachments}->{$l_Key}});
616             # }
617              
618             $this->LineAdjust ($p_From, $p_To);
619             return $l_ID;
620             }
621              
622             sub LineDetach
623             {
624             my ($this, $p_From, $p_To) = (shift, @_);
625              
626             if (ref ($p_From) eq 'ARRAY')
627             {
628             ($p_From, $p_To) = @{$p_From};
629             }
630              
631             foreach my $l_ID ($this->FindAttachmentByAttachment ($p_From, $p_To))
632             {
633             $this->{m_Canvas}->delete ($l_ID);
634             delete ${$this->{m_Attachments}}{$l_ID};
635             }
636             }
637              
638             sub LineAdjust
639             {
640             my ($this, $p_From, $p_To) = (shift, @_);
641             my %l_Hash = %{$this->{m_Attachments}};
642             my $l_Canvas = $this->{m_Canvas};
643              
644             foreach my $l_ID ($this->FindAttachmentByAttachment ($p_From, $p_To))
645             {
646             next unless (ref ($l_Hash {$l_ID}) eq 'ARRAY' && $#{$l_Hash {$l_ID}} > 0);
647              
648             my ($l_From, $l_To) = @{$l_Hash {$l_ID}};
649             my @l_FromBox = $l_Canvas->bbox ($this->GetIconComponent ('image', $l_From));
650             my @l_ToBox = $l_Canvas->bbox ($this->GetIconComponent ('image', $l_To));
651              
652             $l_Canvas->coords
653             (
654             $l_ID,
655             $l_FromBox [0] + (($l_FromBox [2] - $l_FromBox[0]) / 2),
656             $l_FromBox [1] + (($l_FromBox [3] - $l_FromBox[1]) / 2),
657             $l_ToBox [0] + (($l_ToBox [2] - $l_ToBox[0]) / 2),
658             $l_ToBox [1] + (($l_ToBox [3] - $l_ToBox[1]) / 2),
659             );
660              
661             $l_Canvas->lower ($l_ID);
662             }
663             }
664              
665             sub FindAttachmentByID
666             {
667             return ${$_[0]->{m_Attachments}}{$_[1]};
668             }
669              
670             sub FindAttachmentByAttachment
671             {
672             my ($this, $p_From, $p_To) = (shift, @_);
673              
674             my @l_List = $this->FindAttachmentInList
675             (
676             $p_To,
677             $this->FindAttachmentInList ($p_From, keys %{$this->{m_Attachments}})
678             );
679              
680             return ($#l_List >= 0 ? @l_List : undef);
681             }
682              
683             sub FindAttachmentInList
684             {
685             my ($this, $p_IconID, @p_Keys) = (shift, @_);
686             my @l_Return = (@p_Keys);
687              
688             if ($p_IconID ne '')
689             {
690             my %l_Hash = %{$this->{m_Attachments}};
691             @l_Return = ();
692              
693             foreach my $l_ID (@p_Keys)
694             {
695             my ($l_From, $l_To) = (@{$l_Hash {$l_ID}});
696             push (@l_Return, $l_ID) if ($p_IconID eq $l_From || $p_IconID eq $l_To);
697             }
698             }
699              
700             return @l_Return;
701             }
702              
703             #=========================================================================================
704             # ConfigSpec Option Methods
705             #=========================================================================================
706             sub menuselection
707             {
708             return $_[0]->{m_MenuSelection};
709             }
710              
711             sub selection
712             {
713             return @{$_[0]->{m_Selection}};
714             }
715              
716             sub autoadjust
717             {
718             $_[0]->{m_AutoAdjust} = $_[1] if (defined ($_[1]));
719             $_[0]->ArrangeItems() if ($_[0]->{m_AutoAdjust});
720             return $_[0]->{m_AutoAdjust};
721             }
722              
723             sub items
724             {
725             my $this = shift;
726              
727             my %l_Hash;
728              
729             foreach my $l_Item ($this->find ('withtag', 'Icon'))
730             {
731             $l_Hash {(grep (/^Icon_/, $this->gettags ($l_Item)))[0]} = 1;
732             }
733              
734             return (keys %l_Hash);
735             }
736              
737             #=========================================================================================
738             # Alias Methods
739             #=========================================================================================
740             sub detach
741             {
742             return LineDetach (@_);
743             }
744              
745             sub attach
746             {
747             return LineAttach (@_);
748             }
749              
750             sub move
751             {
752             return ItemMove (@_);
753             }
754              
755             sub selected
756             {
757             return IsItemSelected (@_);
758             }
759              
760             1;
761             #=========================================================================================
762             # END OF MODULE
763             #=========================================================================================
764              
765             __END__