File Coverage

blib/lib/Tk/Menustrip.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::Menustrip;
2              
3 1     1   3154 use Tk;
  0            
  0            
4             use Tk::Label;
5             use Tk::Button;
6             use Tk::Toplevel;
7              
8             use base qw (Tk::Frame);
9             use vars qw ($VERSION);
10             use strict;
11             use Carp;
12              
13             $VERSION = '0.01';
14              
15             Tk::Widget->Construct ('Menustrip');
16              
17             sub Populate
18             {
19             my ($this, %p_Options) = (shift, @_);
20              
21             my $l_DefaultFont = delete $p_Options {'-font'} || '-*-Times-Medium-R-Normal--*-140-*-*-*-*-*-*';
22              
23             my $l_SubRef = sub
24             {
25             $this->configure ('-automenu' => 'false');
26             $this->Hide();
27             };
28              
29             $this->SUPER::Populate (@_);
30             $this->toplevel()->bind ('' => $l_SubRef);
31             $this->bind ('' => $l_SubRef);
32              
33             $this->ConfigSpecs
34             (
35             '-background' => [['SELF', 'CHILDREN', 'DESCENDANTS'], 'background', 'Background', $this->parent()->cget ('-background')],
36             '-foreground' => [['SELF', 'PASSIVE', 'CHILDREN', 'DESCENDANTS'], 'foreground', 'Foreground', 'black'],
37             '-borderwidth' => ['SELF', 'borderwidth', 'BorderWidth', 1],
38             '-automenu' => ['METHOD', 'automenu', 'AutoMenu', 'false'],
39             '-font' => ['PASSIVE', 'font', 'Font', $l_DefaultFont],
40             '-relief' => ['SELF', 'relief', 'Relief', 'raised'],
41             );
42              
43             $this->configure ('-font' => $l_DefaultFont);
44              
45             return $this;
46             }
47              
48             sub automenu
49             {
50             $_[0]->{'m_AutoMenu'} =
51             (
52             defined ($_[1]) ?
53             ($_[1] eq 'true' || $_[1] > 0 || $_[1] eq 'on') :
54             $_[0]->{'m_AutoMenu'}
55             );
56             }
57              
58             sub MenuLabel
59             {
60             my ($this, $p_Caption, $p_Flag) = (shift, @_);
61              
62             my $l_Frame = $this->Component
63             (
64             'Frame' => $this->FixName ($p_Caption),
65             '-borderwidth' => 2,
66             '-relief' => 'flat',
67             );
68              
69             my $l_Label = $l_Frame->Component
70             (
71             'Button' => 'Label',
72             '-font' => $this->cget ('-font'),
73             '-text' => $p_Caption,
74             '-relief' => 'flat',
75             '-borderwidth' => 0,
76             '-padx' => 0,
77             '-pady' => 0,
78             );
79              
80             my $l_Popup = $l_Frame->Component
81             (
82             'Toplevel' => 'Popup',
83             '-relief' => 'raised',
84             '-borderwidth' => 1,
85             );
86              
87             $l_Label->configure
88             (
89             '-activebackground' => $l_Label->cget ('-background'),
90             '-highlightthickness' => 1,
91             );
92              
93             $l_Label->pack
94             (
95             '-expand' => 'true',
96             '-side' => 'left',
97             '-ipadx' => 0,
98             '-ipady' => 0,
99             '-padx' => 0,
100             '-pady' => 0,
101             );
102              
103             $l_Frame->pack
104             (
105             '-side' => ($p_Flag eq '-right' ? 'right' : 'left'),
106             '-anchor' => ($p_Flag eq '-right' ? 'ne' : 'nw'),
107             '-fill' => 'y',
108             '-padx' => 1,
109             '-pady' => 1,
110             );
111              
112             $l_Label->bind
113             (
114             '' => sub
115             {
116             $this->configure ('-automenu' => 'true');
117             $this->Show ($l_Label);
118             Tk->break;
119             }
120             );
121              
122             $l_Label->bind
123             (
124             '' => sub
125             {
126             $this->Show ($l_Label) if ($this->cget ('-automenu'));
127             Tk->break;
128             }
129             );
130              
131             $l_Label->bind
132             (
133             '' => sub
134             {
135             $this->configure ('-automenu' => 'true');
136             $this->Show ($l_Label);
137             }
138             );
139              
140             $l_Label->bind
141             (
142             '' => sub
143             {
144             $this->configure ('-automenu' => 'true');
145             $this->Show ($l_Label);
146             }
147             );
148              
149             $l_Label->bind
150             (
151             '' => sub
152             {
153             $l_Label->focusNext();
154             }
155             );
156              
157             $l_Label->bind
158             (
159             '' => sub
160             {
161             $l_Label->focusPrev();
162             }
163             );
164              
165             $l_Popup->bind
166             (
167             '' => sub
168             {
169             $this->automenu ('false');
170             $this->Hide();
171             }
172             );
173              
174             push (@{$this->{m_MenuList}}, $l_Label);
175             $l_Popup->overrideredirect (1);
176             $this->Hide ($l_Label);
177             }
178              
179             sub MenuEntry
180             {
181             my ($this, $p_Caption, $p_EntryCaption, $p_Action) = (shift, @_);
182              
183             unless (defined ($p_EntryCaption))
184             {
185             $this->MenuSeparator ($p_Caption);
186             return;
187             }
188              
189             unless (Exists ($this->Subwidget ($this->FixName ($p_Caption))))
190             {
191             $this->MenuLabel ($p_Caption);
192             return unless Exists ($this->Subwidget ($this->FixName ($p_Caption)));
193             }
194              
195             my $l_Popup = $this->Subwidget ($this->FixName ($p_Caption))->Subwidget ('Popup');
196              
197             my $l_Label = $l_Popup->Component
198             (
199             'Button' => $this->FixName ($p_EntryCaption),
200             '-font' => $this->cget ('-font'),
201             '-highlightthickness' => 1,
202             '-text' => $p_EntryCaption,
203             '-justify' => 'left',
204             '-relief' => 'flat',
205             '-borderwidth' => 1,
206             '-anchor' => 'w',
207             '-padx' => 5,
208             '-pady' => 0,
209             );
210              
211             $l_Popup->{'m_Focus'} = $l_Label unless (defined ($l_Popup->{'m_Focus'}));
212              
213             unless (ref ($p_Action) eq 'CODE')
214             {
215             $p_Action = sub {printf ("[%s]\n", $p_EntryCaption);};
216             }
217              
218             $l_Label->configure
219             (
220             '-command' => sub
221             {
222             if ($l_Label->{m_Enabled} eq 'true')
223             {
224             $this->automenu ('false');
225             $this->Hide();
226             $this->afterIdle ($p_Action);
227             }
228             }
229             );
230              
231             $l_Label->pack
232             (
233             '-expand' => 'true',
234             '-anchor' => 'nw',
235             '-side' => 'top',
236             '-fill' => 'x',
237             '-ipadx' => 0,
238             '-ipady' => 0,
239             '-padx' => 0,
240             '-pady' => 0,
241             );
242              
243             $l_Label->bind
244             (
245             '' => sub
246             {
247             $l_Label->focusPrev();
248             }
249             );
250              
251             $l_Label->bind
252             (
253             '' => sub
254             {
255             $l_Label->focusNext();
256             }
257             );
258              
259             $l_Label->bind
260             (
261             '' => sub
262             {
263             my $l_Header = $l_Popup->parent()->Subwidget ('Label');
264              
265             $this->Hide ($l_Header);
266             $l_Header->focusPrev();
267              
268             my $l_Next = $this->toplevel()->focusCurrent();
269             my $l_Found = 0;
270              
271             foreach my $l_Widget (@{$this->{m_MenuList}})
272             {
273             $l_Found = 1 if ($l_Next eq $l_Widget);
274             }
275              
276             $this->Show ($l_Next) if ($l_Found);
277             }
278             );
279              
280             $l_Label->bind
281             (
282             '' => sub
283             {
284             my $l_Header = $l_Popup->parent()->Subwidget ('Label');
285             $this->Hide ($l_Header);
286             $l_Header->focusNext();
287              
288             my $l_Next = $this->toplevel()->focusCurrent();
289             my $l_Found = 0;
290              
291             foreach my $l_Widget (@{$this->{m_MenuList}})
292             {
293             $l_Found = 1 if ($l_Next eq $l_Widget);
294             }
295              
296             $this->Show ($l_Next) if ($l_Found);
297             }
298             );
299              
300             $l_Label->bind
301             (
302             '' => sub
303             {
304             $l_Label->invoke();
305             }
306             );
307              
308             $this->EnableEntry
309             (
310             $p_Caption,
311             $p_EntryCaption
312             );
313             }
314              
315             sub MenuSeparator
316             {
317             my ($this, $p_Caption) = (shift, @_);
318              
319             unless (Exists ($this->Subwidget ($this->FixName ($p_Caption))))
320             {
321             $this->MenuLabel ($p_Caption);
322             return unless Exists ($this->Subwidget ($this->FixName ($p_Caption)));
323             }
324              
325             my $l_Popup = $this->Subwidget ($this->FixName ($p_Caption))->Subwidget ('Popup');
326              
327             my $l_Frame = $l_Popup->Frame
328             (
329             '-borderwidth' => 1,
330             '-relief' => 'flat',
331             );
332              
333             my $l_Separator = $l_Frame->Frame
334             (
335             '-borderwidth' => 1,
336             '-relief' => 'sunken',
337             '-height' => 2,
338             );
339              
340             $l_Separator->pack
341             (
342             '-anchor' => 'w',
343             '-side' => 'left',
344             '-fill' => 'x',
345             '-expand' => 'true',
346             );
347              
348             $l_Frame->pack
349             (
350             '-anchor' => 'nw',
351             '-expand' => 'true',
352             '-side' => 'top',
353             '-fill' => 'x',
354             );
355             }
356              
357             sub Show
358             {
359             my ($this, $p_Label) = (shift, @_);
360             my $l_Popup = $p_Label->parent()->Subwidget ('Popup');
361             my $l_Label = $p_Label;
362              
363             $this->Hide();
364              
365             $p_Label->parent()->configure
366             (
367             '-relief' => 'groove',
368             );
369              
370             my $l_CodeRef = sub
371             {
372             $l_Popup->raise(); # Tk::
373             $l_Popup->MapWindow();
374              
375             $l_Popup->geometry
376             (
377             '+'.
378             ($l_Label->rootx() - 1).
379             '+'.
380             ($l_Label->parent()->rooty() + $l_Label->parent()->height() + $l_Label->cget ('-borderwidth'))
381             );
382             };
383              
384             $this->toplevel()->bind
385             (
386             '' => $l_CodeRef
387             );
388              
389             &{$l_CodeRef}();
390              
391             $l_Popup->{'m_FocusRestore'} = $this->toplevel()->focusSave();
392             $l_Popup->transient();
393             $l_Popup->deiconify();
394             # $l_Popup->focus();
395             # $l_Popup->{'m_Focus'}->focus() if (Exists ($l_Popup->{'m_Focus'}));
396             }
397              
398             sub Hide
399             {
400             my ($this, $p_Label) = (shift, @_);
401              
402             if (defined ($p_Label))
403             {
404             my $l_Popup = $p_Label->parent()->Subwidget ('Popup');
405              
406             $this->toplevel()->bind
407             (
408             '' => ''
409             );
410              
411             $p_Label->parent()->configure
412             (
413             '-relief' => 'flat',
414             );
415              
416             &{$l_Popup->{'m_FocusRestore'}} if (ref ($l_Popup->{'m_FocusRestore'}) eq 'CODE');
417             delete $l_Popup->{'m_FocusRestore'};
418             $l_Popup->withdraw();
419             }
420             else
421             {
422             foreach my $l_Label (@{$this->{m_MenuList}})
423             {
424             $this->Hide ($l_Label);
425             }
426             }
427             }
428              
429             sub EnableEntry
430             {
431             my ($this, $p_MenuCaption, $p_EntryCaption) = (shift, @_);
432             my $l_Popup = $this->Subwidget ($this->FixName ($p_MenuCaption))->Subwidget ('Popup');
433             my $l_Label = $l_Popup->Subwidget ($this->FixName ($p_EntryCaption));
434              
435             $l_Label->{m_Enabled} = 'true';
436              
437             $l_Label->configure
438             (
439             '-activeforeground' => $this->cget ('-background'),
440             '-activebackground' => $this->cget ('-foreground'),
441             '-foreground' => $this->cget ('-foreground'),
442             '-background' => $this->cget ('-background'),
443             '-relief' => 'flat',
444             );
445             }
446              
447             sub DisableEntry
448             {
449             my ($this, $p_MenuCaption, $p_EntryCaption) = (shift, @_);
450             my $l_Popup = $this->Subwidget ($this->FixName ($p_MenuCaption))->Subwidget ('Popup');
451             my $l_Label = $l_Popup->Subwidget ($this->FixName ($p_EntryCaption));
452              
453             $l_Label->{m_Enabled} = 'false';
454              
455             $l_Label->configure
456             (
457             '-activeforeground' => $l_Label->Darken ($this->cget ('-background'), 80),
458             '-activebackground' => $this->cget ('-background'),
459             '-foreground' => $l_Label->Darken ($this->cget ('-background'), 80),
460             '-background' => $this->cget ('-background'),
461             '-relief' => 'flat',
462             );
463             }
464              
465             sub FixName
466             {
467             return (join ('_', split ('\.', $_[1])));
468             }
469              
470             1;
471              
472             __END__