Re: Two SimpleLists with one data stucture




On May 30, 2006, at 11:51 AM, Vasya Leushin wrote:

muppet ÐÐÑÐÑ:

Some questions come up that prevent me coming up with a useful
example... what should the combo renderer display when not showing the menu, what do the columns mean, etc, etc. Can you describe the context
of the problem in a bit more detail?

Columns 1 is a number of channel, col 2 is a name of the channel, they
are  not editable.
Col 3 is a  value of corresponding channel (editable) which we can
change by editing the cell.
Model for col 4 contains array of presets, where each element is array
with 2 numbers (max. value and mid. value)
and one string as a description (3 elements in total). CellRenderer
(which is combo)for this model
 should display only descriptions and nothing else. If i choose one of
these descriptions in the combo
then two things happen:
1. This description appears in the cell
2. Corresponding mid. value goes to column 3.
In case of 'Blue' this is 15. So, we can forget max value for a while...


This sort of interaction starts to get a little painful in SimpleList, so here's a simplistic stab at that functionality with the bare TreeView API. This displays your data in three view columns, the Number, Name, and Value columns. The value column is editable, allowing the user to type a number, but also has a pulldown menu of presets. The tricky bit here is that the CellRendererCombo will fill the entry with the text of the menu item, which is a string, not a number, so we have to look up the corresponding value when the cell is edited. Also, from what i can tell, you cannot control the display of the menu beyond telling it to display one particular column. To change that behavior you'd have to either subclass the CellRendererCombo and override the START_EDITING method in order to customize the menu, etc, or write a new custom cell renderer. (There are cell renderer examples in the Gtk2 source distribution.)

Other tricks here involve using named constants for the column indices (because i kept forgetting what was what), view columns unrelated to model columns, using a nontrivial cell-edited callback which mangles the input data, and storing the CellRendererCombo's model in a column of the main model.

-=-=-=-=-=-=-
#!/usr/bin/perl -w

use strict;
use Glib ':constants';
use Gtk2 -init;

# Column types for the main model
use constant {
        CHANNEL_NUMBER  => 0,
        CHANNEL_NAME    => 1,
        CHANNEL_VALUE   => 2,
        CHANNEL_PRESETS => 3, # list of presets for this channel
};
my @main_column_types;
$main_column_types[CHANNEL_NUMBER]  = 'Glib::Int';
$main_column_types[CHANNEL_NAME]    = 'Glib::String';
$main_column_types[CHANNEL_VALUE]   = 'Glib::Int';
$main_column_types[CHANNEL_PRESETS] = 'Gtk2::ListStore';

# Column types for the subvalue models
use constant {
        PRESET_MAXVAL => 0,
        PRESET_MIDVAL => 1,
        PRESET_NAME   => 2,
};
my @preset_column_types;
$preset_column_types[PRESET_MAXVAL] = 'Glib::Int';
$preset_column_types[PRESET_MIDVAL] = 'Glib::Int';
$preset_column_types[PRESET_NAME]   = 'Glib::String';


#
# now create a model and fill it.
#
my $model = Gtk2::ListStore->new (@main_column_types);
foreach (
    [1, 'Volume',   0, [[255,  32, 'Preset1'], [255, 192, 'Preset2']]],
[2, 'Pan', 64, [[128, 0, 'Hard left'], [128, 128, 'Hard right']]],
    [3, 'Treble', 128, [[255, 196, 'high frequencies']]],
    [4, 'Mid',    128, [[255,  64, 'midrange frequencies']]],
    [5, 'Bass',   128, [[255, 140, 'low frequencies']]],
) {
        my ($number, $name, $value, $presets) = @$_;
        my $submodel = Gtk2::ListStore->new (@preset_column_types);
        foreach my $p (@$presets) {
                $submodel->set ($submodel->append,
                                PRESET_MAXVAL, $p->[0],
                                PRESET_MIDVAL, $p->[1],
                                PRESET_NAME,   $p->[2]);
        }
        $model->set ($model->append,
                     CHANNEL_NUMBER,  $number,
                     CHANNEL_NAME,    $name,
                     CHANNEL_VALUE,   $value,
                     CHANNEL_PRESETS, $submodel);
}


#
# now set up a view for that model
#

my $treeview = Gtk2::TreeView->new ($model);

# The first two columns are rather boring.
$treeview->insert_column_with_attributes
        (-1, 'Number', Gtk2::CellRendererText->new, text => CHANNEL_NUMBER);
$treeview->insert_column_with_attributes
        (-1, 'Name', Gtk2::CellRendererText->new, text => CHANNEL_NAME);

# For displaying and editing the value, we'll use the CellRendererCombo.
# This will display the current value, and offer an entry to edit it;
# but when in editing mode, there will also be a little button that allows
# the user to pull down a menu of presets.
my $cell = Gtk2::CellRendererCombo->new;
$cell->set (editable => TRUE, # without this, it's just a text cell
            text_column => PRESET_NAME); # submodel col to display in the menu
$treeview->insert_column_with_attributes (-1, "Value", $cell,
                                          text => CHANNEL_VALUE,
                                          model => CHANNEL_PRESETS);
$cell->signal_connect (edited => sub {
        my ($cell, $path_string, $new_text) = @_;
my $iter = $model->get_iter (Gtk2::TreePath->new_from_string ($path_string));
        # If the user chose a preset, we will receive the text of the preset
        # name, since that's what was shown in the menu.  We can't set that
        # into the value column, so we'll have to look up the corresponding
        # value from the submodel.
        if ($new_text !~ /^\d+$/) {
                my $submodel = $model->get ($iter, CHANNEL_PRESETS);
                my $subiter = $submodel->get_iter_first;
                while ($subiter) {
                        my $name = $submodel->get ($subiter, PRESET_NAME);
                        $new_text = $submodel->get ($subiter, PRESET_MIDVAL)
                                if $new_text eq $name;
                        $subiter = $submodel->iter_next ($subiter);
                }
        }
        # note that if the user typed text that wasn't a preset name, this
        # could still not be a number.
        $model->set ($iter, CHANNEL_VALUE, $new_text)
                if $new_text =~ /^\d+$/;
});


#
# and, finally, put all of that on the screen.
#
my $window = Gtk2::Window->new;
$window->signal_connect (destroy => sub { Gtk2->main_quit });
$window->add ($treeview);
$window->set_default_size (300, 0);
$window->show_all;
Gtk2->main;



--
I bring the rock, and provided it is fiscally responsible, I will bring the funk as well. And that's fo-shizzle.
    -- Saturday Night Live




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