package
Gtk2OutlineEditor::CellRendererNode;
use
strict;
use
warnings;
#use rlib "X3D";
use
Gtk2;
#use X3DError;
use
Glib::Object::Subclass Gtk2::CellRenderer::,
properties
=>
[ Glib::ParamSpec->
scalar
(
"node"
,
"X3DNode"
,
"Description"
, [
qw(readable writable)
] ) ],
;
sub
INIT_INSTANCE {
my
(
$cell
) =
@_
;
$cell
->{icon} = Gtk2::IconTheme->get_default->load_icon(
'X3DNode'
, 12,
'no-svg'
);
}
sub
GET_SIZE {
#X3DError::Debug;
my
(
$cell
,
$widget
,
$area
) =
@_
;
my
$layout
=
$widget
->create_pango_layout(
""
);
$layout
->set_markup(
$cell
->format_text );
return
$cell
->calc_size(
$layout
,
$area
);
}
sub
format_text {
my
$cell
=
shift
;
my
$node
=
$cell
->{node}->getValue;
my
$name
=
$node
->getName;
return
sprintf
"<b>%s</b> %s [%d]"
,
$node
->getType,
$name
,
$cell
->{node}->getReferenceCount
if
$name
;
return
sprintf
"<b>%s</b> [%d]"
,
$node
->getType,
$cell
->{node}->getReferenceCount;
}
sub
calc_size {
my
(
$cell
,
$layout
,
$area
) =
@_
;
my
(
$width
,
$height
) =
$layout
->get_pixel_size();
return
(
icon_width + icon_space,
$area
? (
$area
->height -
$height
) / 2 - y_padding : 0,
icon_width + icon_space * 2 +
$width
+ x_padding * 2,
$height
+ y_padding * 2
);
}
sub
RENDER {
#X3DError::Debug;
my
(
$cell
,
$window
,
$widget
,
$background_area
,
$cell_area
,
$expose_area
,
$flags
) =
@_
;
my
$state
;
if
(
$flags
&
'selected'
) {
$state
=
$widget
->has_focus()
?
'selected'
:
'active'
;
}
else
{
$state
=
$widget
->state() eq
'insensitive'
?
'insensitive'
:
'normal'
;
}
$window
->draw_pixbuf(
$widget
->get_style->fg_gc(
$widget
->state ),
$cell
->{icon}, 0, 0,
$cell_area
->x() + x_padding,
$cell_area
->y() +
int
( (
$cell_area
->height - icon_height ) / 2 ),
icon_width, icon_height,
"GDK_RGB_DITHER_NONE"
, 0, 0
);
my
$layout
=
$widget
->create_pango_layout(
""
);
$layout
->set_markup(
$cell
->format_text );
my
(
$x_offset
,
$y_offset
) =
$cell
->calc_size(
$layout
,
$cell_area
);
$widget
->get_style->paint_layout(
$window
,
$state
, 1,
$cell_area
,
$widget
,
"cellrenderertext"
,
$cell_area
->x() +
$x_offset
+ icon_space + x_padding,
$cell_area
->y() +
$y_offset
+ y_padding,
$layout
);
}
1;
__END__
use strict;
use Gtk2 -init;
use Gtk2::Gdk::Keysyms;
package Kaf::CellRendererSpinButton;
use POSIX qw(DBL_MAX UINT_MAX);
use Glib qw(TRUE FALSE);
use constant x_padding => 2;
use constant y_padding => 3;
use Glib::Object::Subclass
"Gtk2::CellRenderer",
signals => {
edited => {
flags => [qw(run-last)],
param_types => [qw(Glib::String Glib::Double)],
},
},
properties => [
Glib::ParamSpec -> double("xalign", "Horizontal Alignment", "Where am i?", 0.0, 1.0, 1.0, [qw(readable writable)]),
Glib::ParamSpec -> boolean("editable", "Editable", "Can I change that?", 0, [qw(readable writable)]),
Glib::ParamSpec -> uint("digits", "Digits", "How picky are you?", 0, UINT_MAX, 2, [qw(readable writable)]),
map {
Glib::ParamSpec -> double($_ -> [0],
$_ -> [1],
$_ -> [2],
0.0,
DBL_MAX,
$_ -> [3],
[qw(readable writable)])
} (["value", "Value", "How much is the fish?", 0.0],
["min", "Min", "No way, I have to live!", 0.0],
["max", "Max", "Ah, you're too generous.", 100.0],
["step", "Step", "Okay.", 5.0])
]
;
sub INIT_INSTANCE {
my $self = shift;
$self->{editable} = 0;
$self->{digits} = 2;
$self->{value} = 0.0;
$self->{min} = 0.0;
$self->{max} = 100.0;
$self->{step} = 5.0;
$self->{xalign} = 1.0;
}
sub calc_size {
my ($cell, $layout, $area) = @_;
my ($width, $height) = $layout -> get_pixel_size();
return ($area ? $cell->{xalign} * ($area->width - ($width + 3 * x_padding)) : 0,
$area ? ($area->height - $height) / 2 - y_padding : 0,
$width + x_padding * 2,
$height + y_padding * 2);
}
sub format_text {
my $cell = shift;
my $format = sprintf '%%.%df', $cell->{digits};
sprintf $format, $cell->{value};
}
sub GET_SIZE {
my ($cell, $widget, $area) = @_;
my $layout = $cell -> get_layout($widget);
$layout -> set_text($cell -> format_text);
return $cell -> calc_size($layout, $area);
}
sub get_layout {
my ($cell, $widget) = @_;
return $widget -> create_pango_layout("");
}
sub RENDER {
my ($cell, $window, $widget, $background_area, $cell_area, $expose_area, $flags) = @_;
my $state;
if ($flags & 'selected') {
$state = $widget -> has_focus()
? 'selected'
: 'active';
} else {
$state = $widget -> state() eq 'insensitive'
? 'insensitive'
: 'normal';
}
my $layout = $cell -> get_layout($widget);
$layout -> set_text ($cell -> format_text);
my ($x_offset, $y_offset, $width, $height) =
$cell -> calc_size($layout, $cell_area);
$widget -> get_style -> paint_layout($window,
$state,
1,
$cell_area,
$widget,
"cellrenderertext",
$cell_area -> x() + $x_offset + x_padding,
$cell_area -> y() + $y_offset + y_padding,
$layout);
}
sub _cell_editing_done {
my ($self, $path, $new_value) = @_;
if ($self->{_focus_out_id}) {
$self->signal_handler_disconnect($self->{_focus_out_id});
delete $self->{_focus_out_id};
}
$self->signal_emit('edited', $path, $new_value);
}
sub START_EDITING {
my ($cell, $event, $view, $path, $background_area, $cell_area, $flags) = @_;
my $spin_button = Gtk2::SpinButton -> new_with_range($cell -> get(qw(min max step)));
$spin_button -> set_value($cell -> get("value"));
$spin_button -> set_digits($cell -> get("digits"));
$spin_button -> grab_focus();
$spin_button -> signal_connect(key_press_event => sub {
my ($spin_button, $event) = @_;
if ($event -> keyval == $Gtk2::Gdk::Keysyms{ Return } ||
$event -> keyval == $Gtk2::Gdk::Keysyms{ KP_Enter }) {
$spin_button -> update();
$cell -> _cell_editing_done($path, $spin_button -> get_value());
$spin_button -> destroy();
return TRUE;
}
elsif ($event -> keyval == $Gtk2::Gdk::Keysyms{ Up }) {
$spin_button -> spin('step-forward', ($spin_button -> get_increments())[0]);
return TRUE;
}
elsif ($event -> keyval == $Gtk2::Gdk::Keysyms{ Down }) {
$spin_button -> spin('step-backward', ($spin_button -> get_increments())[0]);
return TRUE;
}
return FALSE;
});
$spin_button -> {_focus_out_id} =
$spin_button -> signal_connect(focus_out_event => sub {
my ($spin_button, undef) = @_;
$cell -> _cell_editing_done($path, $spin_button -> get_value());
# the spinbutton needs the focus-out event, don't eat it.
return FALSE;
});
$spin_button -> show_all();
# we don't want the editor widget to be the full height of the cell;
# if the cell is taller than the spinbutton, the entry will grow, but
# the spinner buttons won't. tell the system that the cell is only
# as tall as the spinbutton wants to be, and it will do the right thing.
# this means we have to ask the spinbutton how big it wants to be; it
# hasn't been mapped yet, so we'll have to trigger an actual size_request
# calculation.
my $requisition = $spin_button->size_request;
$cell_area->y ($cell_area->y
+ ($cell_area->height - $requisition->height) / 2);
$cell_area->height ($requisition->height);
return $spin_button;
}
###############################################################################
package main;
use Glib qw(TRUE FALSE);
my $window = Gtk2::Window -> new("toplevel");
$window -> set_title ("CellRendererSpinButton");
$window -> signal_connect (delete_event => sub { Gtk2 -> main_quit(); });
my $model = Gtk2::ListStore -> new(qw(Glib::Double));
my $view = Gtk2::TreeView -> new($model);
foreach (qw(12 12.1 12.12)) {
$model -> set($model -> append(), 0 => $_);
}
sub cell_edited {
my ($cell, $path, $new_value) = @_;
$model -> set($model -> get_iter(Gtk2::TreePath -> new_from_string($path)),
0 => $new_value);
}
my $renderer = Kaf::CellRendererSpinButton -> new();
$renderer -> set(mode => "editable",
min => 0,
max => 1000,
step => 2,
digits => 0);
$renderer -> signal_connect(edited => \&cell_edited);
my $column = Gtk2::TreeViewColumn -> new_with_attributes ("no digits",
$renderer,
value => 0);
$column->set_resizable (TRUE);
$view -> append_column($column);
#
# another, centered
#
$renderer = Kaf::CellRendererSpinButton -> new();
$renderer -> set(mode => "editable",
xalign => 0.5,
min => 0,
max => 1000,
step => 0.1,
digits => 1);
$renderer -> signal_connect(edited => \&cell_edited);
$column = Gtk2::TreeViewColumn -> new_with_attributes ("one digit",
$renderer,
value => 0);
$column->set_resizable (TRUE);
$view -> append_column($column);
#
# another, left-justified
#
$renderer = Kaf::CellRendererSpinButton -> new();
$renderer -> set(mode => "editable",
xalign => 0.0,
min => 0,
max => 1000,
step => 0.1,
digits => 2);
$renderer -> signal_connect(edited => \&cell_edited);
$column = Gtk2::TreeViewColumn -> new_with_attributes ("two digits",
$renderer,
value => 0);
$column->set_resizable (TRUE);
$view -> append_column($column);
$window -> add($view);
$window -> show_all();
Gtk2 -> main();