Gtk2::Ex::CellLayout::Base -- basic Gtk2::CellLayout implementation functions
package MyNewViewer; use Gtk2 1.180; # to have CellLayout as an interface use base 'Gtk2::Ex::CellLayout::Base'; use Glib::Object::Subclass 'Gtk2::Widget', interfaces => [ 'Gtk2::CellLayout', 'Gtk2::Buildable' ]; sub my_expose { my ($self, $event) = @_; $self->_set_cell_data; foreach my $cellinfo ($self->_cellinfo_starts) { $cellinfo->{'cell'}->render (@render_args); } foreach my $cellinfo ($self->_cellinfo_ends) { $cellinfo->{'cell'}->render (@render_args); } return Gtk2::EVENT_PROPAGATE; }
Gtk2::Ex::CellLayout::Base provides the following functions for use by a new data viewer widget written in Perl and wanting to implement the CellLayout interface (see Gtk2::CellLayout).
Gtk2::Ex::CellLayout::Base
PACK_START ($self, $cell, $expand) PACK_END ($self, $cell, $expand) CLEAR ($self) ADD_ATTRIBUTE ($self, $cell, $attribute, $column) CLEAR_ATTRIBUTES ($self, $cell) SET_CELL_DATA_FUNC ($self, $cell, $func, $userdata) REORDER ($self, $cell, $position) @list = GET_CELLS ($self)
The functions maintain a list of Gtk2::CellRenderer objects in the viewer widget, together with associated attribute settings and/or data setup function.
Gtk2::CellRenderer
CellLayout::Base is designed as a multiple-inheritance mix-in to add to your @ISA. use base per the synopsis above (see base) is one way to do that. (If you set @ISA yourself be careful not to lose what Glib::Object::Subclass sets up.)
CellLayout::Base
@ISA
use base
Glib::Object::Subclass
You can enhance or override some of CellLayout::Base by writing your own versions of the functions, and then chain up (or not) to the originals with SUPER in the usual way.
SUPER
Gtk2-Perl 1.180 or higher is required for Gtk2::CellLayout as an interface. (You also need that version for Gtk2::Buildable to override the widget superclass Buildable, per "BUILDABLE INTERFACE" below.)
Gtk2::CellLayout
Gtk2::Buildable
Gtk2::Ex::CellLayout::Base keeps information on the added cell renderers in $self->{'cellinfo_list'} on the viewer widget. This field is an arrayref, created when first needed, and each element in the array is a hashref.
$self->{'cellinfo_list'}
[ { cell => $renderer1, pack => 'start', expand => 1, attributes => { text => 3 }, datafunc => \&somefunc, datafunc_userdata => 'xyz' }, { cell => $renderer2, ... }, ... ]
The element fields are
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 is the flag passed in those calls. The pack field is "start" or "end" according to which function was used. "start" and "end" values are per the Gtk2::PackType enumeration, but that enum doesn't normally arise in the context of a viewer widget.
cell
pack_start
pack_end
expand
pack
"start"
"end"
Gtk2::PackType
attributes is a hash table of property name to column number established by add_attribute and set_attributes. datafunc and datafunc_userdata come from set_cell_data_func. These are all used when preparing the renderers to draw a particular row of the Gtk2::TreeModel.
attributes
add_attribute
set_attributes
datafunc
datafunc_userdata
set_cell_data_func
Gtk2::TreeModel
The widget size_request and expose operations are the two most obvious places the cell information is needed. Both will prepare the renderers with data from the model, then ask their sizes or do some drawing. The following function is designed to prepare the renderers.
size_request
expose
$self->_set_cell_data ($iter)
$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.
$self
$iter
$self->{'model'}
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.
propname=>value
is_expander
is_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
Gtk2::CellView
sub do_size_request { my ($self, $requisition) = @_; my $model = $self->{'model'}; my $iter = $model->iter_nth_child (undef, $self->{'rownum'}); $self->_set_cell_data ($iter); my $total_width = 0; my $max_height = 0; 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 is a little more complicated, firstly the cells shouldn't drawn in cellinfo_list order, but instead the start ones on the left, then the end ones from the right (see _cellinfo_starts and _cellinfo_ends below). And the expand flag is meant to indicate which cells (if any) should grow to fill available space when there's more than needed.
cellinfo_list
start
end
_cellinfo_starts
_cellinfo_ends
$self->_cellinfo_starts
$self->_cellinfo_ends
Return the cellinfo_list elements which are from either pack_start or pack_end respectively. These are simply greps of cellinfo_list looking for the pack field set to start or end. In an expose or similar you work across the starts from the left then the ends from the right, towards the centre (or usually reversed to "start"s on the right in rtl mode).
rtl
my $x = 0; foreach my $cellinfo ($self->_cellinfo_starts) { ... $x += $cell_width; } $x = $window_width; foreach my $cellinfo ($self->_cellinfo_ends) { $x -= $cell_width; ... }
Gtk2::Ex::CellLayout::Base also provides the following functions for use by a viewer widget implementing the Gtk2::Buildable interface. As with the CellLayout functions above you can override with your own versions and chain (or not) with SUPER in the usual way.
ADD_CHILD ($self, $builder, $child, $type) $buildattrs = CUSTOM_TAG_START ($self, $builder, $child, $tagname)
To use these functions put "Gtk2::Buildable" in your interfaces list along with Gtk2::CellLayout, as shown in the "SYNOPSIS" above. Buildable is new in Gtk 2.12, so you must depend on that, or conditionalize to omit it in past versions, eg.
"Gtk2::Buildable"
interfaces
interfaces => [ 'Gtk2::CellLayout', # Gtk2::Buildable is new in Gtk 2.12, omit if not available Gtk2::Widget->isa('Gtk2::Buildable') ? ('Gtk2::Buildable') : () ],
If you don't put Gtk2::Buildable in the interfaces at all you can still create a viewer object with the buildable features inherited from Gtk2::Widget, but you can't add renderers as children within the XML.
Gtk2::Widget
The ADD_CHILD and CUSTOM_TAG_START functions provided here implement the same syntax as the core widgets like Gtk2::TreeViewColumn, which means renderers added to layout objects with <child>, and then <attributes> for add_attribute() style setups on those renderers. The GtkTreeView documentation has an example for GtkTreeViewColumn. Here's another with a hypothetical MyNewViewer class,
ADD_CHILD
CUSTOM_TAG_START
Gtk2::TreeViewColumn
<child>
<attributes>
add_attribute()
GtkTreeView
GtkTreeViewColumn
MyNewViewer
<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 calls pack_start with "expand" false. This is the same as the core widgets, and like in the core there's currently no way to instead use pack_end or set expand. (child has a type option which might be pressed into service, or GtkBox has expand etc as settable properties, but best let Gtk take the lead on that.)
child
type
GtkBox
As of Gtk2-Perl 1.221 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 tags. 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.
GtkBuilder
<accelerator>
<accessibility>
GtkWidget
The cellinfo_list idea is based on the similar cell info lists maintained inside the core Gtk2::TreeViewColumn, Gtk2::CellView and Gtk2::IconView. Elements are hashes so there's room for widget code to hang extra information, like the "editing" flag of IconView, or the focus flag and calculated renderer width of TreeViewColumn.
Gtk2::IconView
IconView
TreeViewColumn
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 $column->cell_set_cell_data. It probably works equally well to setup one renderer at a time as it's used, rather than all at once. Perhaps in the future Gtk2::Ex::CellLayout::Base could offer something for that, maybe even as a method on the cellinfo_list elements if they became objects as such.
_set_cell_data
$column->cell_set_cell_data
The display order intended by pack_start and pack_end isn't described very well in the GtkCellLayout interface documentation, but it's the same as GtkBox so see there for details. You might wonder why cellinfo_list isn't maintained with starts and ends separated in the first place, since that's wanted for drawing. The reason is the reorder method works on the renderers in the order added, counting from 0, with pack_start and pack_end together. This makes sense in GtkBox where the pack type can be changed later, though for CellLayout the pack type doesn't change (or not natively at least).
GtkCellLayout
reorder
CellLayout
The GET_CELLS method is always provided, though it's only used if Gtk2-Perl is compiled against Gtk version 2.12 or higher which introduces gtk_cell_layout_get_cells. If you want all the renderers within your widget code (which means simply the cell fields picked out of cellinfo_list) then you can call capital GET_CELLS rather than worry whether lowercase get_cells is available or not.
GET_CELLS
gtk_cell_layout_get_cells
get_cells
Gtk2::CellLayout, Gtk2::CellRenderer
http://user42.tuxfamily.org/gtk2-ex-celllayout-base/
Copyright 2007, 2008, 2009, 2010 Kevin Ryde
Gtk2-Ex-CellLayout-Base is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.
Gtk2-Ex-CellLayout-Base is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Gtk2-Ex-CellLayout-Base. If not, see http://www.gnu.org/licenses/.
To install Gtk2::Ex::CellLayout::Base, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Gtk2::Ex::CellLayout::Base
CPAN shell
perl -MCPAN -e shell install Gtk2::Ex::CellLayout::Base
For more information on module installation, please visit the detailed CPAN module installation guide.