File Coverage

blib/lib/Tk/ColoredButton.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 100.0


line stmt bran cond sub pod time code
1             package Tk::ColoredButton;
2            
3 1     1   25226 use warnings;
  1         2  
  1         33  
4 1     1   5 use strict;
  1         2  
  1         33  
5 1     1   5 use Carp;
  1         6  
  1         89  
6            
7             #====================================================================
8             # $Author : Djibril Ousmanou $
9             # $Copyright : 2011 $
10             # $Update : 18/07/2011 02:07:06 $
11             # $AIM : Create gradient background color on a button $
12             #====================================================================
13            
14 1     1   5 use vars qw($VERSION);
  1         2  
  1         68  
15             $VERSION = '1.05';
16            
17 1     1   5 use base qw/Tk::Derived Tk::Canvas::GradientColor/;
  1         2  
  1         720  
18             use Tk::Balloon;
19             use English '-no_match_vars';
20            
21             Construct Tk::Widget 'ColoredButton';
22            
23             # Id => widget balloon
24             my %all_balloon;
25             my $count = 1;
26            
27             my ( $system_button_face, $system_button_text, $system_disabled_text, $active_background, $default_font )
28             = ();
29             my $FLASH_INTERVALL = 300;
30             my $TEXTVARIABLE_INTERVALL = 300;
31             my $DASH = q{.};
32             my $SPACE = q{ };
33             my $INITWAIT = 350;
34             my $SPACE_PLUS = 4;
35            
36             # Default Colors for all OS
37             if ( $OSNAME eq 'MSWin32' ) {
38             $system_button_face = 'SystemButtonFace';
39             $active_background = $system_button_face;
40             $system_button_text = 'SystemButtonText';
41             $system_disabled_text = 'SystemDisabledText';
42             $default_font = '{MS Sans Serif} 8';
43             }
44             else {
45             $system_button_face = '#D9D9D9';
46             $active_background = '#ECECEC';
47             $system_button_text = 'black';
48             $system_disabled_text = '#A3A3A3';
49             $default_font = '{Helvetica} 12 {bold}';
50             }
51            
52             my %config = (
53             balloon_tooltip => undef,
54             tags => {
55             all => '_cb_tag',
56             text => '_cb_text_tag',
57             image => '_cb_image_tag',
58             bitmap => '_cb_bitmap_tag',
59             font => '_cb_font_tag',
60             focusin => '_cb_focusin_tag',
61             focusout => '_cb_focusout_tag',
62             font => '_cb_font_tag'
63             },
64             button => { press => 0, },
65             ids => { flash => undef, id_repeatdelay => undef },
66             specialbutton => {
67             -background => $system_button_face,
68             -borderwidth => 2,
69             -height => 20,
70             -highlightthickness => 0,
71             -relief => 'raised',
72             -state => 'normal',
73             -width => 80,
74             },
75             '-activebackground' => $active_background,
76             '-activeforeground' => $system_button_text,
77             '-activegradient' => { -start_color => '#FFFFFF', -end_color => '#B2B2B2' },
78             '-anchor' => 'center',
79             '-bitmap' => undef,
80             '-gradient' => { -start_color => '#B2B2B2', -end_color => '#FFFFFF' },
81             '-command' => undef,
82             '-compound' => 'none',
83             '-disabledforeground' => $system_disabled_text,
84             '-font' => $default_font,
85             '-foreground' => $system_button_text,
86             '-highlightbackground' => undef,
87             '-image' => undef,
88             '-justify' => 'center',
89             '-overrelief' => undef,
90             '-padx' => 1,
91             '-pady' => 1,
92             '-relief' => 'raised',
93             '-textvariable' => undef,
94             '-tooltip' => undef,
95             '-wraplength' => 0,
96             );
97            
98             sub Populate {
99             my ( $cw, $ref_parameters ) = @_;
100            
101             $cw->SUPER::Populate($ref_parameters);
102             $cw->Advertise( 'GradientColor' => $cw );
103             $cw->Advertise( 'canvas' => $cw->SUPER::Canvas );
104             $cw->Advertise( 'Canvas' => $cw->SUPER::Canvas );
105            
106             $cw->{_cb_id} = $count;
107             $cw->{_conf_cb}{$count} = \%config;
108            
109             # Default widget configuration
110             foreach ( keys %{ $config{specialbutton} } ) {
111             if ( defined $config{specialbutton}{$_} ) { $cw->configure( $_ => $config{specialbutton}{$_} ); }
112             }
113            
114             # ConfigSpecs
115             $cw->ConfigSpecs(
116             -activebackground => [ 'PASSIVE', 'activeBackground', 'ActiveBackground', $active_background ],
117             -activegradient => [
118             'PASSIVE', 'activeGradient',
119             'ActiveGradient', { -start_color => '#FFFFFF', -end_color => '#B2B2B2' }
120             ],
121             -activeforeground => [ 'PASSIVE', 'activeForeground', 'ActiveForeground', $system_button_text ],
122             -autofit => [ 'PASSIVE', 'autofit', 'Autofit', '0' ],
123             -anchor => [ 'PASSIVE', 'anchor', 'Anchor', 'center' ],
124             -bitmap => [ 'PASSIVE', 'bitmap', 'Bitmap', undef ],
125             -command => [ 'PASSIVE', 'command', 'Command', undef ],
126             -compound => [ 'PASSIVE', 'compound', 'Compound', 'none' ],
127             -disabledforeground => [ 'PASSIVE', 'disabledForeground', 'DisabledForeground', $system_disabled_text ],
128             -font => [ 'PASSIVE', 'font', 'Font', $default_font ],
129             -foreground => [ 'PASSIVE', 'foreground', 'Foreground', $system_button_text ],
130             -gradient =>
131             [ 'PASSIVE', 'gradient', 'Gradient', { -start_color => '#B2B2B2', -end_color => '#FFFFFF' } ],
132             -image => [ 'PASSIVE', 'image', 'Image', undef ],
133             -imagedisabled => [ 'PASSIVE', 'imageDisabled', 'ImageDisabled', undef ],
134             -justify => [ 'PASSIVE', 'justify', 'Justify', 'center' ],
135             -overrelief => [ 'PASSIVE', 'overRelief', 'OverRelief', undef ],
136             -padx => [ 'PASSIVE', 'padx', 'Padx', 1 ],
137             -pady => [ 'PASSIVE', 'pady', 'Pady', 1 ],
138             -state => [ 'PASSIVE', 'state', 'State', 'normal' ],
139             -repeatdelay => [ 'PASSIVE', 'repeatDelay', 'RepeatDelay', undef ],
140             -repeatinterval => [ 'PASSIVE', 'repeatInterval', 'RepeatInterval', undef ],
141             -text => [ 'PASSIVE', 'text', 'Text', $SPACE ],
142             -textvariable => [ 'PASSIVE', 'textVariable', 'TextVariable', undef ],
143             -tooltip => [ 'PASSIVE', 'tooltip', 'Tooltip', undef ],
144             -wraplength => [ 'PASSIVE', 'wrapLength', 'WrapLength', 0 ],
145             );
146            
147             $cw->Delegates( DEFAULT => $cw );
148            
149             foreach my $key (qw/ Down End Home Left Next Prior Right Up /) {
150             $cw->Tk::bind( 'Tk::ColoredButton', "", undef );
151             $cw->Tk::bind( 'Tk::ColoredButton', "", undef );
152             }
153             $cw->Tk::bind( '', \&_press_button );
154             $cw->Tk::bind( '', \&_press_leave );
155             $cw->Tk::bind( '', \&_enter );
156             $cw->Tk::bind( '', \&_leave );
157             $cw->Tk::bind( '', \&_create_bouton );
158             $cw->Tk::bind( '', \&_focus_in );
159             $cw->Tk::bind( '', \&_focus_out );
160            
161             foreach my $key (qw/ Return space /) {
162             $cw->Tk::bind( "", sub { $cw->invoke; } );
163             $cw->Tk::bind( "", sub { $cw->invoke; } );
164             }
165            
166             $count++;
167             return;
168             }
169            
170             sub redraw_button {
171             my $cw = shift;
172            
173             # Simulate press_leave and leave button
174             my $button_press = $config{ $cw->{_cb_id} }{button}{press};
175             if ( $button_press and $button_press == 1 ) { $cw->_leave; }
176             $cw->_create_bouton;
177            
178             return;
179             }
180            
181             sub invoke {
182             my $cw = shift;
183            
184             my $state = $cw->cget( -state );
185             return if ( $state eq 'disabled' );
186            
187             $cw->_command( $cw->cget( -command ) );
188            
189             return;
190             }
191            
192             sub flash {
193             my ( $cw, $interval ) = @_;
194            
195             my $state = $cw->cget( -state );
196             return if ( $state eq 'disabled' );
197            
198             my $id_flash = $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{-flash};
199            
200             if ( defined $id_flash ) {
201             $cw->itemconfigure( $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text}, -fill => $cw->cget( -foreground ) );
202            
203             $id_flash->cancel;
204             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{-flash} = undef;
205             }
206             if ( defined $interval and $interval == 0 ) { return; }
207            
208             if ( not defined $interval ) { $interval = $FLASH_INTERVALL; }
209            
210             my $i = 0;
211             $id_flash = $cw->repeat(
212             $interval,
213             sub {
214             if ( !Tk::Exists $cw ) { return; }
215             if ( $i % 2 == 0 ) {
216             $cw->itemconfigure( $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text},
217             -fill => $cw->cget( -disabledforeground ) );
218             }
219             else {
220             $cw->itemconfigure( $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text}, -fill => $cw->cget( -foreground ) );
221             }
222             $i++;
223             }
224             );
225             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{-flash} = $id_flash;
226            
227             return $id_flash;
228             }
229            
230             sub delete_tooltip {
231             my $cw = shift;
232            
233             my $id = $cw->{_cb_id};
234             if ( $id and exists $all_balloon{$id} and Tk::Exists $all_balloon{$id} ) {
235             $cw->configure( -tooltip => '' );
236             $all_balloon{$id}->configure( -state => 'none' );
237             $all_balloon{$id}->detach($cw);
238             $all_balloon{$id}->destroy;
239             $all_balloon{$id} = undef;
240             }
241            
242             return;
243             }
244            
245             sub _sets_options {
246             my ($cw) = @_;
247            
248             #===============================Configuration========================
249             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-background} = $cw->cget( -background );
250             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-borderwidth} = $cw->cget( -borderwidth );
251             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-height} = $cw->cget( -height );
252             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-relief} = $cw->cget( -relief );
253             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-state} = $cw->cget( -state );
254             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-width} = $cw->cget( -width );
255             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-cursor} = $cw->cget( -cursor );
256             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-highlightcolor} = $cw->cget( -highlightcolor );
257             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-highlightthickness} = $cw->cget( -highlightthickness );
258             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-takefocus} = $cw->cget( -takefocus );
259            
260             my $gradient = $cw->cget( -gradient );
261             my $activegradient = $cw->cget( -activegradient );
262            
263             if ( defined $gradient ) {
264             my $ref = ref $gradient;
265             if ( $ref ne 'HASH' ) {
266             croak('You have to set a hash reference to -gradient option');
267             }
268             }
269             if ( defined $activegradient ) {
270             my $ref = ref $activegradient;
271             if ( $ref ne 'HASH' ) {
272             croak('You have to set a hash reference to -activegradient option');
273             }
274             }
275            
276             return;
277             }
278            
279             sub _create_bouton {
280             my ($cw) = @_;
281            
282             # clear button
283             $cw->_clear_button;
284            
285             # configure all options
286             $cw->_sets_options;
287            
288             # For background gradient color
289             my $ref_gradient = $cw->cget( -gradient );
290             $cw->set_gradientcolor( %{$ref_gradient} );
291            
292             # Create text
293             $cw->_text();
294            
295             # Create image
296             $cw->_image_bitmap();
297            
298             # Create tooltip
299             $cw->_tooltip();
300            
301             # autofit
302             my $autofit = $cw->cget( -autofit );
303             if ( $autofit and $autofit == 1 ) {
304             $cw->_autofit_resize;
305             }
306            
307             return;
308             }
309            
310             sub _clear_button {
311             my $cw = shift;
312            
313             foreach ( $cw->find('all') ) {
314             $cw->delete($_);
315             }
316             $cw->delete('all');
317            
318             return;
319             }
320            
321             sub _enter {
322             my $cw = shift;
323            
324             # mouse over the button
325             $config{ $cw->{_cb_id} }{button}{enter} = 1;
326             my $press_button = $config{ $cw->{_cb_id} }{button}{press};
327             my $state = $cw->cget( -state );
328             my $tag_text = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text};
329             my $background = $cw->cget( -background );
330             $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-background} = $background;
331            
332             return if ( $state eq 'disabled' );
333            
334             if ( defined $press_button and $press_button == 1 ) {
335             $cw->_press_button;
336             }
337            
338             # -background
339             $cw->configure( -background => $cw->cget( -activebackground ) );
340            
341             # -gradient
342             $cw->set_gradientcolor( %{ $cw->cget( -activegradient ) } );
343            
344             # -overrelief
345             if ( my $overrelief = $cw->cget( -overrelief ) ) {
346             $cw->configure( -relief => $overrelief );
347             }
348            
349             # -activeforeground
350             if ( my $activeforeground = $cw->cget( -activeforeground ) ) {
351             $cw->itemconfigure( $tag_text, -fill => $activeforeground );
352             }
353            
354             return;
355             }
356            
357             sub _focus_in {
358             my ($cw) = @_;
359            
360             my $borderwidth = $cw->cget( -borderwidth );
361             my $focusin_tag = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{focusin};
362             my $height = $cw->cget( -height );
363             my $tag_all = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{all};
364             my $width = $cw->cget( -width );
365            
366             my $id_image = $cw->createRectangle(
367             $borderwidth + 1, $borderwidth + 1, $width - $borderwidth + 1, $height - $borderwidth + 1,
368             -tags => [ $tag_all, $focusin_tag ],
369             -dash => $DASH,
370             );
371            
372             return;
373             }
374            
375             sub _focus_out {
376             my ($cw) = @_;
377            
378             my $focusin_tag = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{focusin};
379             if ( $cw->find( 'withtag', $focusin_tag ) ) {
380             $cw->delete($focusin_tag);
381             }
382            
383             return;
384             }
385            
386             sub _leave {
387             my $cw = shift;
388            
389             # mouse not over the button
390             $config{ $cw->{_cb_id} }{button}{enter} = 0;
391            
392             my $foreground = $cw->cget( -foreground );
393             my $state = $cw->cget( -state );
394             my $tag_text = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text};
395             return if ( $state eq 'disabled' );
396            
397             # -background
398             $cw->configure( -background => $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-background} );
399            
400             # -gradient
401             my $gradient = $cw->cget( -gradient );
402             $cw->set_gradientcolor( %{$gradient} );
403            
404             # -overrelief
405             if ( my $overrelief = $cw->cget( -overrelief ) ) {
406             $cw->configure( -relief => $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-relief} );
407             }
408            
409             $cw->itemconfigure( $tag_text, -fill => $foreground );
410            
411             my $id_repeatdelay = $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay};
412             if ( defined $id_repeatdelay ) {
413             $id_repeatdelay->cancel;
414             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay} = undef;
415             }
416            
417             # press_leave set by leave button (just relief)
418             $cw->_press_leave('leave');
419            
420             return;
421             }
422            
423             sub _press_button {
424             my $cw = shift;
425            
426             my $state = $cw->cget( -state );
427             return if ( $state eq 'disabled' );
428            
429             $cw->configure( -relief => 'sunken' );
430             $config{ $cw->{_cb_id} }{button}{press} = 1;
431            
432             # -repeatdelay
433             if ( my $repeatdelay = $cw->cget( -repeatdelay ) ) {
434             my $id_repeatdelay = $cw->repeat(
435             $repeatdelay,
436             sub {
437             if ( !Tk::Exists $cw ) { return; }
438             $cw->invoke;
439             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay}->cancel;
440             $config{ $cw->{_cb_id} }{button}{press_repeatdelay} = 1;
441            
442             # -repeatinterval
443             if ( my $repeatinterval = $cw->cget( -repeatinterval ) ) {
444             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay} = $cw->repeat(
445             $repeatinterval,
446             sub {
447             if ( !Tk::Exists $cw ) { return; }
448             $cw->invoke;
449             }
450             );
451             }
452             }
453             );
454             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay} = $id_repeatdelay;
455             }
456            
457             return;
458             }
459            
460             sub _press_leave {
461             my ( $cw, $who ) = @_;
462            
463             my $state = $cw->cget( -state );
464             if ( $state eq 'disabled' ) { return; }
465            
466             my $id_repeatdelay = $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay};
467             my $press_repeatdelay = $config{ $cw->{_cb_id} }{button}{press_repeatdelay};
468             if ( defined $id_repeatdelay ) {
469             $id_repeatdelay->cancel;
470             $cw->{_conf_cb}{ $cw->{_cb_id} }{ids}{id_repeatdelay} = undef;
471             }
472            
473             # Execute command
474             if ( $config{ $cw->{_cb_id} }{button}{enter} == 1 ) {
475             if ( not defined $press_repeatdelay or $press_repeatdelay != 1 ) {
476             $cw->_command( $cw->cget( -command ) );
477             }
478             }
479            
480             # if widget is destroyed
481             if ( !Tk::Exists $cw ) { return; }
482            
483             $config{ $cw->{_cb_id} }{button}{press_repeatdelay} = 0;
484            
485             if ( my $overrelief = $cw->cget( -overrelief ) ) {
486             $cw->configure( -relief => $overrelief );
487             }
488             else {
489             $cw->configure( -relief => $cw->{_conf_cb}{ $cw->{_cb_id} }{specialbutton}{-relief} );
490             }
491             if ( not defined $who or $who ne 'leave' ) {
492             $config{ $cw->{_cb_id} }{button}{press} = 0;
493             }
494            
495             return;
496             }
497            
498             sub _command {
499             my ( $cw, $ref_args ) = @_;
500            
501             my $state = $cw->cget( -state );
502             if ( $state eq 'disabled' or not defined $ref_args ) { return; }
503            
504             my $type_arg = ref $ref_args;
505            
506             # no arguments
507             if ( $type_arg eq 'CODE' ) {
508             $ref_args->();
509             }
510             elsif ( $type_arg eq 'ARRAY' ) {
511             my $command = $ref_args->[0];
512             my @args;
513             my $i = 0;
514             foreach my $argument ( @{$ref_args} ) {
515             if ( $i != 0 ) { push @args, $argument; }
516             $i++;
517             }
518             $command->(@args);
519             }
520            
521             return;
522             }
523            
524             sub _delete_text {
525             my $cw = shift;
526            
527             my $tag = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text};
528             if ( $cw->find( 'withtag', $tag ) ) {
529             $cw->delete($tag);
530             }
531            
532             return;
533             }
534            
535             sub _delete_image_bitmap {
536             my $cw = shift;
537            
538             my $tag_image = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{image};
539             my $tag_bitmap = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{bitmap};
540            
541             if ( $cw->find( 'withtag', $tag_image ) ) {
542             $cw->delete($tag_image);
543             }
544             if ( $cw->find( 'withtag', $tag_bitmap ) ) {
545             $cw->delete($tag_bitmap);
546             }
547            
548             return;
549             }
550            
551             sub _image_bitmap {
552             my $cw = shift;
553            
554             my $anchor = $cw->cget( -anchor );
555             my $bitmap = $cw->cget( -bitmap );
556             my $compound = $cw->cget( -compound );
557             my $disabledforeground = $cw->cget( -disabledforeground );
558             my $font = $cw->cget( -font );
559             my $foreground = $cw->cget( -foreground );
560             my $image = $cw->cget( -image );
561             my $imagedisabled = $cw->cget( -imagedisabled );
562             my $justify = $cw->cget( -justify );
563             my $wraplength = $cw->cget( -wraplength );
564             my $state = $cw->cget( -state );
565             my $tag_all = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{all};
566             my $tag_image = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{image};
567             my $tag_bitmap = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{bitmap};
568             my $tag_text = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text};
569             my $text = $cw->cget( -text );
570            
571             if ( $state eq 'disabled' and defined $imagedisabled ) {
572             $image = $imagedisabled;
573             }
574            
575             if ( not defined $image and not defined $bitmap ) {
576             return;
577             }
578            
579             $cw->_delete_text;
580             $cw->_delete_image_bitmap;
581            
582             my ( $x_text, $y_text, $x_image, $y_image );
583             ( $x_image, $y_image ) = $cw->_anchor_position;
584            
585             if ( $compound eq 'left'
586             or $compound eq 'bottom'
587             or $compound eq 'center'
588             or $compound eq 'right'
589             or $compound eq 'top' )
590             {
591             ( $x_text, $y_text, $x_image, $y_image ) = $cw->_anchor_position_compound($image);
592             }
593            
594             if ( defined $image ) {
595             my $id_image = $cw->createImage(
596             $x_image, $y_image,
597             -anchor => $anchor,
598             -image => $image,
599             -state => $state,
600             -tags => [ $tag_all, $tag_image ],
601             );
602             }
603             else {
604             my $id_image = $cw->createBitmap(
605             $x_image, $y_image,
606             -anchor => $anchor,
607             -bitmap => $bitmap,
608             -state => $state,
609             -tags => [ $tag_all, $tag_bitmap ],
610             );
611             }
612            
613             if ( defined $x_text and defined $y_text ) {
614             $cw->createText(
615             $x_text, $y_text,
616             -anchor => $anchor,
617             -fill => $foreground,
618             -font => $font,
619             -justify => $justify,
620             -tags => [ $tag_all, $tag_text ],
621             -text => $text,
622             -width => $wraplength,
623             );
624             }
625            
626             if ( $state eq 'disabled' ) {
627             $cw->itemconfigure( $tag_text, -fill => $disabledforeground );
628             }
629            
630             return 1;
631             }
632            
633             sub _text {
634             my $cw = shift;
635             my $anchor = $cw->cget( -anchor );
636             my $disabledforeground = $cw->cget( -disabledforeground );
637             my $font = $cw->cget( -font );
638             my $foreground = $cw->cget( -foreground );
639             my $justify = $cw->cget( -justify );
640             my $state = $cw->cget( -state );
641             my $tag_all = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{all};
642             my $tag_text = $cw->{_conf_cb}{ $cw->{_cb_id} }{tags}{text};
643             my $text = $cw->cget( -text );
644             my $ref_textvariable = $cw->cget( -textvariable );
645             my $wraplength = $cw->cget( -wraplength );
646            
647             # -textvariable used
648             if ( ref $ref_textvariable eq 'SCALAR' ) {
649             $text = ${$ref_textvariable};
650             $cw->configure( -textvariable => undef );
651             $cw->configure( -text => $text );
652            
653             # check modification of textvariable value
654             my $id;
655             $id = $cw->repeat( $TEXTVARIABLE_INTERVALL, [ \&_check_textvariable, $cw, $ref_textvariable, \$id ] );
656             }
657             $cw->_delete_text;
658            
659             my ( $x_text, $y_text ) = $cw->_anchor_position($anchor);
660             $cw->createText(
661             $x_text, $y_text,
662             -anchor => $anchor,
663             -fill => $foreground,
664             -font => $font,
665             -justify => $justify,
666             -tags => [ $tag_all, $tag_text ],
667             -text => $text,
668             -width => $wraplength,
669             );
670            
671             if ( $state eq 'disabled' ) {
672             $cw->itemconfigure( $tag_text, -fill => $disabledforeground );
673             }
674            
675             return;
676             }
677            
678             sub _check_textvariable {
679             my ( $cw, $ref_textvariable, $ref_id ) = @_;
680             my $last_text = $cw->cget( -text );
681             my $new_text = ${$ref_textvariable};
682            
683             if ( ( defined $last_text and defined $new_text ) and ( $last_text ne $new_text ) ) {
684             $cw->configure( -text => $new_text );
685             $cw->redraw_button;
686             }
687             return;
688             }
689            
690             sub _autofit_resize {
691             my $cw = shift;
692            
693             my $image = $cw->cget( -image );
694             my $bitmap = $cw->cget( -bitmap );
695             my $compound = $cw->cget( -compound );
696             my $font = $cw->cget( -font );
697             my $text = $cw->cget( -text );
698             my $width = $cw->width;
699             my $height = $cw->height;
700             my $borderwidth = $cw->cget( -borderwidth );
701            
702             my $widthcw = $cw->width;
703             my $heightcw = $cw->height;
704             my $padx = $cw->cget( -padx ) + $SPACE_PLUS;
705             my $pady = $cw->cget( -pady ) + $SPACE_PLUS;
706            
707             # Text dimension
708             my ( $text_width, $text_height, $image_width, $image_height );
709             if ( defined $text ) {
710             my $text_temp = $cw->createText(
711             0, 0,
712             -anchor => 'nw',
713             -font => $font,
714             -text => $text,
715             );
716             ( undef, undef, $text_width, $text_height ) = $cw->bbox($text_temp);
717             $cw->delete($text_temp);
718             }
719             if ( defined $image ) {
720             $image_width = $image->width;
721             $image_height = $image->height;
722             }
723             elsif ( defined $bitmap ) {
724             my $bitmap_temp = $cw->createBitmap( 0, 0, '-bitmap' => $bitmap, -anchor => 'nw' );
725             ( undef, undef, $image_width, $image_height ) = $cw->bbox($bitmap_temp);
726             $cw->delete($bitmap_temp);
727             }
728            
729             # autofit : Dimension, button
730             my ( $total_width, $total_height ) = ( 0, 0 );
731            
732             # image/bitmap and compound
733             if (
734             ( defined $image or defined $bitmap )
735             and (
736             defined $compound
737             and ($compound eq 'left'
738             or $compound eq 'right'
739             or $compound eq 'center'
740             or $compound eq 'bottom'
741             or $compound eq 'top' )
742             )
743             )
744             {
745            
746             if ( $compound eq 'left' or $compound eq 'right' ) {
747             $width = $image_width + $text_width + ( 2 * $padx );
748             $height = _maxarray( [ $image_height, $text_height ] ) + ( 2 * $pady );
749             }
750             elsif ( $compound eq 'bottom' or $compound eq 'top' ) {
751             $width = _maxarray( [ $image_width, $text_width ] ) + ( 2 * $padx );
752             $height = $image_height + $text_height + ( 2 * $pady );
753             }
754             elsif ( $compound eq 'center' ) {
755             $width = _maxarray( [ $image_width, $text_width ] ) + ( 2 * $padx );
756             $height = _maxarray( [ $image_height, $text_height ] ) + ( 2 * $pady );
757             }
758             }
759            
760             # image/bitmap replace text
761             elsif ( defined $image or defined $bitmap ) {
762             $width = $image->width + ( 2 * $padx );
763             $height = $image->height + ( 2 * $pady );
764             }
765            
766             # just text
767             elsif ( defined $text ) {
768             $width = $text_width + ( 2 * $padx );
769             $height = $text_height + ( 2 * $pady );
770             }
771            
772             if ( $widthcw != $width or $heightcw != $height ) {
773             $cw->configure( -width => $width, -height => $height );
774             }
775            
776             return;
777             }
778            
779             sub _anchor_position {
780             my $cw = shift;
781            
782             my $anchor = $cw->cget( -anchor );
783             my $width = $cw->width;
784             my $height = $cw->height;
785             my $borderwidth = $cw->cget( -borderwidth );
786             my $padx = $cw->cget( -padx );
787             my $pady = $cw->cget( -pady );
788            
789             my %xy_anchor_position = (
790             n => {
791             x => $width / 2,
792             y => ( 2 * $pady ) + ( 2 * $borderwidth ),
793             },
794             nw => {
795             x => ( 2 * $padx ) + ( 2 * $borderwidth ),
796             y => ( 2 * $pady ) + ( 2 * $borderwidth ),
797             },
798             ne => {
799             x => $width - ( 2 * $padx ) - ( 2 * $borderwidth ),
800             y => ( 2 * $pady ) + ( 2 * $borderwidth ),
801             },
802             s => {
803             x => $width / 2,
804             y => $height - ( 2 * $pady ) - ( 2 * $borderwidth ),
805             },
806             sw => {
807             x => ( 2 * $padx ) + ( 2 * $borderwidth ),
808             y => $height - ( 2 * $pady ) - ( 2 * $borderwidth ),
809             },
810             se => {
811             x => $width - ( 2 * $padx ) - ( 2 * $borderwidth ),
812             y => $height - ( 2 * $pady ) - ( 2 * $borderwidth ),
813             },
814             center => {
815             x => $width / 2,
816             y => $height / 2,
817             },
818             w => {
819             x => ( 2 * $padx ) + ( 2 * $borderwidth ),
820             y => $height / 2,
821             },
822             e => {
823             x => $width - ( 2 * $padx ) - ( 2 * $borderwidth ),
824             y => $height / 2,
825             },
826             );
827            
828             return ( $xy_anchor_position{$anchor}{x}, $xy_anchor_position{$anchor}{y} );
829             }
830            
831             sub _anchor_position_compound {
832             my ( $cw, $image ) = @_;
833            
834             my $anchor = $cw->cget( -anchor );
835             my $bitmap = $cw->cget( -bitmap );
836             my $compound = $cw->cget( -compound );
837             my $font = $cw->cget( -font );
838             my $text = $cw->cget( -text );
839             my $width = $cw->width;
840             my $height = $cw->height;
841             my $borderwidth = $cw->cget( -borderwidth );
842             my $padx = $cw->cget( -padx );
843             my $pady = $cw->cget( -pady );
844            
845             my ( $x_text, $y_text, $x_image, $y_image );
846             ( $x_text, $y_text ) = $cw->_anchor_position;
847             $x_image = $x_text;
848             $y_image = $y_text;
849            
850             # Image dimension
851             my ( $image_width, $image_height ) = ();
852             if ( defined $image ) {
853             $image_width = $image->width;
854             $image_height = $image->height;
855             }
856             elsif ( defined $bitmap ) {
857             my $bitmap_temp = $cw->createBitmap( 0, 0, '-bitmap' => $bitmap, -anchor => 'nw' );
858             ( undef, undef, $image_width, $image_height ) = $cw->bbox($bitmap_temp);
859             $cw->delete($bitmap_temp);
860             }
861            
862             # no image or bitmap defined
863             else {
864             return ( $x_text, $y_text, $x_image, $y_image );
865             }
866            
867             # Text dimension
868             my $text_temp = $cw->createText(
869             0, 0,
870             -anchor => 'nw',
871             -font => $font,
872             -text => $text,
873             );
874             my ( undef, undef, $text_width, $text_height ) = $cw->bbox($text_temp);
875             $cw->delete($text_temp);
876            
877             my $diff_width = $text_width - $image_width;
878             my $diff_height = $text_height - $image_height;
879            
880             # Compound
881             my %xy_anchor_position;
882             foreach my $compound_pos (qw/ left right center top bottom /) {
883             foreach my $anchor_pos (qw/ n ne nw s sw se center e w /) {
884             $xy_anchor_position{$compound_pos}{$anchor_pos}{x_text} = $x_text;
885             $xy_anchor_position{$compound_pos}{$anchor_pos}{y_text} = $y_text;
886             $xy_anchor_position{$compound_pos}{$anchor_pos}{x_image} = $x_image;
887             $xy_anchor_position{$compound_pos}{$anchor_pos}{y_image} = $y_image;
888             }
889             }
890            
891             # x
892             foreach (qw / nw w sw /) {
893             $xy_anchor_position{left}{$_}{x_text} += $image_width;
894             $xy_anchor_position{right}{$_}{x_image} += $text_width;
895             if ( $diff_width > 0 ) {
896             $xy_anchor_position{center}{$_}{x_image} += ( $diff_width / 2 );
897             $xy_anchor_position{bottom}{$_}{x_image} += ( $text_width - $image_width ) / 2;
898             $xy_anchor_position{top}{$_}{x_image} += ($diff_width) / 2;
899             }
900             else {
901             $xy_anchor_position{center}{$_}{x_text} -= ( $diff_width / 2 );
902             $xy_anchor_position{bottom}{$_}{x_text} += -($diff_width) / 2;
903             $xy_anchor_position{top}{$_}{x_text} -= ($diff_width) / 2;
904             }
905             }
906             foreach (qw / n center s /) {
907             $xy_anchor_position{left}{$_}{x_text} += ( $image_width / 2 );
908             $xy_anchor_position{left}{$_}{x_image}
909             = ( $xy_anchor_position{left}{$_}{x_text} - ( $text_width / 2 ) - ( $image_width / 2 ) );
910             $xy_anchor_position{right}{$_}{x_text} -= ( $image_width / 2 );
911             $xy_anchor_position{right}{$_}{x_image} += ( $text_width / 2 );
912             }
913             foreach (qw / ne e se /) {
914             $xy_anchor_position{left}{$_}{x_image} -= $text_width;
915             $xy_anchor_position{right}{$_}{x_text} -= $image_width;
916             if ( $diff_width > 0 ) {
917             $xy_anchor_position{center}{$_}{x_image} -= ( $diff_width / 2 );
918             $xy_anchor_position{bottom}{$_}{x_image} -= ( $text_width - $image_width ) / 2;
919             $xy_anchor_position{top}{$_}{x_image} -= ($diff_width) / 2;
920             }
921             else {
922             $xy_anchor_position{center}{$_}{x_text} += ( $diff_width / 2 );
923             $xy_anchor_position{bottom}{$_}{x_text} -= -($diff_width) / 2;
924             $xy_anchor_position{top}{$_}{x_text} += ($diff_width) / 2;
925             }
926             }
927            
928             # y
929             foreach (qw / nw n ne /) {
930             if ( $diff_height > 0 ) {
931             $xy_anchor_position{left}{$_}{y_image} += ( $diff_height / 2 );
932             $xy_anchor_position{right}{$_}{y_image} += ( $diff_height / 2 );
933             $xy_anchor_position{center}{$_}{y_image} += ( $diff_height / 2 );
934             }
935             else {
936             $xy_anchor_position{left}{$_}{y_text} -= ( $diff_height / 2 );
937             $xy_anchor_position{right}{$_}{y_text} -= ( $diff_height / 2 );
938             $xy_anchor_position{center}{$_}{y_text} -= ( $diff_height / 2 );
939             }
940             $xy_anchor_position{bottom}{$_}{y_image} += $text_height;
941             $xy_anchor_position{top}{$_}{y_text} += $image_height;
942             }
943             foreach (qw / sw s se /) {
944             if ( $diff_height > 0 ) {
945             $xy_anchor_position{left}{$_}{y_image} -= ( $diff_height / 2 );
946             $xy_anchor_position{right}{$_}{y_image} -= ( $diff_height / 2 );
947             $xy_anchor_position{center}{$_}{y_image} -= ( $diff_height / 2 );
948             }
949             else {
950             $xy_anchor_position{left}{$_}{y_text} += ( $diff_height / 2 );
951             $xy_anchor_position{right}{$_}{y_text} += ( $diff_height / 2 );
952             $xy_anchor_position{center}{$_}{y_text} += ( $diff_height / 2 );
953             }
954             $xy_anchor_position{bottom}{$_}{y_image} = $height - ( 2 * $pady ) - ( 2 * $borderwidth );
955             $xy_anchor_position{bottom}{$_}{y_text} -= $image_height;
956             $xy_anchor_position{top}{$_}{y_image} = $xy_anchor_position{top}{$_}{y_text} - $text_height;
957             }
958             foreach (qw / w center e /) {
959             $xy_anchor_position{bottom}{$_}{y_text} -= $text_height / 2;
960             $xy_anchor_position{bottom}{$_}{y_image} += $image_height / 2;
961             $xy_anchor_position{top}{$_}{y_text} += $text_height / 2;
962             $xy_anchor_position{top}{$_}{y_image} -= $image_height / 2;
963             }
964            
965             foreach my $anchor_pos (qw/ n ne nw s sw se center e w /) {
966             $xy_anchor_position{left}{$anchor_pos}{x_text} += $SPACE_PLUS;
967             $xy_anchor_position{right}{$anchor_pos}{x_image} += $SPACE_PLUS;
968             }
969            
970             my @xy_text
971             = ( $xy_anchor_position{$compound}{$anchor}{x_text}, $xy_anchor_position{$compound}{$anchor}{y_text} );
972             my @xy_image
973             = ( $xy_anchor_position{$compound}{$anchor}{x_image}, $xy_anchor_position{$compound}{$anchor}{y_image} );
974            
975             return ( @xy_text, @xy_image );
976             }
977            
978             sub _tooltip {
979             my $cw = shift;
980            
981             my $state = $cw->cget( -state );
982            
983             #if ( $state eq 'disabled' ) { return; }
984            
985             my $tooltip_balloon = $cw->cget( -tooltip );
986             my $id = $cw->{_cb_id};
987             my $initwait = $INITWAIT;
988             my $tooltip;
989            
990             if ( ref $tooltip_balloon eq 'ARRAY' and $tooltip_balloon->[1] ) {
991             $tooltip = $tooltip_balloon->[0];
992             $initwait = $tooltip_balloon->[1];
993             }
994             else {
995             $tooltip = $tooltip_balloon;
996             }
997            
998             if ( defined $tooltip ) {
999             if ( exists $all_balloon{$id} and Tk::Exists $all_balloon{$id} ) {
1000             $all_balloon{$id}->configure( -state => 'none' );
1001             $all_balloon{$id}->detach($cw);
1002             $all_balloon{$id} = undef;
1003             }
1004            
1005             $all_balloon{$id} = $cw->Balloon( -background => 'white', );
1006             $all_balloon{$id}->attach(
1007             $cw,
1008             -balloonposition => 'mouse',
1009             -msg => $tooltip,
1010             -initwait => $initwait,
1011             );
1012             }
1013            
1014             return;
1015             }
1016            
1017             sub _maxarray {
1018             my ($ref_umber) = @_;
1019             my $max;
1020            
1021             for my $chiffre ( @{$ref_umber} ) {
1022             $max = _max( $max, $chiffre );
1023             }
1024            
1025             return $max;
1026             }
1027            
1028             sub _max {
1029             my ( $a, $b ) = @_;
1030             if ( not defined $a ) { return $b; }
1031             if ( not defined $b ) { return $a; }
1032             if ( not defined $a and not defined $b ) { return; }
1033            
1034             if ( $a >= $b ) { return $a; }
1035             else { return $b; }
1036            
1037             return;
1038             }
1039            
1040             1;
1041            
1042             __END__