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

Re: GtkCellLayout interface




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!




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