#!/usr/bin/perl -w =doc Implement a custom CellRenderer with a multi-line editor, by deriving a TextView subclass which implements the CellEditable GInterface. =cut # # Copyright (C) 2003 by muppet. # # This library is free software; you can redistribute it and/or modify it under # the terms of the GNU Library General Public License as published by the Free # Software Foundation; either version 2.1 of the License, or (at your option) # any later version. # # This library 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 Library General Public License for # more details. # # You should have received a copy of the GNU Library General Public License # along with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA. # # $Id$ # use strict; use Gtk2 -init; use Gtk2::Gdk::Keysyms; ############################################################################# # First, we need a TextView which implements CellEditable. package Mup::MultilineEntry; use Data::Dumper; use constant TRUE => 1; use constant FALSE => 0; use Glib::Object::Subclass Gtk2::TextView::, # tell Glib that this new type will implement the CellEditable # GInterface. interfaces => [ Gtk2::CellEditable:: ], ; sub set_text { shift->get_buffer->set_text (shift); } sub get_text { my $buffer = shift->get_buffer; $buffer->get_text ($buffer->get_start_iter, $buffer->get_end_iter, TRUE); } sub START_EDITING { warn "start editing\n"; } sub EDITING_DONE { warn "editing done\n"; } sub REMOVE_WIDGET { warn "remove widget\n"; } ############################################################################### # and now, a CellRenderer that uses Mup::MultilineEntry for editing. package Mup::CellRendererMultiline; use Glib qw(TRUE FALSE); use Glib::Object::Subclass "Gtk2::CellRendererText", ; sub START_EDITING { my ($cell, $event, $view, $path, $background_area, $cell_area, $flags) = @_; my $entry = Mup::MultilineEntry->new; $entry->set (border_width => $cell->get ('ypad')); $entry->set_text ($cell->get ('text')); $entry->grab_focus; $entry->signal_connect (key_press_event => sub { my ($widget, $event) = @_; if (($event->keyval == $Gtk2::Gdk::Keysyms{Return} || $event->keyval == $Gtk2::Gdk::Keysyms{KP_Enter}) and not $event->state & 'control-mask') { $cell->signal_emit (edited => $path, $entry->get_text); $entry->destroy; return TRUE; } return FALSE; }); # Make sure the entry has the correct height. On some versions of # gtk+, the entry would otherwise be just a few pixels tall. $entry->set (height_request => $cell_area->height); $entry->show; return $entry; } ############################################################################### # driver code. package main; use Glib qw(TRUE FALSE); my $window = Gtk2::Window->new; $window->set_title ("Multiline CellRenderer"); $window->signal_connect (delete_event => sub { Gtk2->main_quit; FALSE }); my $model = Gtk2::ListStore->new (qw(Glib::String)); my $view = Gtk2::TreeView->new ($model); foreach ('this is a test', "here's some text\nwith newlines in\nain't it cool\nno rubbish bin", "try editing with both\nrenderers.", "in the custom one\nuse Ctrl+Enter to\nadd a new line") { $model->set ($model->append, 0 => $_); } sub cell_edited { my ($cell, $path, $new_value) = @_; my $iter = Gtk2::TreePath->new_from_string ($path); $model->set ($model->get_iter ($iter), 0 => $new_value); } my $renderer = Mup::CellRendererMultiline->new; $renderer->set (editable => TRUE); $renderer->signal_connect (edited => \&cell_edited); my $column = Gtk2::TreeViewColumn->new_with_attributes ("custom renderer", $renderer, text => 0); $view->append_column ($column); $renderer = Gtk2::CellRendererText->new; $renderer->set (editable => TRUE); $renderer->signal_connect (edited => \&cell_edited); $column = Gtk2::TreeViewColumn->new_with_attributes ("standard renderer", $renderer, text => 0); $view->append_column ($column); my $scroller = Gtk2::ScrolledWindow->new; $scroller->set_policy (qw(automatic automatic)); $scroller->add ($view); my $check = Gtk2::CheckButton->new ('resizable columns'); $check->set_active (FALSE); $check->signal_connect (toggled => sub { map { $_->set_resizable ($check->get_active); } $view->get_columns; }); my $box = Gtk2::VBox->new; $box->add ($scroller); $box->pack_start ($check, FALSE, FALSE, 0); $window->add ($box); $window->set_default_size (300, 200); $window->show_all; Gtk2->main;