File Coverage

blib/lib/Tk/Playlist.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #!perl -w
2             #
3             # Tk::Playlist class - provides winamp-style "playlist" editing capibilities.
4             #
5             # By Tyler "Crackerjack" MacDonald
6             # July 23rd, 2000.
7             # Package-ified November 25, 2004.
8             #
9             # This module is freeware; You may redistribute it under the same terms as
10             # perl itself.
11             #
12              
13             package Tk::Playlist;
14              
15 1     1   9530 use 5.005;
  1         4  
  1         39  
16 1     1   6 use strict;
  1         2  
  1         39  
17 1     1   4 use vars qw($VERSION @ISA);
  1         15  
  1         73  
18              
19 1     1   2867 use Tk;
  0            
  0            
20             use Tk::Derived;
21             use Tk::HList;
22              
23             $VERSION = '0.01';
24             @ISA=qw(Tk::Derived Tk::HList);
25              
26             Construct Tk::Widget 'Playlist';
27              
28             sub Tk::Widget::ScrolledPlaylist { shift->Scrolled('Playlist'=>@_); }
29              
30             return 1;
31              
32             sub ClassInit
33             {
34             my($class,$mw)=@_;
35              
36             $mw->eventAdd('<>' => '');
37             $mw->eventAdd('<>' => '');
38             $mw->eventAdd('<>' => '');
39             $mw->eventAdd('<>' => '');
40             $mw->eventAdd('<>' => '');
41             $mw->eventAdd('<>' => '');
42             $mw->eventAdd('<>' => '');
43              
44             $mw->bind($class, '<>', [ 'Toggle' ]);
45             $mw->bind($class, '<>', [ 'SingleSelect' ]);
46             $mw->bind($class, '<>', [ 'RangeSelect' ]);
47             $mw->bind($class, '<>', [ 'MoveEntries' ]);
48             $mw->bind($class, '<>', [ 'EndMovement' ]);
49             $mw->bind($class, '<>', [ 'Delete' ]);
50              
51             # $class->SUPER::ClassInit($mw);
52             }
53              
54             sub Populate
55             {
56             my($cw,$args)=@_;
57             my $f;
58              
59             $cw->ConfigSpecs('-style'=>['PASSIVE', undef, undef, undef]);
60             $cw->ConfigSpecs('-readonly'=>['METHOD', undef, undef, undef]);
61             $cw->ConfigSpecs('-callback_change'=>['METHOD', undef, undef, undef]);
62              
63             $cw->SUPER::Populate($args);
64             }
65              
66             sub Delete
67             {
68             my($cw)=@_;
69              
70             return if($cw->{'readonly'});
71              
72             my @is=$cw->infoSelection();
73             grep($cw->deleteEntry($_),@is);
74              
75             if($cw->{'callback_change'})
76             {
77             my($cmd,@arg);
78             if(ref($cw->{'callback_change'}) eq 'ARRAY')
79             {
80             ($cmd,@arg)=@{$cw->{'callback_change'}};
81             }
82             elsif(ref($cw->{'callback_change'}) eq 'CODE')
83             {
84             ($cmd,@arg)=($cw->{'callback_change'});
85             }
86              
87             if($cmd)
88             {
89             my $i;
90             foreach $i (@is)
91             {
92             &{$cmd}($cw,'delete',$i,@arg);
93             }
94             }
95             }
96             }
97              
98             sub InverseSelect
99             {
100             my($w)=@_;
101             my(%ic,@is);
102             grep($ic{$_}++,$w->infoSelection());
103             @is=grep(!$ic{$_},$w->infoChildren());
104             $w->selectionClear();
105             grep($w->selectionSet($_),@is);
106             }
107              
108              
109             sub evFindClick
110             {
111             my($w,$Ev)=@_;
112             $w->GetNearest($Ev->y, 1);
113             }
114              
115             sub findClick
116             {
117             $_[0]->evFindClick($_[0]->XEvent);
118             }
119              
120             sub EndMovement
121             {
122             my($cw,$args)=@_;
123             if($cw->{moving})
124             {
125             delete($cw->{moving});
126              
127             if($cw->{'callback_change'})
128             {
129             my($cmd,@arg);
130             if(ref($cw->{'callback_change'}) eq 'ARRAY')
131             {
132             ($cmd,@arg)=@{$cw->{'callback_change'}};
133             }
134             elsif(ref($cw->{'callback_change'}) eq 'CODE')
135             {
136             ($cmd,@arg)=($cw->{'callback_change'});
137             }
138              
139             if($cmd)
140             {
141             &{$cmd}($cw,'done_moving',@arg);
142             }
143             }
144             }
145             }
146              
147             sub MoveEntries
148             {
149             my($cw,$args)=@_;
150             my($Ev,$yy,$dir,$ent);
151              
152             return if($cw->{'readonly'});
153              
154             $Ev=$cw->XEvent;
155             $yy=$Ev->y;
156             $ent=$cw->evFindClick($Ev);
157              
158             if(!$cw->{moving})
159             {
160             $cw->{moving}=$yy;
161             $cw->{old_ent}=$ent;
162             }
163             else
164             {
165             if($cw->{moving}>$yy && $cw->{moving}-10>$yy)
166             {
167             $dir=-1;
168             }
169             elsif($cw->{moving}<$yy && $cw->{moving}+10<$yy)
170             {
171             $dir=1;
172             }
173              
174             if($ent && $cw->{old_ent} && $ent eq $cw->{old_ent})
175             {
176             $dir=0;
177             }
178              
179             $cw->{old_ent}=$ent;
180              
181             if($Ev->y+10>=$cw->height)
182             {
183             $dir=1;
184             }
185             elsif($Ev->y-10<=0)
186             {
187             $dir=-1;
188             }
189              
190             if($dir)
191             {
192             my(@ic,%ic,@is,$ii,$icc,@iss);
193             @ic=$cw->infoChildren();
194             grep($ic{$ic[$_]}=$_,$[..$#ic);
195             @is=$cw->infoSelection();
196             if($dir==1)
197             {
198             @iss=reverse(@is);
199             }
200             else
201             {
202             @iss=@is;
203             }
204              
205             foreach $ii (@iss)
206             {
207             my $pos;
208             $icc=[tk_to_cfg_args($cw->entryconfigure($ii))];
209             if(!$ic{$ii})
210             {
211             if($ent)
212             {
213             $pos=$ic{$ent}+$dir;
214             }
215             elsif($Ev->y<10)
216             {
217             $pos=0;
218             }
219             else
220             {
221             $pos=$#ic;
222             }
223             }
224             else
225             {
226             $pos=$ic{$ii}+$dir;
227             }
228             if($pos<0)
229             {
230             $pos=0;
231             }
232             elsif($pos>$#ic)
233             {
234             $pos=$#ic;
235             }
236              
237             if($pos!=$ic{$ii})
238             {
239             $cw->selectionClear($ii);
240             $cw->deleteEntry($ii);
241             $cw->add($ii, @$icc, -at=>$pos);
242             $cw->selectionSet($ii);
243             $cw->anchorSet($ii);
244              
245             if($cw->{'callback_change'})
246             {
247             my($cmd,@arg);
248             if(ref($cw->{'callback_change'}) eq 'ARRAY')
249             {
250             ($cmd,@arg)=@{$cw->{'callback_change'}};
251             }
252             elsif(ref($cw->{'callback_change'}) eq 'CODE')
253             {
254             ($cmd,@arg)=($cw->{'callback_change'});
255             }
256              
257             if($cmd)
258             {
259             &{$cmd}($cw,'move',$ii,$pos,@arg);
260             }
261             }
262             }
263              
264             if($pos!=0 && $pos!=$#ic)
265             {
266             $cw->{moving}=$Ev->y;
267             }
268             }
269              
270             if($dir==-1 && @is)
271             {
272             $cw->see($is[0]);
273             }
274             elsif($dir==1 && @is)
275             {
276             $cw->see($is[$#is]);
277             }
278             }
279             }
280             }
281              
282             sub tk_to_cfg_args
283             {
284             my(@tk)=@_;
285             my(@rv,$i);
286             while($i=shift(@tk))
287             {
288             push(@rv,$i->[0]);
289             push(@rv,$i->[$#$i]);
290             }
291             @rv;
292             }
293              
294             sub RangeSelect
295             {
296             my $w=shift;
297             my $ent;
298              
299              
300             $w->focus() if($w->cget('-takefocus'));
301             $w->selectionClear();
302              
303             if($ent=$w->findClick)
304             {
305             my $nent;
306             unless($nent=$w->infoAnchor())
307             {
308             $nent=$ent;
309             }
310              
311             if($w->selectionIncludes($ent))
312             {
313             $w->selectionClear($ent,$nent);
314             }
315             else
316             {
317             $w->selectionSet($ent,$nent);
318             }
319             $w->anchorSet($ent);
320             }
321             }
322              
323             sub SingleSelect
324             {
325             my $w=shift;
326             my $ent;
327              
328              
329             $w->focus() if($w->cget('-takefocus'));
330             $w->selectionClear();
331              
332             if($ent=$w->findClick)
333             {
334             $w->selectionSet($ent,$ent);
335             $w->anchorSet($ent);
336             }
337             else
338             {
339             $w->anchorClear();
340             }
341             }
342              
343             sub Toggle
344             {
345             my $w=shift;
346             my $ent;
347              
348              
349             $w->focus() if($w->cget('-takefocus'));
350              
351             if($ent=$w->findClick)
352             {
353             if($w->selectionIncludes($ent))
354             {
355             $w->selectionClear($ent,$ent);
356             }
357             else
358             {
359             $w->selectionSet($ent,$ent);
360             }
361             $w->anchorSet($ent);
362             }
363             else
364             {
365             $w->anchorClear();
366             }
367            
368             }
369              
370             sub add_entry
371             {
372             my($cw,$eid,$etxt,$st)=@_;
373             $cw->add($eid,-text=>$etxt,-style=>$st || $cw->cget('-style'));
374             }
375              
376             sub readonly {
377             my($cw, $val) = @_;
378             my $rv = $cw->{readonly};
379             if(defined($val)) {
380             $cw->{readonly} = $val;
381             }
382             $rv;
383             }
384              
385             sub callback_change {
386             my($cw, $val) = @_;
387             my $rv = $cw->{callback_change};
388             if(defined($val)) {
389             $cw->{callback_change} = $val;
390             }
391             $rv;
392             }
393              
394             1;
395             __END__