#!/usr/bin/perl -w
#
# Stock Item and Icon Browser
#
# This source code for this demo doesn't demonstrate anything
# particularly useful in applications. The purpose of the "demo" is
# just to provide a handy place to browse the available stock icons
# and stock items.
#
package stock_browser;
use Glib qw(TRUE FALSE);
use Gtk2;
my $window = undef;
#
# The C version of this sample defines a structure called StockItemInfo
# to hold information about the stock items; it makes StockItemInfo into
# a new boxed type so that, when used with the GtkListStore, all the
# memory management happens properly.
#
# in perl we don't do such things. the StockItemInfo structure becomes
# just a perl hash, and we store it in the Gtk2::ListStore in a column
# with the Glib::Scalar type. this way all the memory management happens
# properly and you don't have to think up elaborate schemes to do so
# (because i already did it for you).
#
sub id_to_macro {
my $id = shift;
my $macro = uc($id);
$macro =~ s/-/_/g;
$macro =~ s/^GTK_/GTK_STOCK_/;
return $macro;
}
sub create_model {
#store = gtk_list_store_new (2, STOCK_ITEM_INFO_TYPE, G_TYPE_STRING);
#my $store = Gtk2::ListStore->new ('scalar', 'Glib::String');
my $store = Gtk2::ListStore->new ('Glib::Scalar', 'Glib::String');
foreach my $id (sort Gtk2::Stock->list_ids) {
my $item = Gtk2::Stock->lookup ($id);
my %info = (
id => $id,
item => $item ? $item : {}
);
# only show icons for stock IDs that have default icons
my $icon_set = Gtk2::IconFactory->lookup_default ($info{id});
if ($icon_set) {
# See at which sizes this stock icon really exists
my @sizes = $icon_set->get_sizes;
# Use menu size if it exists, otherwise first size found
my $size = grep (@sizes, 'menu')
? 'menu'
: $sizes[0];
$info{small_icon} = $window->render_icon ($info{id}, $size);
if ($size ne 'menu') {
# Make the result the proper size for our thumbnail
$info{small_icon} =
Gtk2::Gdk::Pixbuf->scale_simple ($info{small_icon},
Gtk2::Icon->size_lookup ('menu'),
'bilinear');
}
}
$info{accel_str} = $info{item}{keyval}
? Gtk2::Accelerator->name ($info{item}{keyval},
$info{item}{modifier})
: '';
$info{macro} = id_to_macro ($info{id});
# something about redhat9's gnome setup registers a whole slew of
# stock items which don't return icons in this context. i don't
# know if it's because we don't do Gnome2::Program->init or what,
# but it's really annoying, because it messes with lots of things,
# and since you can't pass undef/null for an object property, we
# can't tell the cell renderers to use NULL for the pixbufs.
# so, we only add an entry for stock items which have icons.
if ($info{small_icon}) {
my $iter = $store->append;
$store->set ($iter, 0, \%info, 1, $id);
}
}
return $store;
}
#
# Finds the largest size at which the given image stock id is
# available. This would not be useful for a normal application
#
sub get_largest_size {
my $id = shift;
my $best_size = 'invalid';
my $best_pixels = 0;
my $set = Gtk2::IconFactory->lookup_default ($id);
foreach my $size ($set->get_sizes) {
my ($width, $height) = Gtk2::IconSize->lookup ($size);
next unless defined $height;
if ($width * $height > $best_pixels) {
$best_size = $size;
$best_pixels = $width * $height;
}
}
return $best_size;
}
sub selection_changed {
my $selection = shift;
# warn "\n\nselection_changed $selection";
my $treeview = $selection->get_tree_view;
my $display = $treeview->{stock_display};
my ($model, $iter) = $selection->get_selected;
if ($iter) {
my ($info) = $model->get ($iter, 0);
if ($info->{small_icon} && $info->{item}{label}) {
$display->{type_label}->set_text ("Icon and Item");
} elsif ($info->{small_icon}) {
$display->{type_label}->set_text ("Icon Only");
} elsif ($info->{item}{label}) {
$display->{type_label}->set_text ("Item Only");
} else {
$display->{type_label}->set_text ("???????");
}
$display->{macro_label}->set_text ($info->{macro});
$display->{id_label}->set_text ($info->{id});
if ($info->{item}{label}) {
$display->{label_accel_label}->set_text_with_mnemonic (sprintf '%s %s', $info->{item}{label}, $info->{accel_str});
} else {
$display->{label_accel_label}->set_text ("");
}
if ($info->{small_icon}) {
$display->{icon_image}->set_from_stock ($info->{id},
get_largest_size ($info->{id}));
} else {
$display->{icon_image}->set_from_pixbuf (undef);
}
} else {
$display->{type_label}->set_text ("No selected item");
$display->{macro_label}->set_text ("");
$display->{id_label}->set_text ("");
$display->{label_accel_label}->set_text ("");
$display->{icon_image}->set_from_pixbuf (undef);
}
}
sub macro_set_func_text {
my ($tree_column, $cell, $model, $iter) = @_;
my ($info) = $model->get ($iter, 0);
$cell->set (text => $info->{macro});
}
sub macro_set_func_pixbuf {
my ($tree_column, $cell, $model, $iter) = @_;
my ($info) = $model->get ($iter, 0);
$cell->set (pixbuf => $info->{small_icon});
}
sub id_set_func {
my ($tree_column, $cell, $model, $iter) = @_;
my ($info) = $model->get ($iter, 0);
$cell->set (text => $info->{id});
}
sub accel_set_func {
my ($tree_column, $cell, $model, $iter) = @_;
my ($info) = $model->get ($iter, 0);
$cell->set (text => $info->{accel_str});
}
sub label_set_func {
my ($tree_column, $cell, $model, $iter) = @_;
my ($info) = $model->get ($iter, 0);
# items aren't required to have labels
$cell->set (text => $info->{item}{label} || '');
}
sub do {
if (!$window) {
$window = Gtk2::Window->new;
$window->set_title ("Stock Icons and Items");
$window->set_default_size (-1, 500);
$window->signal_connect (destroy => sub {$window = undef; 1});
$window->set_border_width (8);
my $hbox = Gtk2::HBox->new (FALSE, 8);
$window->add ($hbox);
my $sw = Gtk2::ScrolledWindow->new;
$sw->set_policy ('never', 'automatic');
$hbox->pack_start ($sw, FALSE, FALSE, 0);
my $model = create_model ();
my $treeview = Gtk2::TreeView->new_with_model ($model);
$sw->add ($treeview);
my $column = Gtk2::TreeViewColumn->new;
$column->set_title ("Macro");
my $cell_renderer = Gtk2::CellRendererPixbuf->new;
$column->pack_start ($cell_renderer, FALSE);
### this doesn't work for 2.0.x, because stock_id isn't an attribute for the
### renderer until 2.2.x
### $column->set_attributes ($cell_renderer, stock_id => 1);
$column->set_cell_data_func ($cell_renderer, \¯o_set_func_pixbuf);
$cell_renderer = Gtk2::CellRendererText->new;
$column->pack_start ($cell_renderer, TRUE);
$column->set_cell_data_func ($cell_renderer, \¯o_set_func_text);
$treeview->append_column ($column);
$cell_renderer = Gtk2::CellRendererText->new;
$treeview->insert_column_with_data_func (-1,
"Label",
$cell_renderer,
\&label_set_func);
$cell_renderer = Gtk2::CellRendererText->new;
$treeview->insert_column_with_data_func (-1,
"Accel",
$cell_renderer,
\&accel_set_func);
$cell_renderer = Gtk2::CellRendererText->new;
$treeview->insert_column_with_data_func (-1,
"ID",
$cell_renderer,
\&id_set_func);
my $align = Gtk2::Alignment->new (0.5, 0.0, 0.0, 0.0);
$hbox->pack_end ($align, FALSE, FALSE, 0);
my $frame = Gtk2::Frame->new ("Selected Item");
$align->add ($frame);
my $vbox = Gtk2::VBox->new (FALSE, 8);
$vbox->set_border_width (4);
$frame->add ($vbox);
my $display = {
type_label => Gtk2::Label->new,
macro_label => Gtk2::Label->new,
id_label => Gtk2::Label->new,
label_accel_label => Gtk2::Label->new,
icon_image => Gtk2::Image->new_from_pixbuf (undef), # empty image
};
$treeview->{stock_display} = $display;
$vbox->pack_start ($display->{type_label}, FALSE, FALSE, 0);
$vbox->pack_start ($display->{icon_image}, FALSE, FALSE, 0);
$vbox->pack_start ($display->{label_accel_label}, FALSE, FALSE, 0);
$vbox->pack_start ($display->{macro_label}, FALSE, FALSE, 0);
$vbox->pack_start ($display->{id_label}, FALSE, FALSE, 0);
my $selection = $treeview->get_selection;
$selection->set_mode ('single');
$selection->signal_connect (changed => \&selection_changed);
}
if (!$window->visible) {
$window->show_all;
} else {
$window->destroy;
$window = undef;
}
return $window;
}
1;
__END__
Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
full list)
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.