File Coverage

blib/lib/Tk/StyleDialog.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             ################################################################################
2             # Tk::StyleDialog - Stylish Dialogboxes with Custom Icons #
3             ################################################################################
4             package Tk::StyleDialog;
5              
6 1     1   38613 use strict;
  1         3  
  1         79  
7 1     1   6 use warnings;
  1         2  
  1         32  
8 1     1   469 use Tk;
  0            
  0            
9             use Tk::Toplevel;
10             use Tk::PNG;
11             use Tk::Widget;
12              
13             our $VERSION = '0.04';
14             Tk::Widget->Construct ('StyleDialog');
15              
16             # CORE Built-in icons.
17             # attention, error, info, question
18             our $BUILTIN_ICONS = {
19             'attention' => 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiBAMAAAG/biZnAAAAElBMVEUAAACAgACZmZnAwMD//wAA
20             AABjkWUwAAAAAXRSTlMAQObYZgAAAPNJREFUKM9lkEsOgzAMRA3KAVrJ7KOcoAvYV2DvEU3uf5X6
21             BwqtJZAZXjzjAGi9AVKTpwKMxZS0Q3oDsX0Pq0pYs7Q0y0ci2jLASco/JZjlP1OGtNEOyLQCkbzG
22             UmxoesURkeN04rqGxNXFpN3qlFZ2u0omNqtymkfhfk2OcRKUT4/LDZf5CKyF7yAdh++EDiIx0eEJ
23             2G0Hi8KeRfIpiNLNBqInlW6IfAC2demCPh/wE5q24yaoyVLuiGx+5DtyhyRsaz0kiCodhKFckE7Z
24             2qebZBtMnV0s3Nn5kouecsgR0skBhRLFJV9XQ37KrsMv5iz4ry/n4U7to4iyMAAAAABJRU5ErkJg
25             gg==',
26             'error' => 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiBAMAAAG/biZnAAAAD1BMVEUAAAD/AACZmZn///9gAADt
27             zF8pAAAAAXRSTlMAQObYZgAAAPVJREFUKM9dko2twyAMhGmUAd4BAyD0FrBYoETsP1PPP7RNLSVx
28             Ps7mcJIS4wFe0uyZmpKEmoA0s70DTwpKgd9JJnryOGHF+EsYwqLC25SR2QxZS6k+WiiXlUxoGBmC
29             oTKKxwBq80w0O1HgqwptkXGs1Vu6xzKDvkWktkXdSNTFg83K0OVJl9wjmxXdNzKJrARjhRTB5bWw
30             LDr3fY6sZo6Nbv6Ob6OL8e3Zh2AWP9Y9njfF5+gE9A83Wt9k+MTMgHUhMgD1631LAFwtiGpuhIri
31             6GoxGIn2VQ9y2hy1l0r6r8M469pg9f2H/Btb1xvoZCx+v2PEC2oELiZOaMTkAAAAAElFTkSuQmCC',
32             'info' => 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiBAMAAADIaRbxAAAAD1BMVEVlYXIAAP+ZmZn///8AAADI
33             hm6AAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElN
34             RQfVAQUJAhHTzodBAAAAn0lEQVQoz63S0Q3EIAgAUGNcgNwChusCrQ5wUfef6UQQzHn9Kx9tfEGi
35             oHM3gT3WtcfUA6PBO424lAQ6zRRaAND3YyknwKv/sqWIcBJX4V2cpHWHRNlkUaaA1DFJKvEx0RMO
36             yfhX/CpldLLyCYky9zYsd5DOVr3nbH8QykWbfzSCVmxCHlulLet88CCJ6xBJfuZcNwmbuLaJx/3F
37             3D2lL2ZNO/7TbRBBAAAAAElFTkSuQmCC',
38             'question' => 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiBAMAAADIaRbxAAAAD1BMVEVlYXIAAP+ZmZn///8AAADI
39             hm6AAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACy8AAAsTAXMiW84AAAAHdElN
40             RQfVAQUINxbuWbpjAAAAp0lEQVQoz4XS0Q3EIAgGYGNcgLiA4bpAiwNc1P1nOrQIpqY5Xpp++dEU
41             6txLIdf67pG4MBl8aNSlJMA0I6T1tcgJEPmRLRIJQEMjEjmlobspiiRpUqEybwI5x0SOYUkm9JT4
42             X2axyHdKJqOKXD7Er1LGJKt15Xu2YTlXJlsn5Dn+IJSLDv9oHVqxDXlstbes+8GjS1qX2OWx57pJ
43             2MS1TTzuf8zbr/QD5Iw9gr+vgAwAAAAASUVORK5CYII=',
44             };
45              
46             sub new {
47             my $proto = shift;
48             my $mw = shift;
49             my $class = ref($proto) || $proto || 'Tk::StyleDialog';
50              
51             my $self = {
52             mw => $mw,
53             @_,
54             };
55              
56             bless ($self,$class);
57             return $self->Show;
58             }
59              
60             sub Show {
61             my ($args) = @_;
62              
63             # Args:
64             # mw = parent window
65             # -title = Dialog Title
66             # -text = Dialog message text
67             # -icon = The icon to use inside the dialog
68             # -buttons = Arrayref of button labels
69             # -default_button = The default button
70             # -button_states = Arrayref of button states (normal|disabled)
71              
72             # Prepare default arguments.
73             my $title = 'Error';
74             my $text = 'An error has occurred.';
75             my $icon = 'error';
76             my $center = 1;
77             my $winicon = 'error';
78             my $winmask = 'error';
79             my $buttons = [ ' Ok ' ];
80             my $default_button = undef;
81             my $cancel_button = undef;
82             my $button_states = [];
83             my $standalone = 0;
84             my $grab = '';
85              
86             # Collect args.
87             $title = delete $args->{'-title'} if exists $args->{'-title'};
88             $text = delete $args->{'-text'} if exists $args->{'-text'};
89             $icon = delete $args->{'-icon'} if exists $args->{'-icon'};
90             $center = delete $args->{'-center'} if exists $args->{'-center'};
91             $winicon = delete $args->{'-winicon'} if exists $args->{'-winicon'};
92             $winmask = delete $args->{'-winmask'} if exists $args->{'-winmask'};
93             $buttons = delete $args->{'-buttons'} if exists $args->{'-buttons'};
94             $default_button = delete $args->{'-default_button'} if exists $args->{'-default_button'};
95             $cancel_button = delete $args->{'-cancel_button'} if exists $args->{'-cancel_button'};
96             $button_states = delete $args->{'-button_states'} if exists $args->{'-button_states'};
97             $standalone = delete $args->{'-standalone'} if exists $args->{'-standalone'};
98             $grab = delete $args->{'-grab'} if exists $args->{'-grab'};
99              
100             # Default default button = the first button.
101             $default_button = $buttons->[0] unless defined $default_button;
102              
103             # Default cancel button = the last button.
104             $cancel_button = $buttons->[-1] unless defined $cancel_button;
105              
106             # Internal variables.
107             my $selectedbutton = undef;
108              
109             #######################################################
110             ## Create the Dialog Window ##
111             #######################################################
112              
113             # Create the window.
114             my $win = $args->{mw}->Toplevel (
115             -title => $title || 'Error',
116             );
117              
118             # Handle the clicking of the "X" button.
119             $win->protocol ('WM_DELETE_WINDOW' => sub {
120             $selectedbutton = $cancel_button;
121             });
122              
123             # Handle keypresses.
124             $win->bind ('', sub {
125             $selectedbutton = $default_button;
126             });
127             $win->bind ('', sub {
128             $selectedbutton = $default_button;
129             });
130             $win->bind ('', sub {
131             $selectedbutton = $cancel_button;
132             });
133              
134             # Unless standalone, make it a child of the main window.
135             unless ($standalone) {
136             $win->transient ($win->Parent->toplevel);
137             }
138              
139             # Divide the window into frames.
140             my $bottom_frame = $win->Frame->pack (-side => 'bottom', -fill => 'x');
141             my $top_half = $win->Frame->pack (-side => 'bottom', -fill => 'both', -expand => 1);
142             my $icon_frame = $top_half->Frame->pack (-side => 'left', -fill => 'y');
143             my $label_frame = $top_half->Frame->pack (-side => 'left', -fill => 'both', -expand => 1);
144             my $button_frame = $bottom_frame->Frame->pack (-side => 'top', -fill => 'y');
145              
146             #######################################################
147             ## Button Frame ##
148             #######################################################
149              
150             # Draw the window buttons.
151             for (my $i = 0; $i < scalar @{$buttons}; $i++) {
152             my $label = $buttons->[$i];
153              
154             # Get this button's state.
155             my $state = 'normal';
156             if (scalar @{$button_states} > $i) {
157             $state = (defined $button_states->[$i] ? $button_states->[$i] : 'normal');
158             }
159              
160             # If this is the default button, draw a border around it.
161             if ($label eq $default_button) {
162             my $border = $button_frame->Frame (
163             -background => '#000000',
164             )->pack (-side => 'left', -padx => 10, -pady => 10);
165             my $btn = $border->Button (
166             -text => $label,
167             -state => $state,
168             -command => sub {
169             $selectedbutton = $label;
170             },
171             -highlightthickness => 0,
172             )->pack (-side => 'top', -padx => 1, -pady => 1);
173             }
174             else {
175             my $btn = $button_frame->Button (
176             -text => $label,
177             -state => $state,
178             -command => sub {
179             $selectedbutton = $label;
180             },
181             -highlightthickness => 0,
182             )->pack (-side => 'left', -padx => 10, -pady => 10);
183             }
184             }
185              
186             #######################################################
187             ## Icon Frame ##
188             #######################################################
189              
190             # If they gave us a Photo object, use it.
191             my $photo = undef;
192             if (ref($icon)) {
193             $photo = $icon;
194             }
195             else {
196             # Get the internal one. Does it exist?
197             if (!exists $BUILTIN_ICONS->{$icon}) {
198             # Load Tk::StyleDialog::Builtins.
199             require Tk::StyleDialog::Builtins;
200             }
201             $icon = 'error' unless exists $BUILTIN_ICONS->{$icon};
202              
203             if (exists $BUILTIN_ICONS->{$icon}) {
204             $photo = $win->Photo (
205             -data => $BUILTIN_ICONS->{$icon},
206             -format => 'PNG',
207             -width => 34,
208             -height => 34,
209             );
210             }
211             }
212              
213             my $iconimg = $icon_frame->Label (
214             -image => $photo,
215             -border => 0,
216             )->pack (-side => 'top', -pady => 10, -padx => 20);
217              
218             #######################################################
219             ## Label Frame ##
220             #######################################################
221              
222             my $label = $label_frame->Label (
223             -text => $text,
224             -justify => 'left',
225             )->pack (-side => 'top', -anchor => 'nw', -pady => 20, -padx => 10);
226              
227             # Update the window to get realistic dimensions.
228             $win->withdraw;
229             $win->update;
230              
231             # Center the window?
232             if ($center) {
233             my $screenwidth = $args->{mw}->screenwidth;
234             my $screenheight = $args->{mw}->screenheight;
235             my $posX = ($screenwidth - $win->width) / 2;
236             my $posY = ($screenheight - $win->height) / 2;
237             $win->MoveToplevelWindow (int($posX),int($posY));
238             }
239              
240             # Set the minsize to be its default size.
241             $win->minsize ($win->width,$win->height);
242              
243             # Set the app icon.
244             $win->Icon (-image => $photo);
245              
246             $win->deiconify;
247              
248             # Grab.
249             if ($grab eq 'global') {
250             $win->grabGlobal;
251             }
252             else {
253             $win->grab;
254             }
255              
256             # Wait for a button.
257             $win->focusForce;
258             $win->waitVariable (\$selectedbutton);
259             $win->destroy;
260              
261             # Return the selected button.
262             return $selectedbutton;
263             }
264              
265             1;
266             __END__