Gtk2::CellRendererSpinButton-Z



Hi,
Here is a working package, for the 
Gtk2::CellRendererSpinButton.

It sets initial value, updates itself, and sets
new initial value at each edit.

I use a package global to hold the current value,
and if anyone knows a better way, my ears are open. :-)

#!/usr/bin/perl -w
use strict;
use Gtk2 -init;

# package Gtk2::CellRendererSpinButtonZ;
#
# with a simple example usage
#
#this package is based on the Mup::CellRendererSpinButton
#by muppet, but added 
#
# 1.  SET_PROPERTY sub to load and show initial values
# 2.  an extra signal handler for the focus-out to set
#     the spinbox, when going out of focus
# 3.  a global $cur_val to maintain the initial editing 
#     start point

package Gtk2::CellRendererSpinButtonZ;
use POSIX qw(DBL_MAX UINT_MAX);
use constant x_padding => 2;
use constant y_padding => 3;
use Gtk2::Gdk::Keysyms;

#global to hold current value to load when start editing
my $cur_val;  

use Glib::Object::Subclass "Gtk2::CellRenderer",
 signals => {
   edited => {
      flags       => [ qw(run-last) ],
      param_types => [ qw(Glib::String Glib::Double) ],
   },
 },
 properties => [
   Glib::ParamSpec->double(
      "xalign", "Horizontal Alignment",
      "Where am i?", 0.0, 1.0, 1.0, [ qw(readable writable) ]
   ),
   Glib::ParamSpec->boolean(
      "editable",           "Editable",
      "Can I change that?", 0,
      [ qw(readable writable) ]
   ),
   Glib::ParamSpec->uint(
      "digits",             "Digits",
      "How picky are you?", 0,
      UINT_MAX,             2,
      [ qw(readable writable) ]
   ),
   map {
      Glib::ParamSpec->double(
         $_->[ 0 ],
         $_->[ 1 ],
         $_->[ 2 ],
         0.0, DBL_MAX,
         $_->[ 3 ],
         [ qw(readable writable) ]
       )
    } (
      [ "value", "Value", "How much is the fish?",    0.0 ],
      [ "min",   "Min",   "No way, I have to live!",  0.0 ],
      [ "max",   "Max",   "Ah, you're too generous.", 100.0 ],
      [ "step",  "Step",  "Okay.",                    5.0 ]
    )
 ];

sub INIT_INSTANCE {
   my $self = shift;
   $self->{ editable } = 0;
   $self->{ digits }   = 2;
   $self->{ value }    = 0.0;
   $self->{ min }      = 0.0;
   $self->{ max }      = 100.0;
   $self->{ step }     = 5.0;
   $self->{ xalign }   = 1.0;
}

sub SET_PROPERTY {
    my ($self, $pspec, $val) = @_;
    $self->{ $pspec->get_name  } = $val;

# set the initial editing value
 if ($pspec->get_name eq 'value') {
        $cur_val = $val;
     }
}

sub calc_size {
   my ( $cell, $layout, $area ) = @_;
   my ( $width, $height ) = $layout->get_pixel_size();

   return (
        $area
      ? $cell->{ xalign } * ( $area->width - ( $width + 3 * x_padding ) )
      : 0,
      0,
      $width + x_padding * 2,
      $height + y_padding * 2
   );
}

sub format_text {
   my $cell = shift;
   my $format = sprintf '%%.%df', $cell->{ digits };
   sprintf $format, $cell->{ value };
}

sub GET_SIZE {
   my ( $cell, $widget, $area ) = @_;

   my $layout = $cell->get_layout( $widget );
   $layout->set_text( $cell->format_text );

   return $cell->calc_size( $layout, $area );
}

sub get_layout {
   my ( $cell, $widget ) = @_;

   return $widget->create_pango_layout( "" );
}

sub RENDER {
   my ( $cell, $window, $widget, $background_area, $cell_area, $expose_area,
      $flags )
    = @_;
   my $state;

   if ( $flags & 'selected' ) {
      $state =
       $widget->has_focus()
       ? 'selected'
       : 'active';
   }
   else {
      $state =
       $widget->state() eq 'insensitive'
       ? 'insensitive'
       : 'normal';
   }

   my $layout = $cell->get_layout( $widget );
   $layout->set_text( $cell->format_text );

   my ( $x_offset, $y_offset, $width, $height ) =
    $cell->calc_size( $layout, $cell_area );
   $widget->get_style->paint_layout(
      $window,
      $state,
      1,
      $cell_area,
      $widget,
      "cellrenderertext",
      $cell_area->x() + $x_offset + x_padding,
      $cell_area->y() + $y_offset + y_padding,
      $layout
   );
}

sub START_EDITING {
   my ( $cell, $event, $view, $path, $background_area, $cell_area, $flags ) =
    @_;
   my $spin_button =
    Gtk2::SpinButton->new_with_range( $cell->get( qw(min max step) ) );

   $spin_button->set_value( $cell->get( "value" ) );
   $spin_button->set_digits( $cell->get( "digits" ) );
   
   #set initial point for editing    
   $spin_button->set_value( $cur_val );

   $spin_button->grab_focus();

   $spin_button->signal_connect(
      key_press_event => sub {
         my ( $event_box, $event ) = @_;

         if (  $event->keyval == $Gtk2::Gdk::Keysyms{ Return }
            || $event->keyval == $Gtk2::Gdk::Keysyms{ KP_Enter } )
         {
            $spin_button->update();
            $cell->signal_emit( edited => $path, $spin_button->get_value() );
            $spin_button->destroy();
            return 1;
         }
         elsif ( $event->keyval == $Gtk2::Gdk::Keysyms{ Up } ) {
            $spin_button->spin( 'step-forward',
               ( $spin_button->get_increments() )[ 0 ] );
            return 1;
         }
         elsif ( $event->keyval == $Gtk2::Gdk::Keysyms{ Down } ) {
            $spin_button->spin( 'step-backward',
               ( $spin_button->get_increments() )[ 0 ] );
            return 1;
         }
         return 0;
      }
   
    );

   $spin_button->signal_connect(
      'focus-out-event' => sub {
         my ( $event_box, $event ) = @_;
            $spin_button->update();
            $cell->signal_emit( edited => $path, $spin_button->get_value() );
        #set the init value for next edit
        $cur_val = $spin_button->get_value();
        
        return 0;
      }
   );
   
   $spin_button->show_all();

   return $spin_button;
}
1;

################################################################
package main;

my $window = Gtk2::Window->new( "toplevel" );
$window->set_title( "CellRendererSpinButtonZ demo" );
$window->signal_connect( delete_event => sub { Gtk2->main_quit(); } );

my $model = Gtk2::ListStore->new( qw(Glib::Double) );
my $view  = Gtk2::TreeView->new( $model );

#setup init value
$model->set( $model->append(), 0 => 42.42 );

my $renderer = Gtk2::CellRendererSpinButtonZ->new();

$renderer->set(
   mode   => "editable",
   min    => 0,
   max    => 1000,
   step   => 1.0,
   digits => 2
);

$renderer->signal_connect( edited => \&cell_edited );

my $column =
 Gtk2::TreeViewColumn->new_with_attributes( "2 digit", $renderer, value => 0 );

$view->append_column( $column );

my $vbox = Gtk2::VBox->new( 0, 5 );

$vbox->pack_start( $view, 1, 1, 0 );

my $button = Gtk2::Button->new( "Show Values" );
$button->signal_connect( "clicked" => sub { &show_values( @_ ); } );
$vbox->pack_start( $button, 0, 0, 0 );
$window->add( $vbox );
$window->show_all();

Gtk2->main();
####################################################################
sub cell_edited {
   my ( $cell, $path, $new_value ) = @_;

   $model->set( $model->get_iter( Gtk2::TreePath->new_from_string( $path ) ),
      0 => $new_value );
}
####################################################################
sub show_values {

   my $treeselection = $view->get_selection;
   my $iter          = $treeselection->get_selected;

   print $model->get( $iter, 0 ), "\n";

}

__END__


-- 
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]