schnell18
schnell18

Reputation: 320

Curses::UI::Grid tab captured

I use the Curses::UI::Grid to display the tabular data. The window consists of a table and a few buttons to navigate the data display window to other windows as illustrated below: Curses::UI::Grid tabular data sample

However, when the data is displayed, the focus goes to the first row and if I use the tab to shift the focus to next UI control, it never goes to the buttons at the bottom. It just cycle thru the cells of the first row.

Here is the code to reproduce the problem:

#!/usr/bin/env perl

use strict;
use warnings;
use Curses::UI;
use Curses::UI::Grid;

my $debug = 0;

# Create the root object.
my $cui = new Curses::UI ( 
    -color_support => 1,
    -clear_on_exit => 1, 
    -debug => $debug,
);

create_promote_deps_window();
$cui->set_binding( \&exit_dialog , "\cQ");

$cui->mainloop();

sub exit_dialog {
    my $return = $cui->dialog(
        -message   => "Do you really want to quit?",
        -title     => "Confirm",
        -buttons   => ['yes', 'no'],
    );

    exit(0) if $return;
}

sub create_base_window {
    my ($name) = @_;

    $cui->add(
        $name,
        'Window', 
        -border       => 1, 
        -titlereverse => 0, 
        -padtop       => 2, 
        -padbottom    => 3, 
        -ipad         => 1,
        -title        => 'CTRL-Q to quiz',
    );
}

sub create_promote_deps_window {
    my ($name) = @_;

    my $win = create_base_window($name);

    my $grid = $win->add(
        'grid',
        'Grid',
        -height       => 14,
        -width        => -1,
        -editable     => 0,
        -border       => 1,
        -process_bindings => {
            CUI_TAB => undef,
        },
        # -bg       => "blue",
        # -fg       => "white",
    );

    $grid->add_cell(
        "otp",
        -width => 10,
        -label => "OTP"
    );

    $grid->add_cell(
        "commit1",
        -width => 10,
        -label => "Commit#"
    );

    $grid->add_cell(
        "otnp",
        -width => 10,
        -label => "OTNP"
    );

    $grid->add_cell(
        "commit2",
        -width => 10,
        -label => "Commit#"
    );

    $grid->add_cell(
        "overlap",
        -width => 32,
        -label => "Overlap"
    );

    my $button_callback = sub {
        my $this = shift;

        my $btn_name = $this->get();
        if ($btn_name eq "Back") {
            # give up promotion and return to promote window
            $win->focus();
        }
        elsif ($btn_name eq "PromoteWithDeps") {
        }
    };
    $win->add(
        undef,
        'Buttonbox',
        -y        => -1,
        -buttons  => [
            {
                -label   => "< Back >",
                -value   => "Back",
                -onpress => $button_callback,
            },
            {
                -label   => "< Promote w/ all deps >",
                -value   => "PromoteWithDeps",
                -onpress => $button_callback,
            },
        ],
    );

    my @data = (
        ['HDT-10', 'e3042b0', 'HDT-7', '6741e47', 'src/tc/b.p'],
        ['HDT-10', 'e3042b0', 'HDT-7', '6741e47', 'src/tc/a.p'],
        ['HDT-10', 'e3042b0', 'HDT-7', '6741e47', 'src/tc/c.p'],
        ['HDT-10', 'e3042b0', 'HDT-7', '66a3254', 'src/tc/c.p'],
        ['HDT-10', 'e3042b0', 'HDT-7', '66a3254', 'src/tc/b.p'],
        ['HDT-10', 'e3042b0', 'HDT-7', '66a3254', 'src/tc/a.p'],
        ['HDT-10', 'e3042b0', 'HDT-8', '8b65677', 'src/tc/e.p'],
        ['HDT-10', 'e3042b0', 'HDT-8', '8b65677', 'src/tc/d.p'],
        ['HDT-10', 'e3042b0', 'HDT-9', '3eefa90', 'src/tc/f.p'],
    );
    foreach my $f (@data) {

        $grid->add_row(
            undef,
            # -fg    => 'black',
            # -bg    => 'yellow',
            -cells => {
                otp     => $f->[0],
                commit1 => $f->[1],
                otnp    => $f->[2],
                commit2 => $f->[3],
                overlap => $f->[4],
            }
        );
    }

    $grid->layout();
    return $win;
}

How can I customize the tab order so that user can shift the focus the buttons below the Curses::UI::Grid?

Thanks!

Upvotes: 3

Views: 1476

Answers (1)

Glen K
Glen K

Reputation: 115

The difficulty you're encountering with tabbing out of the grid lies not with the window's tab ordering but in the fact that the Curses::UI::Grid provides its own bindings for Tab and Shift+Tab. A basic solution is to provide your own handler for when Tab and Shift+Tab are pressed when the grid has focus:

sub move_focus {
    my $widget = $_[0];
    my $key    = $_[1];

    if ($key eq "\t") {
        $widget->parent()->focus_next();
    }
    else {
        $widget->parent()->focus_prev();
    }
}

You can then bind this handler to your grid:

$grid->set_binding(\&move_focus, "\t");
$grid->set_binding(\&move_focus, KEY_BTAB());

However, you might find using the cursor keys to move between cells is tedious, so perhaps you still want to be able to tab between cells and only jump to the buttons when the cursor is at the end of the row. In that case, your custom handler will need to be a little more intelligent:

sub move_focus {
    my $grid = $_[0];
    my $key  = $_[1];

    if ($key eq "\t") {
        my $last_cell = $grid->get_cell($grid->{_cells}[$#{$grid->{_cells}}]);
        if ($grid->get_foused_cell() == $last_cell) {
            $grid->parent()->focus_next();
        }
        else {
            $grid->next_cell();
        }
    }
    else {
        my $first_cell = $grid->get_cell($grid->{_cells}[0]);
        if ($grid->get_foused_cell() == $first_cell) {
            $grid->parent()->focus_prev();
        }
        else {
            $grid->prev_cell();
        }
    }
}

Upvotes: 2

Related Questions