Re: EXTERNAL: Re: Gtk2::SpinButton For Hex



Hi,

Looks like twisting the implementation of the standard Spinbutton widget is not quite easy to be achieved - maybe my alternative is quicker to put to effective use.

I append code that I reduced from a gtk2 application I did a couple of years ago, that implements a hex Spinbutton as a set of procedures. I am leaving for 8 days of vacation tomorrow morning, did this very rapidly without doing much testing. However, I realized some things that need improving: use fixed format + size of entry box, parametrize the number of digits (presently hard-wired to 4 digits - as needed in my old application): this code is an example of a an approach that works, but needs to be improved to become a library procedure.

Not included in the example, but easy to implement, a "get_value" and a "set_value" procedure, and possibly a "step" parameter. I also stuck to keeping this a set of procedures, rather than implementing a widget.

Juergen

============ demo code of a hex spin-button implementation ==========
============  for adequate display, set editor tabs to 4   ==========

#! /usr/bin/perl

use strict;
use warnings;
use diagnostics;
use Gtk2                '-init';
use Glib                qw (TRUE FALSE );



use constant SPIN_HEIGHT => 16;                      # height of arrow pixmap (must
                                                                                #               correspond to 
pixmap data)

use constant SPIN_MIDDLE => ( SPIN_HEIGHT / 2 );

use constant VERT_MARGIN        => 3;            # top and bottom margin of widget

use constant REPEAT_LATENCY     => 700;              # msec before first auto repeat
use constant REPEAT_INTERVAL => 30;          # msec before following auto repeat


# Pixmap for arrow item of hex pseudo spinbox
# -------------------------------------------

my $arrow_xpm   = Gtk2::Gdk::Pixbuf->new_from_xpm_data (
                        "11 16  3 1",
                        "      c None",
                        "+     c Black",
                        "-     c Gray80",
                        "    -+-    ",
                        "   -+++-   ",
                        "  -++-++-  ",
                        " -++- -++- ",
                        "-++-   -++-",
                        "---     ---",
                        "           ",
                        "           ",
                        "           ",
                        "           ",
                        "---     ---",
                        "-++-   -++-",
                        " -++- -++- ",
                        "  -++-++-  ",
                        "   -+++-   ",
                        "    -+-     "                );



# Arrow-button event in pseudo-spinbox entry widget
# =================================================
#       Argument  #0 :  entry widget (pseudo spinbutton)
#                         #1 :  entry-item-position     step: +1 or -1
#                         #2 :  event                   ''
#                         #3 :  threshold y-coordinate between up and down zone

sub SpinarrowHit {
    my ( $p_box, $p_pos, $p_event, $p_middle ) = @_;

    my ( $x_step, $time_out );
    if ( ${$p_box}{'REPEAT'} ne '' ) {

                        # Spin arrow button released: cancel repeat timer

                Glib::Source->remove ( ${$p_box}{'REPEAT'} );
                ${$p_box}{'REPEAT'} = '';
    }
    if ( ref ($p_event) =~ /Button/ ) {

                        # Spin arrow button pressed: step the value, set repeat timer

                if ( index ($p_event->type, 'release' ) > 0 ) {
                        unless ( ${$p_box}{'REPEAT'} eq '' ) {
                                Glib::Source->remove ( ${$p_box}{'REPEAT'} );
                                ${$p_box}{'REPEAT'} = '';
                        }
                        return;
                }
                my $pos_y = $p_event->y;

                if ( $pos_y <= $p_middle - 1 ) {
                        $x_step = 1;
                } elsif ( $pos_y > $p_middle + 1 ) {
                        $x_step = -1;
                } else {
                        return;
                }
                $time_out = REPEAT_LATENCY;
    } else {

                        # Repeat timer struck: step and re-launch the repeat timer

                $x_step = $p_pos;
                $time_out = REPEAT_INTERVAL;
    }

    my $x_value = $p_box->get_text ();
    $x_value =~ s/\s*//;
    unless ( $x_value =~ /^[0-9a-f]+$/i ) { return; }
    $x_value= hex ( $x_value );
    if ( ( $x_step == 1 ) && ( $x_value >= ${$p_box}{'MAX'} ) ) { return; }
    if ( ( $x_step == -1 ) && ($x_value <= ${$p_box}{'MIN'} ) ) { return; }
    ${$p_box}{'VALUE'} = $x_value + $x_step;
    $p_box->set_text ( sprintf ( "%04x", $x_value + $x_step ) );

    ${$p_box}{'REPEAT'} = Glib::Timeout->add ( $time_out,
                                sub {
                                        SpinarrowHit ( $p_box, $x_step, '', $p_middle );
                                        return FALSE;
                                } );
} # sub SpinarrowHit



# Check contents of the pseudo spinbox against non-hex characters
# ===============================================================
#   Restore to last valid value in case of error
#
#       Argument  #0 :  entry widget (pseudo spinbutton)
#                         #1 :  entry-item-position     step: +1 or -1
#                         #2 :  event

sub SpinvalueCheck {
    my ( $p_box, $p_pos, $p_event ) = @_;

    my $new_value;
    my $old_value = ${$p_box}{'VALUE'};
    my $x_shown = $p_box->get_text ();
    if ( $x_shown =~ /^[0-9a-f]+$/i ) {
                $new_value = hex ( $x_shown );
                ${$p_box}{'VALUE'} = $new_value;
    } else {
                $new_value = $old_value;
                $p_box->set_text ( sprintf ( "%04x", $old_value ) );
    }
} # SpinvalueCheck



# Create a hex Spinbutton
# =======================
#       Argument  #0 :  intial value
#                         #1 :  lower limit
#                         #2 :  upper limit
#
#       Return:   entry widget created (pseudo spinbutton)
#
#       - program calls: numeric values are represented as perl values
#       - spinbox display: values are represented as hex strings
#       - contents of the entry widget are verified (only hex digits?) when
#         focus is lost: in case of an error, revert to the last valid hex value.
#
#       State variables attached as hash values:
#               ${$widget}{VALUE}                       last accepted value
#               ${$widget}{MIN}                         lowest value
#               ${$widget}{MAX}                         highest accepted value
#               ${$widget}{REPEAT}                      id of repeat timer

sub HexSpinButton {
        my ( $p_value, $p_min, $p_max ) = @_;

        my $w_temp = Gtk2::Entry->new_with_max_length (4);
        $w_temp->set_editable ( TRUE );
        $w_temp->set_size_request ( 70, -1 );
        $w_temp->set_icon_from_pixbuf ( 'secondary', $arrow_xpm );
        $w_temp->set_icon_activatable ( 'secondary', TRUE );
        $w_temp->set_inner_border ( { 'left'=>4, 'right'=>0,
                                                                'top'=>VERT_MARGIN, 'bottom'=>VERT_MARGIN } );
        $w_temp->signal_connect ( 'icon-press', \&SpinarrowHit, SPIN_MIDDLE );
        $w_temp->signal_connect ( 'icon-release', \&SpinarrowHit, SPIN_MIDDLE );
        $w_temp->signal_connect ( 'leave-notify-event', \&SpinvalueCheck );

        $w_temp->set_text ( sprintf ( "%04x", $p_value ) );

        ${$w_temp}{'VALUE'} = sprintf ( $p_value );
        ${$w_temp}{'MIN'} = $p_min;
        ${$w_temp}{'MAX'} = $p_max;
        ${$w_temp}{'REPEAT'} = '';
        return $w_temp;
} # sub HexSpinButton



# Main procedure (demo)
# =====================

my $f_main = Gtk2::Window->new( 'toplevel' );

my $f_outer = Gtk2::HBox->new ();
$f_outer->set_size_request ( 300, 200 );
$f_main->add ( $f_outer );

my $spin_button = HexSpinButton ( 0x13, 1, 0x100 );

$f_outer->pack_start ( $spin_button, TRUE, FALSE, 0 );


$f_main->show_all;
Gtk2->main;
exit ();


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