File Coverage

blib/lib/Tk/TOTD.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Tk::TOTD;
2              
3 1     1   21006 use strict;
  1         2  
  1         40  
4 1     1   5 use warnings;
  1         2  
  1         29  
5 1     1   393 use Tk;
  0            
  0            
6             use Tk::ROText;
7             use Tk::DialogBox;
8             use Tk::Widget;
9              
10             our $VERSION = '0.4';
11              
12             Tk::Widget->Construct ('TOTD');
13              
14             sub new {
15             my $proto = shift;
16             my $mw = shift;
17             my $class = ref($proto) || $proto || 'Tk::TOTD';
18              
19             my $self = {
20             mw => $mw,
21             dialog => undef,
22             @_,
23             };
24              
25             bless ($self,$class);
26             return $self;
27             }
28              
29             sub Show {
30             my ($args) = @_;
31              
32             my $self = $args->{mw}->DialogBox (
33             -title => $args->{'-title'} || 'Tip Of The Day',
34             -background => $args->{'-background'} || '#BFBFBF',
35             -buttons => [],
36             );
37             $self->geometry ('460x260');
38             $self->resizable (0,0);
39              
40             # Keep a reference to get back to it later.
41             $args->{dialog} = $self;
42              
43             my $header = $args->{'-slogan'} || 'Did you know that...',
44              
45             my $totd;
46             if (exists $args->{'-image'}) {
47             $totd = $args->{'-image'};
48             }
49             else {
50             $totd = $self->Photo (-data => &hint, -format => 'gif');
51             }
52              
53             my @messages = (
54             'This is the Tk::TOTD module, for incorporating Tip Of The Day '
55             . 'functionality into any Perl/Tk program!',
56             "As you can see,\n\neven if your messages are\n\nVERY,\nVERY\n\n"
57             . "long,\n\na scrollbar is made available to see the rest\n\n"
58             . "of the contents\n\nof your tip!",
59             'If all tips are displayed, the queue starts over again to make the '
60             . 'tip rotation infinite.',
61             'If you use B<-checkvariable> you can have your program allow the user '
62             . 'to choose whether he/she wants to have your Tip Of The Day '
63             . 'pop up on every startup.',
64             'You can have as many tips as you like.',
65             'You can incorporate TOTD into a program with only one function call!',
66             'You can customize all the colors and fonts used in this dialog window--'
67             . 'even the labels such as "Did you know that..." and "Show tips '
68             . 'at startup"!',
69             'The messages are displayed randomly each time you spawn a TOTD window.',
70             'The number of the tip you are viewing and the whole number of tips is '
71             . 'displayed in the lower left edge of the window. This is to '
72             . 'help you keep track of which tips you have read and to know how '
73             . 'many to expect!',
74             'There are 10 tips here--so there\'s plenty for you to read!',
75             );
76              
77             if (exists $args->{'-messages'}) {
78             @messages = @{$args->{'-messages'}};
79             }
80              
81             $self->{colors} = {
82             bg => $args->{'-background'} || '#BFBFBF',
83             left => $args->{'-leftbackground'} || '#808080',
84             main => $args->{'-mainbackground'} || '#FFFFFF',
85             slide => $args->{'-slidecolor'} || '#FFFF99',
86             fg => $args->{'-foreground'} || '#000000',
87             };
88             $self->{fonts} = {
89             main => {
90             family => $args->{'-mainfont'} || 'Arial',
91             size => $args->{'-mainfontsize'} || 10,
92             },
93             title => {
94             family => $args->{'-titlefont'} || 'Times New Roman',
95             size => $args->{'-titlefontsize'} || 14,
96             },
97             };
98              
99             my $top = $self->Frame (
100             -width => 440,
101             -height => 200,
102             -background => $self->{colors}->{bg},
103             );
104             my $bot = $self->Frame (
105             -height => 40,
106             -width => 440,
107             -background => $self->{colors}->{bg},
108             );
109             $bot->pack (-side => 'bottom', -fill => 'both', -ipady => 3, -ipadx => 3);
110             $top->pack (-side => 'top', -fill => 'both', -pady => 10, -padx => 10, -expand => 1);
111              
112             my $pan = $top->Frame (
113             -width => 60,
114             -height => 200,
115             -border => 0,
116             -background => $self->{colors}->{left},
117             )->pack (-side => 'left', -fill => 'y', -pady => 0, -padx => 0, -expand => 1);
118              
119             $pan->Label (
120             -image => $totd,
121             -background => $self->{colors}->{left},
122             )->place (-x => 15, -y => 10);
123              
124             my $pos = $pan->Label (
125             -text => "1/" . scalar(@messages),
126             -foreground => $self->{colors}->{slide},
127             -background => $self->{colors}->{left},
128             -font => [
129             -family => $self->{fonts}->{main}->{family},
130             -size => $self->{fonts}->{main}->{size},
131             -weight => 'bold',
132             ],
133             )->place (-x => 15, -y => 170);
134              
135             my $main = $top->Frame (
136             -width => 380,
137             -height => 200,
138             -border => 0,
139             -background => $self->{colors}->{main},
140             )->pack (-side => 'right', -fill => 'both', -pady => 0, -padx => 0, -expand => 1);
141              
142             my $ttab = $main->Frame (
143             -width => 380,
144             -height => 50,
145             -border => 0,
146             -background => $self->{colors}->{main},
147             )->pack (-side => 'top', -fill => 'x', -pady => 0, -padx => 0, -expand => 1);
148              
149             my $title = $ttab->Label (
150             -text => $header,
151             -foreground => $self->{colors}->{fg},
152             -background => $self->{colors}->{main},
153             -font => [
154             -family => $self->{fonts}->{title}->{family},
155             -size => $self->{fonts}->{title}->{size},
156             -weight => 'bold',
157             ],
158             )->place (-x => 25, -y => 10);
159              
160             my $mtab = $main->Frame (
161             -width => 380,
162             -height => 125,
163             -border => 0,
164             -background => $self->{colors}->{main},
165             )->pack (-side => 'bottom', -fill => 'both', -pady => 0, -padx => 0, -expand => 1);
166              
167             my $pod = $mtab->Scrolled ('ROText',
168             -foreground => $self->{colors}->{fg},
169             -background => $self->{colors}->{main},
170             -scrollbars => 'e',
171             -wrap => 'word',
172             -relief => 'flat',
173             -font => [
174             -family => $self->{fonts}->{main}->{family},
175             -size => $self->{fonts}->{main}->{size},
176             ],
177             )->pack (-fill => 'both', -expand => 1);
178              
179             my $void = 1;
180              
181             my $bl = $bot->Frame (
182             -height => 40,
183             -background => $self->{colors}->{bg},
184             );
185             my $br = $bot->Frame (
186             -height => 40,
187             -background => $self->{colors}->{bg},
188             );
189             $bl->pack (-side => 'left', -fill => 'both', -ipady => 0, -ipadx => 0, -expand => 1);
190             $br->pack (-side => 'right', -fill => 'both', -ipady => 0, -ipadx => 0, -expand => 1);
191              
192             my $checkbox = $bl->Checkbutton (
193             -text => $args->{'-checklabel'} || 'Show tips at startup',
194             -variable => $args->{'-checkvariable'} || \$void,
195             -foreground => $self->{colors}->{fg},
196             -background => $self->{colors}->{bg},
197             -activeforeground => $self->{colors}->{fg},
198             -activebackground => $self->{colors}->{bg},
199             -onvalue => 1,
200             -offvalue => 0,
201             -font => [
202             -family => $self->{fonts}->{main}->{family},
203             -size => $self->{fonts}->{main}->{size},
204             ],
205             )->place (-x => 10, -y => 15);
206              
207             # Shuffle the messages array.
208             srand;
209             my @new = ();
210             while (@messages) {
211             push (@new, splice (@messages, rand @messages, 1));
212             }
213             (@messages) = (@new);
214              
215             # Begin keeping track of things.
216             my $index = 0;
217             $pod->insert ('end',$messages[0]);
218              
219             my $close = $br->Button (
220             -text => $args->{'-closebutton'} || 'Close',
221             -foreground => $self->{colors}->{fg},
222             -background => $self->{colors}->{bg},
223             -activeforeground => $self->{colors}->{fg},
224             -activebackground => $self->{colors}->{bg},
225             -font => [
226             -family => $self->{fonts}->{main}->{family},
227             -size => $self->{fonts}->{main}->{size},
228             ],
229             -command => sub {
230             $self->{'selected_button'} = 'Close';
231             },
232             )->pack (-side => 'right', -padx => 10);
233              
234             my $next = $br->Button (
235             -text => $args->{'-nextbutton'} || 'Next Tip',
236             -foreground => $self->{colors}->{fg},
237             -background => $self->{colors}->{bg},
238             -activeforeground => $self->{colors}->{fg},
239             -activebackground => $self->{colors}->{bg},
240             -font => [
241             -family => $self->{fonts}->{main}->{family},
242             -size => $self->{fonts}->{main}->{size},
243             ],
244             -command => sub {
245             $index++;
246             my $num = $index + 1;
247              
248             if ($num > scalar(@messages)) {
249             $num = 1;
250             $index = 0;
251             }
252              
253             $pos->configure (-text => "$num/" . scalar(@messages));
254              
255             my $data = $messages[$index];
256             $pod->delete ('1.0','end');
257             $pod->insert ('end',$data);
258             $pod->insert ('end',"\n");
259             $self->update;
260             },
261             )->pack (-side => 'right', -padx => 5);
262              
263             $self->Show;
264             }
265              
266             sub configure {
267             my ($cw,%args) = @_;
268              
269             foreach my $arg (keys %args) {
270             $cw->{$arg} = $args{$arg};
271             }
272             }
273              
274             sub hint {
275             return 'R0lGODlhFwAfAOYAAAAAAICAAP//AAD//8DAwP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
276             AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
277             AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
278             AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
279             AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
280             AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
281             AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yH5
282             BAEAAH8ALAAAAAAXAB8AAAfVgH+Cg4SFhoeEAYqKiIiKApCQjI2DAQIFl5mYAZR/lgWgfwB/mJCj
283             jpegBQCsmgKnhgGqoKwAmKWwiamqta4BuYKfs6KkmQK/sbeztr7AnpG3r67Hzpau0dHIhgCRl8Sl
284             1IgA1pi9t9qH45HEkeiHA+rXv/CIA6vW3dQF9IX2tI+SfqniJ8hfKFaLas2iB8BgKFqsCBCwtXBU
285             w2GiCkhUOBDWRVWkak2sWOhjAUEaJ1Lc50yUwVqsOjYyyZFlJ5MkO7mcZVOnIJMEfe4MKtRlS6FH
286             BwUCADs=
287             ';
288             }
289              
290             sub Exit {
291             my $cw = shift;
292              
293             undef $cw;
294             }
295              
296             sub destroy {
297             my $self = shift;
298              
299             if ($self->{dialog}) {
300             $self->{dialog}->{selected_button} = 'Close';
301             }
302             }
303              
304             =head1 NAME
305              
306             Tk::TOTD - Tip Of The Day dialog for Perl/Tk.
307              
308             =head1 SYNOPSIS
309              
310             use Tk::TOTD;
311              
312             my $top = MainWindow->new();
313              
314             my $totd = $top->TOTD (
315             -title => 'Tip Of The Day -- MyPerlApp',
316             -messages => \@messages,
317             );
318              
319             $totd->Show;
320              
321             =head1 DESCRIPTION
322              
323             Tk::TOTD provides a simple Tip of the Day dialog for Perl/Tk programs.
324              
325             =head1 OPTIONS
326              
327             The options recognized by B are as follows:
328              
329             =over 4
330              
331             =item B<-title>
332              
333             Specify the title of the Tip Of The Day dialog. Defaults to "Tip Of The Day"
334              
335             =item B<-messages>
336              
337             The array of tip messages. If omitted, a default 10 tips about this module
338             will be used instead.
339              
340             =item B<-slogan>
341              
342             Set the slogan at the top of the dialog. Default is "Did you know that..."
343              
344             =item B<-image>
345              
346             A L object. If omitted, the default totd image is used. This default
347             image is appropriate for most TOTD usages, but if you use this as something other
348             than a Tip Of The Day you may want to use your own image. The default image's
349             dimensions are B<23x31>.
350              
351             =item B<-background>
352              
353             The main window's background color. Defaults to #BFBFBF
354              
355             =item B<-leftbackground>
356              
357             Background color for the left panel (where the image and slide number is). Defaults
358             to #808080
359              
360             =item B<-mainbackground>
361              
362             The background color of the main content area. Defaults to #FFFFFF (white).
363              
364             =item B<-slidecolor>
365              
366             The text color of the slide number (as on the left panel). Defaults to #FFFF99.
367              
368             =item B<-foreground>
369              
370             Main foreground color of text. Defaults to #000000 (black).
371              
372             =item B<-mainfont>
373              
374             The main font family used on most of the labels. Defaults to Arial.
375              
376             =item B<-mainfontsize>
377              
378             Font size of the main font. Defaults to 10.
379              
380             =item B<-titlefont>
381              
382             The font family used on the slogan text. Defaults to Times New Roman.
383              
384             =item B<-titlefontsize>
385              
386             Font size on the slogan text. Defaults to 14.
387              
388             =item B<-checklabel>
389              
390             The label on the checkbutton. Defaults to "Show tips at startup"
391              
392             =item B<-checkvariable>
393              
394             The variable to store the state of the checkbutton. 1 for checked, 0 for not.
395              
396             =item B<-closebutton>
397              
398             The text of the close button. Defaults to "Close"
399              
400             =item B<-nextbutton>
401              
402             The text of the next button. Defaults to "Next Tip"
403              
404             =back
405              
406             =head1 METHODS
407              
408             =over 4
409              
410             =item B
411              
412             Displays the Tip Of The Day dialog. The TOTD dialog is based from Tk::DialogBox
413             and therefore will pause your main window.
414              
415             =item B
416              
417             Reconfigure previously set options.
418              
419             =item B
420              
421             Completely clean up the TOTD DialogBox. This method is a workaround for an
422             underlying bug in C wherein if a DialogBox is open, and you
423             close the C by clicking on the "X" button from the window manager,
424             your program doesn't exit completely because the DialogBox is waiting on a
425             variable that's only set when a button has been clicked.
426              
427             You can work around this bug by calling C on your C
428             object when your C is exited.
429              
430             $mw->protocol('WM_DELETE_WINDOW', sub {
431             $totd->destroy();
432             exit(0);
433             });
434              
435             =back
436              
437             =head1 CHANGES
438              
439             Version 0.4 - Nov 11 2013
440             - Add the destroy() method to allow for a workaround to a bug in
441             Tk::DialogBox.
442              
443             Version 0.3 - Nov 1 2013
444             - Fix a bug where using the "Close" button on the dialog wouldn't dismiss the
445             dialog properly, and the program would never exit gracefully again.
446              
447             Version 0.2 - Jan 16 2005
448             - The widget now behaves as a DialogBox as it should, blocking the main window
449             until closed.
450              
451             =head1 BUGS
452              
453             None known yet.
454              
455             =head1 AUTHOR
456              
457             Noah Petherbridge, http://www.kirsle.net/
458              
459             This code is distributed under the same terms as Perl.
460              
461             =cut
462              
463             1;