File Coverage

blib/lib/Tk/DockFrame.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             #=============================================================================#
2             # This is public class Tk::DockPort used by Tk::DockFrame
3             #=============================================================================#
4             package Tk::DockPort;
5              
6 1     1   2470 use Tk::Frame;
  0            
  0            
7             use Tk;
8              
9             use base qw (Tk::Frame);
10             use vars qw ($VERSION);
11             use strict;
12             use Carp;
13              
14             $VERSION = '0.03';
15              
16             Tk::Widget->Construct ('DockPort');
17              
18             1;
19              
20             #=============================================================================#
21             # This is a private class used by Tk::DockFrame::Win32 & Tk::DockFrame::X11
22             #=============================================================================#
23             package Tk::DockFrame::Base;
24              
25             use Tk::Toplevel;
26             use Tk::Frame;
27             use Tk;
28              
29             use base qw (Tk::Frame Tk::Toplevel);
30             use strict;
31             use Carp;
32              
33             Tk::Widget->Construct ('DockFrame::Base');
34              
35             #------------------------------- Private methods -----------------------------#
36              
37             sub __trimrelease
38             {
39             foreach my $l_Widget (@{$_[0]->{m_TrimElements}})
40             {
41             $l_Widget->grabRelease();
42             }
43             }
44              
45             #-----------------------------Event-Handlers----------------------------------#
46              
47             sub ButtonPressEvent
48             {
49             my ($this, $p_EventWidget) = @_;
50              
51             $this->undock();
52             $this->Tk::raise();
53             $this->__trimrelease();
54              
55             $this->{'m_Offsets'} =
56             [
57             $p_EventWidget->pointerx() - $this->rootx(),
58             $p_EventWidget->pointery() - $this->rooty(),
59             ];
60             }
61              
62             sub ButtonReleaseEvent
63             {
64             $_[0]->{'m_CantDockYet'} = undef;
65             $_[0]->__trimrelease();
66             $_[0]->Tk::raise();
67             }
68              
69             sub DragEvent
70             {
71             my ($this, $p_EventWidget) = @_;
72              
73             return unless ($this->toplevel() eq $this);
74              
75             $this->MoveToplevelWindow
76             (
77             $p_EventWidget->pointerx() - ${$this->{'m_Offsets'}}[0],
78             $p_EventWidget->pointery() - ${$this->{'m_Offsets'}}[1],
79             );
80              
81             $this->idletasks();
82              
83             my $l_Sensitivity = $this->cget ('-sensitivity');
84             my $l_DockWidget;
85             my $l_Found = 0;
86              
87             my @l_Box =
88             (
89             $this->rootx(),
90             $this->rooty(),
91             $this->width() + $this->rootx(),
92             $this->height() + $this->rooty(),
93             );
94              
95             foreach my $l_Child ($this->parent()->children())
96             {
97             next if (ref ($l_Child) ne 'Tk::DockPort' || defined ($l_Child->{'m_Client'}));
98              
99             my @l_Coords = ($l_Child->rootx(), $l_Child->rooty());
100              
101             my $l_Test =
102             (
103             $l_Coords [0] >= $l_Box [0] - $l_Sensitivity &&
104             $l_Coords [0] <= $l_Box [2] + $l_Sensitivity &&
105             $l_Coords [1] >= $l_Box [1] - $l_Sensitivity &&
106             $l_Coords [1] <= $l_Box [3] + $l_Sensitivity
107             );
108              
109             if (! $l_Test)
110             {}
111             elsif ($this->{'m_CantDockYet'})
112             {
113             $l_Found = 1;
114             }
115             else
116             {
117             $l_DockWidget = $l_Child;
118             }
119             }
120              
121             $this->dock ($l_DockWidget) if (defined ($l_DockWidget));
122             $this->{'m_CantDockYet'} = undef unless ($l_Found);
123             $this->Tk::raise();
124             $this->idletasks();
125             }
126              
127             #-----------------------------'METHOD'-type-settings--------------------------#
128              
129             sub trimcount
130             {
131             my ($this, $p_TrimCount) = (shift, @_);
132              
133             $this->{'m_TrimElements'} = [] unless (defined ($this->{'m_TrimElements'}));
134              
135             if (defined ($p_TrimCount) && $p_TrimCount >= 0)
136             {
137             my @l_TrimElements = @{$this->{m_TrimElements}};
138              
139             $p_TrimCount = 12 if ($p_TrimCount > 12);
140              
141             while ($p_TrimCount > $#l_TrimElements + 1)
142             {
143             my $l_Widget = $this->Component
144             (
145             'Frame' => 'TrimElement_'.($#l_TrimElements + 1),
146             '-cursor' => 'fleur',
147             '-relief' => 'raised',
148             '-borderwidth' => 1,
149             '-width' => 2,
150             );
151              
152             $l_Widget->pack
153             (
154             '-side' => 'left',
155             '-anchor' => 'nw',
156             '-fill' => 'y',
157             '-ipadx' => 0,
158             '-padx' => 1,
159             '-pady' => 1,
160             );
161              
162             $l_Widget->bind ('' => sub {$this->ButtonReleaseEvent ($l_Widget);});
163             $l_Widget->bind ('' => sub {$this->ButtonPressEvent ($l_Widget);});
164             $l_Widget->bind ('' => sub {$this->DragEvent ($l_Widget);});
165             push @l_TrimElements, $l_Widget;
166             }
167              
168             while ($p_TrimCount <= $#l_TrimElements)
169             {
170             (pop @l_TrimElements)->destroy();
171             }
172              
173             $this->{m_TrimElements} = [@l_TrimElements];
174             }
175              
176             return $#{$this->{m_TrimElements}} + 1;
177             }
178              
179             1;
180              
181              
182             #=============================================================================#
183             # This is a private class used by Tk::DockFrame
184             #=============================================================================#
185             package Tk::DockFrame::X11;
186              
187             use strict;
188             use Carp;
189              
190             use base qw (Tk::Frame Tk::Toplevel Tk::DockFrame::Base);
191              
192             Tk::Widget->Construct ('DockFrame::X11');
193              
194             #------------------------------- Private methods -----------------------------#
195              
196             sub Populate
197             {
198             my $this = shift;
199              
200             $this->SUPER::Populate (@_);
201              
202             my $l_ClientFrame = $this->Component
203             (
204             'Frame' => 'ClientFrame',
205             );
206              
207             my $l_Spacer = $this->Component
208             (
209             'Frame' => 'Spacer',
210             );
211              
212             $this->Delegates
213             (
214             'Construct' => $l_ClientFrame,
215             'DEFAULT' => $l_ClientFrame,
216             );
217              
218             $this->ConfigSpecs
219             (
220             '-dock' => ['METHOD', 'dock', 'Dock', 0],
221             '-trimcount' => ['METHOD', 'trimcount', 'TrimCount', 1],
222             '-sensitivity' => ['PASSIVE', 'sensitivity', 'Sensitivity', 10],
223             '-decorate' => ['PASSIVE', 'decorate', 'Decorate', 0],
224             '-trimgap' => ['PASSIVE', 'trimgap', 'TrimGap', 2],
225             'DEFAULT' => [$l_ClientFrame],
226             );
227              
228             $l_ClientFrame->pack
229             (
230             '-expand' => 'true',
231             '-fill' => 'both',
232             '-side' => 'left',
233             );
234              
235             $this->configure
236             (
237             '-relief' => 'raised',
238             '-borderwidth' => 1,
239             );
240              
241             $this->bind ('' => sub {$this->ExposeEvent();});
242              
243             return $this;
244             }
245              
246             #-----------------------------Event-Handlers----------------------------------#
247              
248             sub ButtonPressEvent
249             {
250             my ($this, $p_EventWidget) = (shift, @_);
251             $this->SUPER::ButtonPressEvent (@_);
252             $p_EventWidget->grab();
253             }
254              
255             sub ExposeEvent
256             {
257             my $this = shift;
258              
259             my ($l_Spacer, $l_ClientFrame) =
260             (
261             $this->Subwidget ('Spacer'),
262             $this->Subwidget ('ClientFrame')
263             );
264              
265             if (defined ($l_Spacer) && defined ($l_ClientFrame))
266             {
267             $l_Spacer->pack
268             (
269             '-before' => $l_ClientFrame,
270             ($#{$this->{m_TrimElements}} > -1 ? ('-after' => ${$this->{m_TrimElements}} [-1]) : ()),
271             '-ipadx' => $this->cget ('-trimgap'),
272             '-side' => 'left',
273             );
274             }
275              
276             unless (defined ($this->cget ('-dock')))
277             {
278             $this->MoveToplevelWindow
279             (
280             $this->rootx() || $this->parent()->toplevel()->rootx(),
281             $this->rooty() || $this->parent()->toplevel()->rooty(),
282             );
283              
284             $this->raise();
285             }
286             }
287              
288             #------------------------------- Public methods -----------------------------#
289              
290             sub dock
291             {
292             my ($this, $p_Dock) = (shift, @_);
293              
294             unless (defined ($p_Dock))
295             {
296             return $this->{'Configure'}{'-dock'};
297             }
298              
299             unless ($p_Dock)
300             {
301             $this->DoWhenIdle (sub {$this->undock();});
302             return;
303             }
304              
305             unless ($this->IsMapped())
306             {
307             $this->DoWhenIdle (sub {$this->dock ($p_Dock);});
308             $this->MapWindow();
309             return ($p_Dock);
310             }
311              
312             if ($this->toplevel() eq $this)
313             {
314             $this->resizable (1, 1);
315             $this->wmCapture();
316             }
317              
318             $this->DoWhenIdle
319             (
320             sub
321             {
322             my @l_SlaveList = $p_Dock->packSlaves();
323             # $this->pack ('-fill' => 'both', '-after' => $p_Dock);
324             $this->__trimrelease();
325              
326             $this->pack
327             (
328             '-expand' => 'true',
329             '-in' => $p_Dock,
330             '-side' => 'left',
331             '-fill' => 'both',
332             '-anchor' => 'nw',
333             ($#l_SlaveList > -1 ? ('-before' => $l_SlaveList [0]) : ()),
334             );
335              
336             $p_Dock->GeometryRequest (1, 1);
337             }
338             );
339              
340             return ($this->{'Configure'}{'-dock'} = $p_Dock);
341             }
342              
343             sub undock
344             {
345             my @l_Coords = ($_[0]->rootx(), $_[0]->rooty());
346              
347             if ($_[0]->toplevel() ne $_[0])
348             {
349             my %l_PackInfo = eval {$_[0]->packInfo();};
350             my $l_DockPort = $l_PackInfo {'-in'};
351              
352             $_[0]->packForget();
353             $_[0]->parent()->update();
354             $_[0]->wmRelease();
355              
356             if (defined ($l_DockPort))
357             {
358             my @l_Slaves = $l_DockPort->packSlaves();
359             $l_DockPort->GeometryRequest (0, 0) if ($#l_Slaves == -1);
360             }
361             }
362              
363             $_[0]->{'m_CantDockYet'} = 1;
364             $_[0]->{'Configure'}{'-dock'} = undef;
365             $_[0]->overrideredirect ($_[0]->{'Configure'}{'-decorate'} ? 0 : 1);
366             $_[0]->resizable (0, 0);
367             $_[0]->deiconify();
368             $_[0]->MapWindow();
369             $_[0]->MoveToplevelWindow (@l_Coords);
370             $_[0]->idletasks();
371             }
372              
373             1;
374              
375              
376             #=============================================================================#
377             # This is a private class used by Tk::DockFrame
378             #=============================================================================#
379             package Tk::DockFrame::Win32;
380              
381             use base qw (Tk::Toplevel Tk::DockFrame::Base);
382              
383             Tk::Widget->Construct ('DockFrame::Win32');
384              
385             *Ev = \&Tk::Ev;
386              
387             #------------------------------- Private methods -----------------------------#
388              
389             sub Populate
390             {
391             my $this = shift;
392              
393             $this->SUPER::Populate (@_);
394              
395             my $l_Spacer = $this->Component
396             (
397             'Frame' => 'Spacer',
398             );
399              
400             $this->ConfigSpecs
401             (
402             '-sensitivity' => ['PASSIVE', 'sensitivity', 'Sensitivity', 10],
403             '-decorate' => ['PASSIVE', 'decorate', 'Decorate', 0],
404             '-trimgap' => ['PASSIVE', 'trimgap', 'TrimGap', 2],
405             '-trimcount' => ['METHOD', 'trimcount', 'TrimCount', 1],
406             '-dock' => ['METHOD', 'dock', 'Dock', 0],
407             );
408              
409             $this->configure
410             (
411             '-relief' => 'raised',
412             '-borderwidth' => 1,
413             '-takefocus' => 0,
414             );
415              
416             $this->bind ('' => sub {$this->ExposeEvent();});
417              
418             return $this;
419             }
420              
421             #-----------------------------Event-Handlers----------------------------------#
422              
423             sub ExposeEvent
424             {
425             my $this = shift;
426              
427             my $l_Spacer = $this->Subwidget ('Spacer');
428             my $l_ClientFrame;
429              
430             foreach my $l_Widget ($this->children())
431             {
432             next if ($l_Widget->name() eq 'spacer' || $l_Widget->name() =~ /^trimElement\_/);
433             $l_ClientFrame = $l_Widget;
434             last;
435             }
436              
437             $l_Spacer->pack
438             (
439             ($#{$this->{m_TrimElements}} > -1 ? ('-after' => ${$this->{m_TrimElements}} [-1]) : ()),
440             (defined ($l_ClientFrame) ? ('-before' => $l_ClientFrame) : ()),
441             '-ipadx' => $this->cget ('-trimgap'),
442             '-side' => 'left',
443             );
444             }
445              
446             sub CheckDockEvent
447             {
448             my ($p_EventWidget, $this, $p_Count, $p_Width, $p_Height, $p_X, $p_Y, $p_SendEvent, $p_Type) = @_;
449              
450             my $l_MirrorFrame = $this->{'m_Mirror'};
451              
452             if ($p_Count + $p_Width + $p_Height + $p_X + $p_Y + $p_SendEvent && $l_MirrorFrame)
453             {
454             $this->MoveResizeWindow
455             (
456             $l_MirrorFrame->rootx(),
457             $l_MirrorFrame->rooty(),
458             $l_MirrorFrame->width(),
459             $l_MirrorFrame->height()
460             );
461              
462             $this->Tk::raise();
463             }
464             else
465             {
466             Tk::break;
467             }
468             }
469              
470             sub ResizeEvent
471             {
472             my ($p_EventWidget, $this) = @_;
473              
474             my $l_MirrorFrame = $this->{'m_Mirror'};
475              
476             return unless (defined ($l_MirrorFrame));
477              
478             $this->MoveResizeWindow
479             (
480             $l_MirrorFrame->rootx(),
481             $l_MirrorFrame->rooty(),
482             $l_MirrorFrame->width(),
483             $l_MirrorFrame->height()
484             );
485              
486             $this->Tk::raise();
487              
488             Tk::break;
489             }
490              
491             sub MapEvent
492             {
493             my ($p_EventWidget, $this) = @_;
494              
495             my $l_MirrorFrame = $this->{'m_Mirror'};
496              
497             return unless (defined ($l_MirrorFrame));
498              
499             $l_MirrorFrame->IsMapped() ? $this->MapWindow() : $this->UnmapWindow();
500             }
501              
502             #------------------------------- Public methods -----------------------------#
503              
504             sub dock
505             {
506             my ($this, $p_Dock) = (shift, @_);
507              
508             if (! defined ($p_Dock) || defined ($this->{'m_Mirror'}))
509             {
510             return $this->{'Configure'}{'-dock'};
511             }
512              
513             unless ($p_Dock)
514             {
515             $this->DoWhenIdle (sub {$this->undock();});
516             return;
517             }
518              
519             unless ($this->IsMapped())
520             {
521             $this->DoWhenIdle (sub {$this->undock(); $this->dock ($p_Dock);});
522             $this->MapWindow();
523             return ($p_Dock);
524             }
525              
526             my @l_SlaveList = $p_Dock->packSlaves();
527              
528             my $l_MirrorFrame = $this->{'m_Mirror'} = $p_Dock->parent()->Frame
529             (
530             '-width' => $this->reqwidth(),
531             '-height' => $this->reqheight(),
532             );
533              
534             $l_MirrorFrame->bind
535             (
536             '' => [\&ResizeEvent, $this]
537             );
538              
539             $l_MirrorFrame->bind
540             (
541             '' => [\&MapEvent, $this]
542             );
543              
544             $l_MirrorFrame->bind
545             (
546             '' => [\&MapEvent, $this]
547             );
548              
549             $l_MirrorFrame->bind
550             (
551             '' => [\&CheckDockEvent, $this, Ev('c'), Ev('w'), Ev('h'), Ev('x'), Ev('y'), Ev('E'), Ev('T')]
552             );
553              
554             $l_MirrorFrame->pack
555             (
556             '-expand' => 'true',
557             '-in' => $p_Dock,
558             '-side' => 'left',
559             '-fill' => 'both',
560             '-anchor' => 'nw',
561             ($#l_SlaveList > -1 ? ('-before' => $l_SlaveList [0]) : ()),
562             );
563              
564             $p_Dock->GeometryRequest (1, 1);
565             $this->__trimrelease();
566             $this->overrideredirect (1);
567             $this->deiconify();
568             $this->idletasks();
569             $p_Dock->toplevel()->Tk::raise();
570             $p_Dock->toplevel()->focus();
571             return ($this->{'Configure'}{'-dock'} = $p_Dock);
572             }
573              
574             sub undock
575             {
576             my $this = shift;
577              
578             my $l_MirrorFrame = $this->{'m_Mirror'};
579              
580             if (defined ($l_MirrorFrame))
581             {
582             my %l_PackInfo = eval {$l_MirrorFrame->packInfo();};
583             my $l_DockPort = $l_PackInfo {'-in'};
584              
585             $l_MirrorFrame->packForget();
586             $l_MirrorFrame->parent()->update();
587             $this->geometry (join ('x', $this->reqwidth(), $this->reqheight()));
588             $this->{'m_CantDockYet'} = 1;
589             $this->{'m_Mirror'} = undef;
590             $l_MirrorFrame->destroy();
591              
592             if (defined ($l_DockPort))
593             {
594             my @l_Slaves = $l_DockPort->packSlaves();
595             $l_DockPort->GeometryRequest (0, 0) if ($#l_Slaves == -1);
596             }
597             }
598              
599             $this->overrideredirect ($this->cget ('-decorate') ? 0 : 1);
600             $this->deiconify();
601             $this->idletasks();
602             }
603              
604             1;
605              
606              
607             #=============================================================================#
608             # This is public class Tk::DockFrame
609             #=============================================================================#
610             package Tk::DockFrame;
611              
612             use base ($^O eq 'MSWin32' ? qw (Tk::DockFrame::Win32) : qw (Tk::DockFrame::X11));
613              
614             use vars qw ($VERSION);
615              
616             $VERSION = '2.0';
617              
618             Tk::Widget->Construct ('DockFrame');
619              
620             1;
621              
622              
623             #=============================================================================#
624             # END
625             #=============================================================================#
626              
627             __END__