On Dec 30, 2007, at 12:30 AM, muppet wrote:
The _ADD_INTERFACE() xsub necessary for perl code to implement an interface does not exist in Gtk2::CellLayout, so it appears you can't implement one in perl at the moment. It shouldn't be that hard to knock up a patch...
...like this. The patch is smaller than the example code, which is lifted from GtkCellView in gtk+ HEAD.
Attachment:
celllayoutiface.patch
Description: Binary data
#!/usr/bin/perl -w
package MupCellLayout;
use strict;
use warnings;
use Gtk2;
use Glib ':constants';
use Carp qw(croak);
use Glib::Object::Subclass
Gtk2::Widget::,
signals => {
size_request => \&do_size_request,
size_allocate => \&do_size_allocate,
expose_event => \&do_expose_event,
},
properties => [
{
pspec => Glib::ParamSpec->object ('model', 'Model',
'The data model',
Gtk2::TreeModel::,
['readable', 'writable']),
set => sub {
my ($self, $model) = @_;
delete $self->{displayed_row};
$self->{model} = $model;
},
},
{
pspec => Glib::ParamSpec->boxed ('displayed-row', 'Displayed Row',
'Row to display in model',
Gtk2::TreePath::,
['readable', 'writable']),
get => sub {
my ($self) = @_;
return $self->{displayed_row}
? $self->{displayed_row}->get_path ()
: undef;
},
set => sub {
my ($self, $path) = @_;
croak "Trying to set the displayed row without a model!"
unless $self->{model};
$self->{displayed_row} =
Gtk2::TreeRowReference->new ($self->{model}, $path);
$self->queue_resize ();
$self->queue_draw ();
},
},
Glib::ParamSpec->int ('spacing', 'Spacing',
'Pixels between packed renderers',
0, 20, 2, ['readable', 'writable']),
],
interfaces => [ qw( Gtk2::CellLayout ) ],
;
sub INIT_INSTANCE {
my ($self) = @_;
$self->no_window (TRUE);
$self->{cells} = [];
}
sub FINALIZE_INSTANCE {
my ($self) = @_;
$self->clear ();
delete $self->{model};
delete $self->{cells};
delete $self->{displayed_row};
}
sub _set_cell_data {
my $self = shift;
my $path = $self->{displayed_row}->get_path;
my $iter = $self->{model}->get_iter ($path);
foreach my $info (@{ $self->{cells} }) {
$info->{renderer}->freeze_notify ();
foreach my $attr (@{ $info->{attributes} }) {
my $val = $self->{model}->get ($iter, $attr->{column});
$info->{renderer}->set ($attr->{property}, $val);
}
$info->{renderer}->thaw_notify ();
}
}
sub do_size_request {
my ($self, $requisition) = @_;
my $width = 0;
my $height = 0;
my $spacing = $self->get ('spacing');
$self->_set_cell_data () if $self->{displayed_row};
my $first_cell = TRUE;
foreach my $info (@{ $self->{cells} }) {
next unless $info->{renderer}->get ('visible');
$width += $spacing if $first_cell;
my (undef, undef, $w, $h) =
$info->{renderer}->get_size ($self, undef);
$info->{requested_width} = $w;
$width += $w;
$height = $h if $h > $height;
$first_cell = FALSE;;
}
$requisition->width ($width);
$requisition->height ($height);
}
sub do_size_allocate {
my ($self, $allocation) = @_;
# XXX need a source hack to do this...
#$self->allocation ($allocation);
$self->allocation->x ($allocation->x);
$self->allocation->y ($allocation->y);
$self->allocation->width ($allocation->width);
$self->allocation->height ($allocation->height);
my $spacing = $self->get ('spacing');
my $expand_cell_count = 0;
my $full_requested_width = 0;
my $first_cell = TRUE;
foreach my $info (@{ $self->{cells} }) {
next unless $info->{renderer}->get ('visible');
$full_requested_width += $spacing if $first_cell;
$full_requested_width += $info->{requested_width};
$expand_cell_count++ if $info->{expand};
$first_cell = FALSE;;
}
my $extra_space = $allocation->width - $full_requested_width;
if ($extra_space < 0) {
$extra_space = 0;
} elsif ($extra_space > 0 && $expand_cell_count > 0) {
$extra_space /= $expand_cell_count;
}
foreach my $info (@{ $self->{cells} }) {
next unless $info->{from} eq 'start';
next unless $info->{renderer}->get ('visible');
$info->{real_width} = $info->{requested_width}
+ ($info->{expand} ? $extra_space : 0);
}
foreach my $info (@{ $self->{cells} }) {
next unless $info->{from} eq 'end';
next unless $info->{renderer}->get ('visible');
$info->{real_width} = $info->{requested_width}
+ ($info->{expand} ? $extra_space : 0);
}
}
sub do_expose_event {
my ($self, $event) = @_;
my $rtl = $self->get_direction eq 'rtl';
return FALSE unless $self->drawable;
# "blank"
# XXX
if ($self->{displayed_row}) {
$self->_set_cell_data ()
} elsif ($self->{model}) {
return FALSE;
}
my $area = Gtk2::Gdk::Rectangle->new ($self->allocation->values);
$area->x = $self->allocation->width if $rtl;
my $state = $self->state eq 'prelight' ? ['prelit'] : [];
foreach my $info (@{ $self->{cells} }) {
next unless $info->{from} eq 'start';
next unless $info->{renderer}->get ('visible');
$area->width ($info->{real_width});
#$area->x -= $area->width if $rtl;
$info->{renderer}->render ($event->window, $self,
$area, $area, $event->area,
$state);
$area->x ($area->x + $info->{real_width})
unless $rtl;
}
$area->x ($rtl
? $self->allocation->x
: $self->allocation->x + $self->allocation->width);
foreach my $info (@{ $self->{cells} }) {
next unless $info->{from} eq 'end';
next unless $info->{renderer}->get ('visible');
$area->width ($info->{real_width});
$area->x ($area->x - $area->width) if !$rtl;
$info->{renderer}->render ($event->window, $self,
$area, $area, $event->area,
$state);
$area->x ($area->x + $info->{real_width})
if $rtl;
}
}
sub real_pack {
my ($self, $cell, $expand, $from) = @_;
push @{ $self->{cells} }, {
renderer => $cell,
expand => $expand,
from => $from,
};
}
sub PACK_START {
my ($self, $cell, $expand) = @_;
print "PACK_START @_\n";
real_pack $self, $cell, $expand, 'start';
}
sub PACK_END {
my ($self, $cell, $expand) = @_;
print "PACK_END @_\n";
real_pack $self, $cell, $expand, 'end';
}
sub CLEAR {
my ($self) = @_;
print "CLEAR @_\n";
}
sub ADD_ATTRIBUTE {
my ($self, $cell, $attribute, $column) = @_;
print "ADD_ATTRIBUTE @_\n";
foreach my $info (@{ $self->{cells} }) {
if ($info->{renderer} == $cell) {
push @{ $info->{attributes} }, {
property => $attribute,
column => $column,
};
}
}
}
sub SET_CELL_DATA_FUNC {
my ($self, $cell, $func) = @_;
print "SET_CELL_DATA_FUNC @_\n";
}
sub CLEAR_ATTRIBUTES {
my ($self, $cell) = @_;
print "CLEAR_ATTRIBUTES @_\n";
foreach my $info (@{ $self->{cells} }) {
if ($info->{renderer} == $cell) {
$info->{attributes} = [];
}
}
}
sub REORDER {
my ($self, $cell, $position) = @_;
print "REORDER @_\n";
for (my $i = 0 ; $i < @{ $self->{cells} } ; $i++) {
if ($self->{cells}[$i]{renderer} == $cell) {
my $info = splice @{ $self->{cells} }, $i, 1;
splice @{ $self->{cells} }, $position, 0, $i;
return;
}
}
}
sub GET_CELLS {
my $self = shift;
print "GET_CELLS @_\n";
return map { $_->{renderer} } @{ $self->{cells} };
}
package main;
use strict;
use warnings;
use Gtk2 -init;
use Glib ':constants';
my @stuff = qw(one two three four five six seven eight nine ten);
my $model = Gtk2::ListStore->new ('Glib::String', 'Glib::Int');
foreach my $i (0..$#stuff) {
$model->set ($model->append, 0, $stuff[$i], 1, $i);
}
my $layout = MupCellLayout->new (model => $model);
my $cell = Gtk2::CellRendererText->new ();
$layout->pack_start ($cell, TRUE);
$layout->add_attribute ($cell, text => 0);
$cell = Gtk2::CellRendererText->new ();
$layout->pack_end ($cell, FALSE);
$layout->add_attribute ($cell, text => 1);
my $combo = Gtk2::ComboBox->new ($model);
$cell = Gtk2::CellRendererText->new ();
$combo->pack_start ($cell, FALSE);
$combo->add_attribute ($cell, text => 0);
$cell = Gtk2::CellRendererText->new ();
$combo->pack_start ($cell, FALSE);
$combo->add_attribute ($cell, text => 1);
$combo->signal_connect (changed => sub {
$layout->set (displayed_row => $model->get_path ($combo->get_active_iter ()));
});
$combo->set_active (2);
my $window = Gtk2::Window->new;
my $vbox = Gtk2::VBox->new;
my $frame = Gtk2::Frame->new;
$frame->set_shadow_type ('in');
$window->add ($vbox);
$vbox->add ($frame);
$frame->add ($layout);
$vbox->add ($combo);
$window->show_all ();
$window->signal_connect (destroy => sub { Gtk2->main_quit });
Gtk2->main;
-- zella (crying): I want... us: What? zella (still crying): I want... something!