#!/usr/local/bin/perl -w use strict; use integer; use Getopt::Std; use Gtk; use vars qw($automatic $window $canvas $pixmap $r_gc $width $height $bs $orig_bs $shrink $VERBOSE $x $y); my %o; getopts('ab:svx:y:', \%o); $VERBOSE = $o{'v'}; $shrink = $o{'s'}; $automatic = $o{'a'}; $width = $o{'x'} || 400; $height = $o{'y'} || $o{'x'} || 400; $bs = $o{'b'} || 10; # each "block" is 10x10 pixels by default $orig_bs = $bs; $x = int($width/$bs/2); $y = int($height/$bs/2); my $timeout = 512; # milliseconds my $timer; my @grid; my %moves = ( 65361 => sub { $x = int($width/$bs)-1 if --$x < 0 }, # west 65362 => sub { $y = int($height/$bs)-1 if --$y < 0 }, # north 65363 => sub { $x = 0 if ++$x >= int($width/$bs) }, # east 65364 => sub { $y = 0 if ++$y >= int($height/$bs) }, # south ); { my $prev_rand = 65361; sub auto_move { my $rand = 65361 + int rand 4; if ( ($rand != $prev_rand) && (($rand % 2) == ($prev_rand % 2)) ) { $rand = $prev_rand; } $prev_rand = $rand; &{$moves{$rand}}; my $many = ($width/$bs) * ($height/$bs); while(defined $grid[$x]->[$y]) { $x = int(rand($width/$bs)); $y = int(rand($height/$bs)); print "attempt: ($x, $y)\n" if $VERBOSE; return 0 if --$many < 0; Gtk->timeout_remove($timer); $timeout = $timeout/2; #return 0 if $timeout < 1; $timeout = 1 if $timeout < 1; $timer = Gtk->timeout_add($timeout, \&auto_move, ()); if ($shrink) { $bs--; $bs=$orig_bs if $bs < 1; } } random_color($canvas); block_plot($x, $y); return 1; } } init Gtk; $window = Gtk::Window->new('toplevel'); $window->signal_connect('destroy', sub { $window->destroy; exit 0 }); $window->signal_connect('key_press_event', \&key_handler); $window->set_title('blox'); my $vbox = Gtk::VBox->new(0, 0); $window->add($vbox); $vbox->show; $canvas = Gtk::DrawingArea->new; $canvas->size($width, $height); $canvas->signal_connect('expose_event', \&pixmap_expose); $vbox->pack_start($canvas, 1, 1, 0); $canvas->set_events([ 'exposure_mask', 'button_press_mask', 'button1-motion-mask', 'button2-motion-mask', 'button3-motion-mask', ]); $canvas->signal_connect('button_press_event', \&mouse_click); $canvas->signal_connect('motion_notify_event', \&mouse_click); $canvas->show; $canvas->realize; $pixmap = Gtk::Gdk::Pixmap->new($canvas->window, $width, $height, -1); $r_gc = Gtk::Gdk::GC->new($canvas->window); *random_color = \&set_random_color; { my %c = ( 'red' => int(rand 65536), 'green' => int(rand 65536), 'blue' => int(rand 65536) ); sub set_random_progressive_color { my $widget = shift || return undef; COLOR: for(keys %c) { while(1) { $c{$_} += (int(rand 3)-1) * int(rand 4096); next COLOR if ($c{$_} > 0) && ($c{$_} < 65536); } } my $r_color = $widget->window->get_colormap->color_alloc(\%c); $r_gc->set_foreground($r_color); 1; } } random_color($canvas); sub block_plot { my $x = shift; my $y = shift; $grid[$x] = [] unless defined $grid[$x]; $grid[$x]->[$y] = 1; # $pixmap->draw_rectangle($r_gc, 1, $x*$bs, $y*$bs, $bs, $bs); # filled $pixmap->draw_rectangle($r_gc, 0, $x*$bs, $y*$bs, $bs, $bs); # outline $canvas->window->draw_pixmap( $canvas->style->fg_gc('normal'), $pixmap, 0, 0, 0, 0, $width, $height ); 1; } sub blank_canvas { $bs = $orig_bs; my $widget = shift; my $r_color = $widget->window->get_colormap->color_alloc( { 'red' => 0, 'green' => 0, 'blue' => 0 } ); $r_gc->set_foreground($r_color); $pixmap->draw_rectangle($r_gc, 1, 0, 0, $width, $height); $widget->window->draw_pixmap( $widget->style->fg_gc('normal'), $pixmap, 0, 0, 0, 0, $width, $height ); @grid = (); } $window->show; $timer = Gtk->timeout_add($timeout, \&auto_move, ()); main Gtk; { my $previous_button = 1; sub mouse_click { my $widget = shift; my $event = shift; $x = int($event->{'x'}/$bs); $y = int($event->{'y'}/$bs); $previous_button = $event->{'button'} if defined $event->{'button'}; if ($previous_button == 1) { set_random_color($canvas); } elsif ($previous_button == 2) { set_random_progressive_color($canvas); } else { # don't change the color for button 3 } block_plot($x, $y); 1; } } sub pixmap_expose { my $widget = shift; my $event = shift; my ($x1, $y1, $x2, $y2) = @{$event->{'area'}}; $widget->window->draw_pixmap( $widget->style->fg_gc('normal'), $pixmap, $x1, $y1, $x1, $y1, $x2, $y2); 1; } sub set_random_color { my $widget = shift || return undef; my $r_color = $widget->window->get_colormap->color_alloc( { 'red' => int(rand 65536), 'green' => int(rand 65536), 'blue' => int(rand 65536), } ); $r_gc->set_foreground($r_color); } sub key_handler { my $widget = shift; my $event = shift; my $l = chr($event->{'keyval'}); if ($event->{'keyval'} == 65307) { blank_canvas($canvas); random_color($canvas); $timeout = 512; } elsif (defined $moves{$event->{'keyval'}}) { &{$moves{$event->{'keyval'}}}; my $many = ($width/$bs) * ($height/$bs); while(defined $grid[$x]->[$y]) { $x = int(rand($width/$bs)); $y = int(rand($height/$bs)); return 1 if --$many < 0; } random_color($canvas); block_plot($x, $y); } elsif ($event->{'keyval'} == 32) { # space # *random_color } else { print STDERR "$$event{'keyval'}\n"; } 1; }