Re: image layout questions



On Tue, 7 Aug 2007 19:03:04 +1200
"Johan Aberg" <abergster gmail com> wrote:

I'm looking for a way to display images in a horizontal layout. I'm
building a timeline displaying images from left to right. I'd like to
be able to use set_reorderable(TRUE) to shuffle the images around left
or right on this timeline.
The TreeView seems to be a good candidate of doing this, but it seems
to be design to show data in rows and columns in a vertical layout. I
only want one row with lots of columns and I need to be able to access
each cell to reorder them.
Any suggestion what widget/class that could help me out here?

I wrote this thumbnail-previwer awhile ago. It uses the Gnome2::Canvas
for display. I display the thumbnails vertically, but you could
easily switch it to horizontal. Reordering them out to be easy too.
Anyways, just run the script in a directory
full of images.... it will find all images and recurse into sub-dirs.
As far as widgets go, for doing specialized things of your imagination,
it's hard to beat a Canvas.

#!/usr/bin/perl
use warnings;
use strict;
use Gtk2 '-init';
use Glib qw/TRUE FALSE/; 
use Gnome2::Canvas;


chdir '..';  #little hack to load any images in toplevel directory
             #otherwise only subdirs are shown at opening
                           
#automatically put full file path to clipboards
#to paste menu
my $clipboard =  Gtk2::Clipboard->get(Gtk2::Gdk->SELECTION_CLIPBOARD);
#to mouse
my $clipboard1 =  Gtk2::Clipboard->get(Gtk2::Gdk->SELECTION_PRIMARY);

my $window = Gtk2::Window->new('toplevel');
$window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
$window->set_border_width(5);
$window->set_default_size(600,400);

my $vbox = Gtk2::VBox->new(0,1);

#create a hbox to pack the information label
   my $hbox0 = Gtk2::VBox->new(FALSE,1);
   my $label_info = Gtk2::Label->new();
   $label_info->set_markup( &make_label('Filename','Dimensions','Size'));

 $hbox0->pack_start($label_info,FALSE,FALSE,1); 
 $vbox->pack_start($hbox0,0,0,0);

my $hbox = Gtk2::HBox->new(0,5);
#these vboxs will return the bulk of the gui
my $tbox = &ret_tree();  #the dir selector
$hbox->pack_start($tbox,0,0,0);

my ($cbox,$can) = &ret_can(); #thumbnail canvas
$hbox->pack_start($cbox,0,0,0);

my ($zbox,$can1) = &ret_can1(); #main image canvas
$hbox->pack_start($zbox,1,1,1);

$vbox->pack_start($hbox,1,1,0);

#add and show the vbox
$window->add($vbox);
$window->show_all();

#our main event-loop
Gtk2->main();
###################################################################
sub make_label{
my ($name, $dimensions, $size) = @_;
return  
"<span background = 'yellow' foreground= 'black' size ='10000'><i> $name  </i></span>".
"<span background = 'black' foreground= 'green' size ='20000'><i> $dimensions  </i></span>".
"<span background = 'blue' foreground= 'red' size ='20000'><i> $size  </i></span>";
}
#################################################################
sub ret_tree {
my $vbox = Gtk2::VBox->new(FALSE,5);
        #create a scrolled window that will host the treeview
        my $sw = Gtk2::ScrolledWindow->new (undef, undef);
                $sw->set_shadow_type ('etched-out');
                $sw->set_policy ('automatic','always');
                $sw->set_placement('top-right');
                $sw->set_size_request (200, 300);
                $sw->set_border_width(0);

        my $tree_store = Gtk2::TreeStore->new(qw/Glib::String/);

        my %tree = %{ hashdir() };

        #fill it with data
        foreach my $key (sort keys %tree ) {
                #the iter is a pointer in the treestore. We
                #use to add data.
                my $iter = $tree_store->append(undef);
                $tree_store->set ($iter,0 => $key);
                
                #need recursive sub here to nest subdirs
                &recurse($tree_store, $tree{$key} , $iter );
         }

            #this will create a treeview, specify $tree_store as its model
            my $tree_view = Gtk2::TreeView->new($tree_store);
                
            #create a Gtk2::TreeViewColumn to add to $tree_view
            my $tree_column = Gtk2::TreeViewColumn->new();
                
            $tree_column->set_title('Select');
                        
           #create a renderer that will be used to display info
           #in the model
           my $renderer = Gtk2::CellRendererText->new;
           #add this renderer to $tree_column. This works like a Gtk2::Hbox
           # so you can add more than one renderer to $tree_column                      
           $tree_column->pack_start ($renderer, FALSE);
                
           # set the cell "text" attribute to column 0   
           #- retrieve text from that column in treestore 
           # Thus, the "text" attribute's value will depend on the row's value
           # of column 0 in the model($treestore),
           # and this will be displayed by $renderer,
           # which is a text renderer
          $tree_column->add_attribute($renderer, text => 0);
        
           #add $tree_column to the treeview
          $tree_view->append_column ($tree_column);
        
         $sw->add($tree_view);

         $tree_view->get_selection->signal_connect(
                changed =>\&cell_selected,$tree_store ); 

         #$tree_view->expand_all;
         # expand only first level
         $tree_view->expand_row (Gtk2::TreePath->new(0),0);
         
$vbox->pack_start($sw,1,1,0);
$vbox->show_all();
return $vbox;
}
######################################################################
sub ret_can {
 
  my $vbox = Gtk2::VBox->new(FALSE,5);
        #create a scrolled window that will host the treeview
        my $sw = Gtk2::ScrolledWindow->new (undef, undef);
                $sw->set_shadow_type ('etched-out');
                $sw->set_policy ('automatic', 'always');
                $sw->set_placement('top-right');
                $sw->set_size_request (130, 300);
                $sw->set_border_width(0);

        my $canvas   = Gnome2::Canvas->new_aa;
        $canvas->set_scroll_region( 0,0,10,2000);

        my $black = Gtk2::Gdk::Color->new (0x0000,0x0000,0x0000);
        $canvas->modify_bg('normal',$black);
        $canvas->set_center_scroll_region (FALSE);
  
        $sw->add($canvas);

   $vbox->pack_start($sw,TRUE,TRUE,0);
   $vbox->show_all();
return ($vbox,$canvas);
}
######################################################################
sub ret_can1{
 
  my $vbox = Gtk2::VBox->new(TRUE,5);
        #create a scrolled window that will host the thumb canvas
        my $sw = Gtk2::ScrolledWindow->new (undef, undef);
                $sw->set_shadow_type ('etched-out');
                $sw->set_policy ('always', 'always');
                $sw->set_placement('top-right');
                $sw->set_size_request (300, 300);
                $sw->set_border_width(0);

        my $canvas   = Gnome2::Canvas->new_aa;
        $canvas->set_scroll_region( 0,0,2000,2000);

        my $black = Gtk2::Gdk::Color->new (0x0000,0x0000,0x0000);
        $canvas->modify_bg('normal',$black);
        $canvas->set_center_scroll_region (FALSE);

    $sw->add($canvas);

$vbox->pack_start($sw,TRUE,TRUE,0);
$vbox->show_all();
return ($vbox,$canvas);
}
######################################################################
sub recurse{            
  my ( $tree_store, $hashref , $iter ) = @_;
  
     my %hash = %{$hashref};
  
     foreach my $key (sort keys %hash ){        
        
       my $iter_child = $tree_store->append($iter);                    
       if( scalar (keys %hash == 0 ) ){  
             $tree_store->set ($iter_child,0 => $key );
         }else{
            $tree_store->set ($iter_child,0 => $key );
           &recurse($tree_store, $hash{$key}, $iter_child);
         }
   }
}
###################################################################

sub cell_selected{
       my ($tree_selection,$model ) = @_ ;

       my $sel = $tree_selection->get_selected_rows;
       my $value='';
       if( defined $sel ){
          my $path = $sel->to_string;
          my @path_ele = split /:/, $path;
        #reconstruct filesystem path from model path         
         while( @path_ele ){
            $path = join ':', @path_ele;
            #print "path $path\n";
            my $iter = $model->get_iter_from_string($path);
            my $val = $model->get($iter,0);
            $value = $val.'/'.$value;
            pop @path_ele;
           }
      }  
#print "$value\n";
add_dir_contents("./$value");

return FALSE;
}
#############################################################

sub hashdir {
    my $dir = shift || '.';
    opendir my $dh, $dir or die $!;

    my $tree = {}->{$dir} = {};

    while ( my $file = readdir($dh) ) {
        next if $file =~ m[^\.{1,2}$];

         my $path = $dir . '/' . $file;

      if(-d $path){ 
       $tree->{$file} = hashdir($path); 
      }else{ next }
    }

return $tree;
}
#########################################################
sub add_dir_contents {
    my $path   = $_[0];

  #this decode utf8 routine is used so filenames with extended
   # ascii characters (unicode) in filenames, will work properly
   use Encode;
   opendir my $dh, $path or warn "Error: $!";
   my @files = grep !/^\.\.?$/, readdir $dh;
   closedir $dh;
   @files = map { decode( 'utf8', "$path/".$_  ) } sort @files;
     
    my @thumbs=();
    
    foreach my $file (@files) {
        $file =~ s|//|/|g;
       (my $text = $file ) =~ s|^.*/||g;
      if( $file =~ /.*\.(png|jpg|gif)$/ ){ push @thumbs, $file }
    }

#print "@thumbs\n";
load_thumbs( \ thumbs );

}
###############################################################
sub load_thumbs{
my $thumbsref = shift; 

#clean out old thumbs 
foreach my $item ( @{$can->{'temp'}} ){ $item->destroy; }
@{$can->{'temp'}} =();

my $root = $can->root;
my $count = 0;

foreach my $file( @$thumbsref ){
        
        my $pixbuf_t = Gtk2::Gdk::Pixbuf->new_from_file_at_scale($file,100,100,1);
        my $image = Gnome2::Canvas::Item->new ($root,
                                               'Gnome2::Canvas::Pixbuf',
                                               pixbuf => $pixbuf_t,
                                               x      => 2.0,
                                               y      => $count * 108,
                                               width  => 100,
                                               height => $pixbuf_t->get_height,
                                               anchor => 'nw',
                                               );
       
        $image->{'filepath'} = $file; #data rider to hold path

        $image->signal_connect (event => sub {
                my ($item, $event) = @_;
                if( $event->type eq 'button-press' ){
                     &display_image( $image->{'filepath'}  );
                   }
         });
         
       my $line = Gnome2::Canvas::Item->new ($root,
               'Gnome2::Canvas::Line',
                points => [0.0, $count * 108, 130.0, $count * 108],
            fill_color => '#ff0000',
            width_units => 6.0,
       );


   push @{$can->{'temp'}}, $image; #list to delete on refresh
   push @{$can->{'temp'}}, $line;
   $count++;
 }
#print @{$can->{'temp'}},"\n";
#display_image( ${$can->{'temp'}}[0]  );  #display first image in list
$can->set_scroll_region (0, 0, 10, $count * 108);
$can->scroll_to (0, 0); 
}
##############################################################
sub display_image{
  if( ref $can1->{'temp'} eq 'Gnome2::Canvas::Pixbuf' ){
                  $can1->{'temp'}->destroy}

  my $im = Gtk2::Gdk::Pixbuf->new_from_file( $_[0] );
  my $x = $im->get_width;
  my $y = $im->get_height;
  my $image = Gnome2::Canvas::Item->new ($can1->root,
                                       'Gnome2::Canvas::Pixbuf',
                                           pixbuf => $im,
                                           x      => 5.0,
                                           y      => 5.0,
                                           width  => $x,
                                           height => $y,
                                           anchor => 'nw',
                                           );

 $can1->{'temp'} = $image;
 $can1->set_scroll_region (0, 0, $x + 10, $y + 10);
 $can1->scroll_to (0, 0); 

 # set to clipboard for menu or mouse paste
 $clipboard->clear;
 $clipboard1->clear;
 $clipboard->set_text($_[0]);
 $clipboard1->set_text($_[0]);

 my $filebase = substr ($_[0], rindex ($_[0], "/") + 1);
 $label_info->set_markup( &make_label( $filebase, "$x x $y" , (stat $_[0] )[7] ));
}
##################################################################

__END__
zentara
-- 
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]