The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

# ported from Tim-Philipp Meuller's Tree View tutorial,
# http://scentric.net/tutorial/sec-custom-cell-renderers.html#sec-custom-cell-renderer-example-body
# by muppet, 6 feb 04.
#
# This is based mainly on GtkCellRendererProgress
#  in GAIM, written and (c) 2002 by Sean Egan
#  (Licensed under the GPL), which in turn is
#  based on Gtk's GtkCellRenderer[Text|Toggle|Pixbuf]
#  implementation by Jonathan Blandford */

package Mup::CellRendererProgress;

use strict;
use warnings;
use Glib qw(G_PARAM_READWRITE);
use Gtk2;
use Glib::Object::Subclass
  Gtk2::CellRenderer::,
  properties => [
    Glib::ParamSpec->double ('percentage',
                             'Percentage',
                             'The fractional progress to display',
                             0.0, 1.0, 0.0, G_PARAM_READWRITE),
  ],
  ;


sub INIT_INSTANCE {
  my $self = shift;
  $self->set (mode => 'inert',
              xpad => 2,
              ypad => 2);
  $self->{percentage} = 0.0;
}

# we'll use the default new, GET_PROPERTY and SET_PROPERTY provided by
# Glib::Object::Subclass.


#
# calculate the size of our cell, taking into account padding and
# alignment properties of parent.
#

use constant FIXED_WIDTH  => 100;
use constant FIXED_HEIGHT => 10;

sub MAX { $_[0] > $_[1] ? $_[0] : $_[1] }

sub GET_SIZE {
  my ($cell, $widget, $cell_area) = @_;
  my ($x_offset, $y_offset) = (0, 0);

  my $width  = int ($cell->get ('xpad') * 2 + FIXED_WIDTH);
  my $height = int ($cell->get ('ypad') * 2 + FIXED_HEIGHT);

  if ($cell_area) {

    $x_offset = $cell->get ('xalign') * ($cell_area->width - $width);
    $x_offset = MAX ($x_offset, 0);

    $y_offset = $cell->get ('yalign') * ($cell_area->height - $height);
    $y_offset = MAX ($y_offset, 0);
  }

  return ($x_offset, $y_offset, $width, $height);
}


sub RENDER {
  my ($cell, $window, $widget, $background_area, $cell_area, $expose_area, $flags) = @_;

  # invoke GET_SIZE directly to avoid a lot of marshalling overhead.
  my ($x_offset, $y_offset, $width, $height)
            = $cell->GET_SIZE ($widget, $cell_area);

  my $state = $widget->has_focus ? 'active' : 'normal';

  my ($xpad, $ypad) = $cell->get (qw(xpad ypad));

  $width  -= $xpad*2;
  $height -= $ypad*2;

  my $style = $widget->style;
  $style->paint_box ($window,
                     'normal', 'in',
                     undef, $widget, "trough",
                     $cell_area->x + $x_offset + $xpad,
                     $cell_area->y + $y_offset + $ypad,
                     $width - 1, $height - 1);

  $style->paint_box ($window,
                     $state, 'out',
                     undef, $widget, "bar",
                     $cell_area->x + $x_offset + $xpad,
                     $cell_area->y + $y_offset + $ypad,
                     $width * $cell->{percentage},
                     $height - 1);
}


package main;

use strict;
use Glib qw(TRUE FALSE);
use Gtk2 -init;

my $liststore;
my $increasing = TRUE; # direction of progress bar change

use constant {
  COL_PERCENTAGE => 0,
  COL_TEXT       => 1,
  NUM_COLS       => 2,

  STEP           => 0.01,
};


sub increase_progress_timeout {
  my $renderer = shift;
  my $iter = $liststore->get_iter_first; # first and only row

  my $perc = $liststore->get ($iter, COL_PERCENTAGE);

  if ($perc > (1.0 - STEP)  ||  ($perc < STEP && $perc > 0.0) ) {
    $increasing = (!$increasing);
  }

  if ($increasing) {
    $perc += STEP;
  } else {
    $perc -= STEP;
  }

  my $buf = sprintf '%u %%', $perc*100;

  $liststore->set ($iter, COL_PERCENTAGE, $perc, COL_TEXT, $buf);

  return TRUE; # Call again
}


sub create_view_and_model {
  $liststore = Gtk2::ListStore->new (qw(Glib::Double Glib::String));
  my $iter = $liststore->append;
  $liststore->set ($iter, COL_PERCENTAGE, 0.5); # start at 50%

  my $view = Gtk2::TreeView->new ($liststore);

  my $renderer = Gtk2::CellRendererText->new;
  my $col = Gtk2::TreeViewColumn->new;
  $col->pack_start ($renderer, TRUE);
  $col->add_attribute ($renderer, text => COL_TEXT);
  $col->set_title ("Progress");
  $view->append_column ($col);

  $renderer = Mup::CellRendererProgress->new;
  $col = Gtk2::TreeViewColumn->new;
  $col->pack_start ($renderer, TRUE);
  $col->add_attribute ($renderer, percentage => COL_PERCENTAGE);
  $col->set_title ("Progress");
  $view->append_column ($col);

  Glib::Timeout->add (50, \&increase_progress_timeout);

  return $view;
}


my $window = Gtk2::Window->new;
$window->set_default_size (150, 100);
$window->signal_connect (delete_event => sub {Gtk2->main_quit});

my $view = create_view_and_model();

$window->add ($view);

$window->show_all;

Gtk2->main;