NAME

Gtk2::Ex::CellLayout::Base -- basic Gtk2::CellLayout implementation functions

SYNOPSIS

package MyNewViewer;
use Gtk2;
use base 'Gtk2::Ex::CellLayout::Base';

use Glib::Object::Subclass
 Gtk2::Widget::,
 interfaces => [ 'Gtk2::CellLayout', 'Gtk2::Buildable' ],
 properties => [ ... ];

sub my_expose {
  my ($self, $event) = @_;
  $self->_set_cell_data;
  foreach my $cellinfo (@$self->{'cellinfo_list'}) {
    next unless $cell->{'pack'} eq 'start';
    $cellinfo->{'cell'}->render (...);
  }
  ...
}

DESCRIPTION

Gtk2::Ex::CellLayout::Base provides a basic set of functions for use by new data viewer widgets written in Perl and wanting to implement the Gtk2::CellLayout interface. This means

PACK_START
PACK_END
CLEAR
ADD_ATTRIBUTE
CLEAR_ATTRIBUTES
SET_CELL_DATA_FUNC
REORDER
GET_CELLS

The functions maintain a list of Gtk2::CellRenderer objects packed into the viewer widget, with associated attribute settings or data setup function.

Gtk2::Ex::CellLayoutBase is designed as a multiple-inheritance superclass to be brought in with use base as in the synopsis above (see base). Because of this you can enhance it or override it by writing your own versions of the functions offered, chaining (or not) to the originals with SUPER in the usual way.

CELL INFO LIST

Gtk2::Ex::CellLayout::Base keeps information on the added cell renderers in $self->{'cellinfo_list'} on the viewer widget. This field is an array reference, created when first needed. Each element in the array is a hash reference, with the hash containing

cell               Gtk2::CellRenderer object
pack               string 'start' or 'end'
expand             boolean
attributes         hash ref { propname => colnum }
datafunc           code ref or undef
datafunc_userdata  any scalar

cell is the renderer object added in by pack_start or pack_end, and expand the flag passed in those calls. The pack field is "start" or "end" according to which function was used. Those "start" and "end" values are per the Gtk2::PackType enumeration, though that enum doesn't often arise in the context of a viewer widget.

attributes is a hash table of property name to column number built by add_attribute or set_attributes. Likewise datafunc and datafunc_userdata from set_cell_data_func. Both are used when preparing the renderers to draw a particular row of the Gtk2::TreeModel.

The widget size_request and expose operations are the two most obvious places the cell information is needed. Both will want to prepare the renderers with data from the model then ask their size and in the case of expose do some drawing. The following function is designed to prepare the renderers

$self->_set_cell_data ($iter, [propname=>value])

Set the property values in all the cell renderers packed into $self, ready to draw the model row given by $iter. The model object is expected to be in $self->{'model'} and the $self->{'cellinfo_list'} attributes described above are used.

Extra propname=>value parameters can be given, to be applied to all the renderers. For example the is_expander and is_expanded properties could be set according to the viewer's state (and whether the model row has children and can be expanded).

Here's a minimal size_request handler for a viewer like the core Gtk2::CellView which displays a single row of a model, with each renderer one after the other horizontally. The width is the total of all renderers, and the height is the maximum among them. It could look like

sub do_size_request {
  my ($self, $requisition) = @_;
  $iter = $self->{'model'}->get_nth_iter ($self->{'rownum'});
  my $total_width = 0;
  my $max_height = 0;

  $self->_set_cell_data ($iter);
  foreach my $cellinfo (@{$self->{'cellinfo_list'}}) {
    my $cell = $cellinfo->{'cell'};
    my (undef,undef, $width,$height) = $cell->get_size($self,undef);
    $total_width += $width;
    $max_height = max ($max_height, $height);
  }
  $requisition->width ($total_width);
  $requisition->height ($max_height);
}

An expose handler will be a little more complicated, firstly the cells shouldn't drawn in cellinfo_list order, but instead the pack_start ones from the left, then the pack_end ones from the right. And the expand flag is meant to indicate which cells (if any) should grow to fill available space when there's more than needed.

BUILDABLE INTERFACE

Gtk2::Ex::CellLayout::Base provides the following functions for use by a viewer widget also implementing the Gtk2::Buildable interface.

ADD_CHILD
CUSTOM_TAG_START

To use them you must put "Gtk2::Buildable" in your interfaces list along with Gtk2::CellLayout (as shown in "SYNOPSIS" above). (If you don't then you can still create a viewer object with buildable, but not add renderers as "children".) As with the CellLayout functions above you can override with your own versions and chain (or not) with SUPER in the usual way.

The functions implement the same syntax as the core widgets like Gtk2::TreeViewColumn. Renderers are added to layout objects with <child>, and after the <object> form an <attributes> does the equivalent of the add_attribute setups. The GtkTreeView documentation has an example of GtkTreeViewColumn. Here's another with a hypothetical MyNewViewer class,

<object class="MyNewViewer" id="myviewer">
  <property name="model">myliststore</property>
  <child>
    <object class="GtkCellRendererText" id="myrenderer">
      <property name="underline">single</property>
    </object>
    <attributes>
      <attribute name="text">0</attribute>
    </attributes>
  </child>
</object>

A renderer "child" added this way is added using pack_start and "expand" false. This is the same as the core widgets, and like the core there's currently no way to instead use pack_end or expand. (child has a type option which might be pressed into service, or GtkBox has expand etc as settable properties, but we'd prefer to let the Gtk core take the lead on that.)

As of Gtk2-Perl 1.181 there's no chaining up to tag handlers in widget superclasses, which means a buildable interface like this loses anything those superclasses add to GtkBuilder's standard forms. In particular for example you loose <accelerator> and <accessibility> from GtkWidget. Not sure how bad that is in practice, hopefully a future Gtk2-Perl will allow chaining, or do it automatically.

OTHER NOTES

The cellinfo_list idea is based on the similar cell info lists maintained inside the core Gtk2::TreeViewColumn, Gtk2::CellView and Gtk2::IconView widgets. With elements as hashes there's room for widget code to hang extra information, like the "editing" flag of IconView, or the focus flag and calculated width TreeViewColumn keeps.

The _set_cell_data function provided above is also similar to what the core widgets do. Gtk2::TreeViewColumn even makes its version of that public as cell_set_cell_data. It's probably equally valid to setup one renderer at a time as it's used, rather than all at once; so perhaps in the future Gtk2::Ex::CellLayout::Base might offer something for that, maybe even as a method on the cellinfo_list elements if they were blessed to become objects.

The display layout intended by pack_start and pack_end isn't well described in the GtkCellLayout documentation, but it's the same as GtkBox so see there for details. It might be wondered why cellinfo_list isn't maintained with starts and ends separated in the first place, since that's what will be wanted for drawing. The reason is the reorder method which works in terms of renderers added in sequence, with pack_start and pack_end together, counting from 0. This makes more sense in GtkBox where pack type can be changed later (something CellLayout doesn't do).

Perhaps in the future Gtk2::Ex::CellLayout::Base could offer functions to pick the start elements out from the ends. But if your expose code uses two loops in the style of say the core Gtk2::CellView then it's just as easy to skip the opposite ones as you go. Otherwise a couple of greps and reverse gives you all elements in display order if you really want that. Eg.

my @disps = (grep ({$_->{'pack'} eq 'start'} @$cellinfo_list),
             reverse grep {$_->{'pack'} eq 'end'} @$cellinfo_list);

The GET_CELLS method is always provided but only used if Gtk2-Perl was compiled against Gtk version 2.12 or later where the gtk_cell_layout_get_cells function was introduced. Within viewer widget code if you want all the renderers (which is simply the cell fields picked out of cellinfo_list) then it's suggested you call capital GET_CELLS rather than worry whether the lowercase get_cells is available or not.

SEE ALSO

Gtk2::CellLayout, Gtk2::CellRenderer