Skip Menu |

This queue is for tickets about the Tickit-Widgets CPAN distribution.

Report information
The Basics
Id: 88954
Status: resolved
Priority: 0/
Queue: Tickit-Widgets

People
Owner: Nobody in particular
Requestors: TEAM [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.12
Fixed in: 0.13



Subject: Callbacks for radio/check button toggle
Maybe I'm missing something but it seems that there's no way to listen for notifications when button states are toggled - if that's the case, an on_change or similar callback would be very useful for reacting to state changes. cheers, Tom
On Wed Sep 25 02:46:13 2013, TEAM wrote: Show quoted text
> Maybe I'm missing something but it seems that there's no way to listen > for notifications when button states are toggled - if that's the case, > an on_change or similar callback would be very useful for reacting to > state changes.
Ah yes. Easy enough to add. Attached is a patch to add 'on_toggle' to CheckButton, 'on_activate' to RadioButton, and 'on_changed' to RadioButton::Group. -- Paul Evans
Subject: rt88954.patch
=== modified file 'lib/Tickit/Widget/CheckButton.pm' --- lib/Tickit/Widget/CheckButton.pm 2013-09-27 12:56:35 +0000 +++ lib/Tickit/Widget/CheckButton.pm 2013-09-27 13:02:58 +0000 @@ -129,6 +129,10 @@ The label text to display alongside this button. +=item on_toggle => CODE + +Optional. Callback function to invoke when the check state is changed. + =back =cut @@ -140,7 +144,8 @@ my $self = $class->SUPER::new( %args ); - $self->{label} = $args{label}; + $self->set_label( $args{label} ) if defined $args{label}; + $self->set_on_toggle( $args{on_toggle} ) if $args{on_toggle}; return $self; } @@ -185,6 +190,31 @@ $self->redraw; } +=head2 $on_toggle = $checkbutton->on_toggle + +=cut + +sub on_toggle +{ + my $self = shift; + return $self->{on_toggle}; +} + +=head2 $checkbutton->set_on_toggle( $on_toggle ) + +Return or set the CODE reference to be called when the button state is +changed. + + $on_toggle->( $checkbutton, $active ) + +=cut + +sub set_on_toggle +{ + my $self = shift; + ( $self->{on_toggle} ) = @_; +} + =head1 METHODS =cut @@ -200,6 +230,7 @@ my $self = shift; $self->{active} = 1; $self->set_style_tag( active => 1 ); + $self->{on_toggle}->( $self, 1 ) if $self->{on_toggle}; } =head2 $checkbutton->deactivate @@ -213,6 +244,7 @@ my $self = shift; $self->{active} = 0; $self->set_style_tag( active => 0 ); + $self->{on_toggle}->( $self, 0 ) if $self->{on_toggle}; } *key_toggle = \&toggle; === modified file 'lib/Tickit/Widget/RadioButton.pm' --- lib/Tickit/Widget/RadioButton.pm 2013-08-30 23:19:22 +0000 +++ lib/Tickit/Widget/RadioButton.pm 2013-09-28 13:03:41 +0000 @@ -88,6 +88,16 @@ =back +The following style actions are used: + +=over 4 + +=item activate + +The main action to activate the C<on_click> handler. + +=back + =cut style_definition base => @@ -130,6 +140,11 @@ supplied, a new group will be constructed that can be accessed using the C<group> accessor. +=item value => SCALAR + +Optional. If supplied, used to set the button's identification value, which +is passed to the group's C<on_changed> callback. + =back =cut @@ -141,7 +156,10 @@ my $self = $class->SUPER::new( %args ); - $self->{label} = $args{label}; + $self->set_label( $args{label} ) if defined $args{label}; + $self->set_on_toggle( $args{on_toggle} ) if $args{on_toggle}; + $self->set_value( $args{value} ) if defined $args{value}; + $self->{group} = $args{group} || Tickit::Widget::RadioButton::Group->new; return $self; @@ -199,6 +217,58 @@ $self->redraw; } +=head2 $on_toggle = $radiobutton->on_toggle + +=cut + +sub on_toggle +{ + my $self = shift; + return $self->{on_toggle}; +} + +=head2 $radiobutton->set_on_toggle( $on_toggle ) + +Return or set the CODE reference to be called when the button state is +changed. + + $on_toggle->( $radiobutton, $active ) + +When the radio tick mark moves from one button to another, the old button is +marked unactive before the new one is marked active. + +=cut + +sub set_on_toggle +{ + my $self = shift; + ( $self->{on_toggle} ) = @_; +} + +=head2 $value = $radiobutton->value + +=cut + +sub value +{ + my $self = shift; + return $self->{value}; +} + +=head2 $radiobutton->set_value( $value ) + +Return or set the scalar value used to identify the radio button to the +group's C<on_changed> callback. This can be any scalar value; it is simply +stored by the button and not otherwise used. + +=cut + +sub set_value +{ + my $self = shift; + ( $self->{value} ) = @_; +} + =head1 METHODS =cut @@ -218,11 +288,14 @@ if( my $old = $group->active ) { $old->set_style_tag( active => 0 ); + $old->{on_toggle}->( $old, 0 ) if $old->{on_toggle}; } $group->set_active( $self ); $self->set_style_tag( active => 1 ); + $self->{on_toggle}->( $self, 1 ) if $self->{on_toggle}; + return 1; } @@ -301,7 +374,7 @@ sub new { my $class = shift; - return bless \(my $self), $class; + return bless [ undef, undef ], $class; } =head2 $radiobutton = $group->active @@ -313,13 +386,42 @@ sub active { my $self = shift; - return $$self; + return $self->[0]; } sub set_active { my $self = shift; - ( $$self ) = @_; + ( $self->[0] ) = @_; + $self->[1]->( $self->active, $self->active->value ) if $self->[1]; +} + +=head2 $on_changed = $group->on_changed + +=cut + +sub on_changed +{ + my $self = shift; + return $self->[1]; +} + +=head2 $group->set_on_changed( $on_changed ) + +Return or set the CODE reference to be called when the active member of the +group changes. This may be more convenient than setting the C<on_toggle> +callback of each button in the group. + +The callback is passed the currently-active button, and its C<value>. + + $on_changed->( $active, $value ) + +=cut + +sub set_on_changed +{ + my $self = shift; + ( $self->[1] ) = @_; } =head1 AUTHOR === modified file 't/11widget-radiobutton.t' --- t/11widget-radiobutton.t 2013-05-11 19:29:25 +0000 +++ t/11widget-radiobutton.t 2013-09-28 13:03:58 +0000 @@ -14,13 +14,25 @@ push my @buttons, Tickit::Widget::RadioButton->new( label => "Radio 1", + value => 1, ); push @buttons, Tickit::Widget::RadioButton->new( label => "Radio $_", + value => $_, group => $buttons[0]->group ) for 2 .. 4; +my $radio2_active; +$buttons[1]->set_on_toggle( + sub { ( undef, $radio2_active ) = @_ } +); + +my $active_value; +$buttons[0]->group->set_on_changed( + sub { ( undef, $active_value ) = @_ } +); + is( $buttons[2]->label, "Radio 3", '$button->label' ); my $vbox = Tickit::Widget::VBox->new; @@ -36,6 +48,8 @@ [TEXT("( )",fg=>15,b=>1), BLANK(2), TEXT("Radio 4")] ], 'Display initially' ); +ok( !$radio2_active, '$radio2_active false initially' ); + pressmouse( press => 1, 1, 10 ); flush_tickit; @@ -47,6 +61,8 @@ 'Display after click 2' ); ok( $buttons[1]->is_active, 'Radio 2 is active' ); +ok( $radio2_active, '$radio2_active after click 2' ); +is( $active_value, 2, 'active ->value is 2 after click 2' ); pressmouse( press => 1, 3, 10 ); @@ -60,6 +76,8 @@ ok( !$buttons[1]->is_active, 'Radio 2 no longer active' ); ok( $buttons[3]->is_active, 'Radio 4 is active' ); +ok( !$radio2_active, '$radio2_active false after click 4' ); +is( $active_value, 4, 'active ->value is 4 after click 4' ); $buttons[0]->set_label( "First radio" ); === modified file 't/12widget-checkbutton.t' --- t/12widget-checkbutton.t 2013-05-11 19:29:25 +0000 +++ t/12widget-checkbutton.t 2013-09-27 13:03:47 +0000 @@ -11,8 +11,10 @@ my $root = mk_window; +my $active; my $button = Tickit::Widget::CheckButton->new( label => "Check button", + on_toggle => sub { ( undef, $active ) = @_ }, ); is( $button->label, "Check button", '$button->label' ); @@ -33,6 +35,7 @@ 'Display after click' ); ok( $button->is_active, '$button->is_active true after click' ); +ok( $active, 'on_toggle invoked after click' ); pressmouse( press => 1, 0, 7 ); @@ -42,5 +45,6 @@ 'Display after second click' ); ok( !$button->is_active, '$button->is_active true after second click' ); +ok( !$active, 'on_toggle invoked after second click' ); done_testing;
Released in 0.13. -- Paul Evans