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

# Be warned, this thing is slightly out of whack...

#TITLE: Packer
#REQUIRES: Gtk



#use strict;
use Gtk;

sub destroy {
	my($widget) = @_;
	Gtk->main_quit;
}

sub main {

	my($info) = {};

	init Gtk;
	
	my($window) = new Gtk::Window -toplevel;
	
	$window->signal_connect( "destroy" => \&destroy);
	
	my($window_pack) = new Gtk::Packer;
	$window->add($window_pack);
	$window->border_width(4);
	
	my($top_pack) = new Gtk::Packer;
	$window_pack->add_defaults($top_pack, -top, -center, [-fill_x, -fill_y, -expand]);
	
	my($frame) = new Gtk::Frame("Packing Area");
	$frame->set_usize(400,400);
	$top_pack->add($frame, -left, -center, [-fill_x, -fill_y, -expand], 0, 8, 8, 0, 0);
	my($packer) = new Gtk::Packer;
	$frame->add($packer);
	
	my($button_pack) = new Gtk::Packer;
	$top_pack->add($button_pack, -left, -north, [], 
					0, 0, 0, 0, 0);
	
	my($button_add) = new Gtk::Button "Add Button";
	$top_pack->add($button_add, -top, -center, -fill_x, 0, 8, 8, 8, 0);
	$button_add->signal_connect(clicked => \&add_widget, $info);
	
	my($button_quit) = new Gtk::Button "Quit";
	$top_pack->add($button_quit, -top, -center, -fill_x, 0, 8, 8, 0, 0);
	$button_quit->signal_connect(clicked => sub { destroy $window });
	
	my($bottom_pack) = new Gtk::Packer;
	$window_pack->add_defaults($bottom_pack, -top, -center, -fill_x);
	
	my($side_frame) = new Gtk::Frame "Side";
	$window_pack->add($side_frame, -left, -west, -fill_y, 0, 10, 10, 0, 0);
	
	my($side_pack) = new Gtk::Packer;
	$side_frame->add($side_pack);
	
	my($button_top) = new Gtk::ToggleButton "Top";
	my($button_bottom) = new Gtk::ToggleButton "Bottom";
	my($button_left) = new Gtk::ToggleButton "Left";
	my($button_right) = new Gtk::ToggleButton "Rght";
	
	$button_top->{side} = -top;
	$button_bottom->{side} = -bottom;
	$button_left->{side} = -left;
	$button_right->{side} = -right;

	$button_top->set_usize(50, -1);
	$button_bottom->set_usize(50, -1);
	$button_left->set_usize(50, -1);
	$button_right->set_usize(50, -1);
	$side_pack->add($button_top, -top, -center, [], 0, 5, 5, 0, 0);
	$side_pack->add($button_bottom, -bottom, -center, [], 0, 5, 5, 0, 0);
	$side_pack->add($button_left, -left, -center, [], 0, 10, 5, 0, 0);
	$side_pack->add($button_right, -right, -center, [], 0, 10, 5, 0, 0);
	
	$button_top->signal_connect(toggled => \&toggle_side, $info);
	$button_bottom->signal_connect(toggled => \&toggle_side, $info);
	$button_left->signal_connect(toggled => \&toggle_side, $info);
	$button_right->signal_connect(toggled => \&toggle_side, $info);
	
	my($anchor_frame) = new Gtk::Frame "Anchor";
	$window_pack->add($anchor_frame, -left, -west, -fill_y, 0, 10, 10, 0, 0);
	
	my($anchor_pack) = new Gtk::Packer;
	$anchor_frame->add($anchor_pack);
	
	my($anchor_table) = new Gtk::Table(3, 3, 1);
	$anchor_pack->add($anchor_table, -top, -center, [-fill_y, -fill_x, -expand], 0, 10, 5, 0, 0);
	
	my($button_n) = new Gtk::ToggleButton "N";
	my($button_ne) = new Gtk::ToggleButton "NE";
	my($button_e) = new Gtk::ToggleButton "E";
	my($button_se) = new Gtk::ToggleButton "SE";
	my($button_s) = new Gtk::ToggleButton "S";
	my($button_sw) = new Gtk::ToggleButton "SW";
	my($button_w) = new Gtk::ToggleButton "W";
	my($button_nw) = new Gtk::ToggleButton "NW";
	my($button_center) = new Gtk::ToggleButton "";
	
	$button_n->{anchor} = "north";
	$button_ne->{anchor} = "ne";
	$button_e->{anchor} = "east";
	$button_se->{anchor} = "se";
	$button_s->{anchor} = "south";
	$button_sw->{anchor} = "sw";
	$button_w->{anchor} = "west";
	$button_nw->{anchor} = "nw";
	$button_center->{anchor} = "center";
	
	$button_n->signal_connect(toggled => \&toggle_anchor, $info);
	$button_ne->signal_connect(toggled => \&toggle_anchor, $info);
	$button_e->signal_connect(toggled => \&toggle_anchor, $info);
	$button_se->signal_connect(toggled => \&toggle_anchor, $info);
	$button_s->signal_connect(toggled => \&toggle_anchor, $info);
	$button_sw->signal_connect(toggled => \&toggle_anchor, $info);
	$button_w->signal_connect(toggled => \&toggle_anchor, $info);
	$button_nw->signal_connect(toggled => \&toggle_anchor, $info);
	$button_center->signal_connect(toggled => \&toggle_anchor, $info);
	
	$anchor_table->attach_defaults($button_nw, 0, 1, 0, 1);
	$anchor_table->attach_defaults($button_n, 1, 2, 0, 1);
	$anchor_table->attach_defaults($button_ne, 2, 3, 0, 1);
	$anchor_table->attach_defaults($button_w, 0, 1, 1, 2);
	$anchor_table->attach_defaults($button_center, 1, 2, 1, 2);
	$anchor_table->attach_defaults($button_e, 2, 3, 1, 2);
	$anchor_table->attach_defaults($button_sw, 0, 1, 2, 3);
	$anchor_table->attach_defaults($button_s, 1, 2, 2, 3);
	$anchor_table->attach_defaults($button_se, 2, 3, 2, 3);
	
	my($options_frame) = new Gtk::Frame "Options";
	$window_pack->add($options_frame, -left, -west, -fill_y, 0, 10, 10, 0, 0);
	
	my($options_pack) = new Gtk::Packer;
	$options_frame->add($options_pack);
	
	my($button_fillx) = new Gtk::ToggleButton "Fill X";
	my($button_filly) = new Gtk::ToggleButton "Fill Y";
	my($button_expand) = new Gtk::ToggleButton "Expand";
	
	$options_pack->add($button_fillx, -top, -north, [-fill_x, -expand], 0, 10, 5, 0, 0);
	$options_pack->add($button_filly, -top, -center, [-fill_x, -expand], 0, 10, 5, 0, 0);
	$options_pack->add($button_expand, -top, -south, [-fill_x, -expand], 0, 10, 5, 0, 0);
	
	$button_fillx->{option} = -fill_x;
	$button_filly->{option} = -fill_y;
	$button_expand->{option} = -expand;
	
	$button_fillx->signal_connect(toggled => \&toggle_options, $info);
	$button_filly->signal_connect(toggled => \&toggle_options, $info);
	$button_expand->signal_connect(toggled => \&toggle_options, $info);
	
	$info->{widgets} = [];
	$info->{packer} = $packer;
	$info->{button_top} = $button_top;
	$info->{button_bottom} = $button_bottom;
	$info->{button_left} = $button_left;
	$info->{button_right} = $button_right;
	$info->{button_n} = $button_n;
	$info->{button_ne} = $button_ne;
	$info->{button_e} = $button_e;
	$info->{button_se} = $button_se;
	$info->{button_s} = $button_s;
	$info->{button_sw} = $button_sw;
	$info->{button_w} = $button_w;
	$info->{button_nw} = $button_nw;
	$info->{button_center} = $button_center;
	$info->{button_fillx} = $button_fillx;
	$info->{button_filly} = $button_filly;
	$info->{button_expand} = $button_expand;
	
	add_widget(undef, $info);
	
	$window->show_all;
	
	Gtk->main;
	
	return 0;
}

main;

sub toggle_options {
	my($widget, $info) = @_;
	
	my($option, $fillx, $filly, $expand, $pchild, @options);
	
	$option = $widget->{option};
	
	if (not defined $info->{pchild}) {
		die;
	}
	
	$pchild = $info->{pchild};
	
	push @options, -fill_x if $info->{button_fillx}->active;
	push @options, -fill_y if $info->{button_filly}->active;
	push @options, -expand if $info->{button_expand}->active;
	
	$info->{packer}->configure($info->{current},
								$pchild->side,
								$pchild->anchor,
								\@options,
								$pchild->border_width,
								$pchild->pad_x,
								$pchild->pad_y,
								$pchild->ipad_x,
								$pchild->ipad_y);

}


sub toggle_anchor {
	my($widget,$info) = @_;
	
	if ($widget->active) {
		my($anchor) = $widget->{anchor};
		
		my($pchild) = $info->{pchild};
		if (not defined $pchild) {
			die;
		}
		
		$info->{packer}->configure($info->{current}, 
									$pchild->side,
									$anchor,
									$pchild->options,
									$pchild->border_width,
									$pchild->pad_x,
									$pchild->pad_y,
									$pchild->ipad_x,
									$pchild->ipad_y);

		foreach (	$info->{button_n},
					$info->{button_ne},
					$info->{button_e},
					$info->{button_se},
					$info->{button_s},
					$info->{button_sw},
					$info->{button_w},
					$info->{button_nw},
					$info->{button_center}
				) {
			if ($_ != $widget) {
				$_->set_state(0);
				$_->set_sensitive(1);
			}
		}
		
		$widget->set_sensitive(0);
		
	}
}

sub toggle_side {
	my($widget,$info) = @_;
	
	if ($widget->active) {
		my($side) = $widget->{side};
		
		my($pchild) = $info->{pchild};
		if (not defined $pchild) {
			die;
		}
		
		$info->{packer}->configure($info->{current}, 
									$side,
									$pchild->anchor,
									$pchild->options,
									$pchild->border_width,
									$pchild->pad_x,
									$pchild->pad_y,
									$pchild->ipad_x,
									$pchild->ipad_y);

		foreach (	$info->{button_top},
					$info->{button_bottom},
					$info->{button_left},
					$info->{button_right}
				) {
			if ($_ != $widget) {
				$_->set_state(0);
				$_->set_sensitive(1);
			}
		}
		
		$widget->set_sensitive(0);
		
	}
}

sub set_widget {
	my($w,$info) = @_;
	
	my($pchild);
	
	if ($w->active) {
		$info->{current} = $w;
		
		$pchild = undef;
		foreach ($info->{packer}->children) {
			if ($_->widget eq $info->{current}) {
				$pchild = $_;
				last;
			}
		}
		$info->{pchild} = $pchild;		
		
		$info->{button_top}->set_state(1) if $pchild->side eq "top";
		$info->{button_bottom}->set_state(1) if $pchild->side eq "bottom";
		$info->{button_left}->set_state(1) if $pchild->side eq "left";
		$info->{button_right}->set_state(1) if $pchild->side eq "right";

		$info->{button_north}->set_state(1) if $pchild->anchor eq "north";
		$info->{button_ne}->set_state(1) if $pchild->anchor eq "ne";
		$info->{button_east}->set_state(1) if $pchild->anchor eq "east";
		$info->{button_se}->set_state(1) if $pchild->anchor  eq "se";
		$info->{button_south}->set_state(1) if $pchild->anchor eq "south";
		$info->{button_sw}->set_state(1) if $pchild->anchor eq "sw";
		$info->{button_west}->set_state(1) if $pchild->anchor eq "west";
		$info->{button_nw}->set_state(1) if $pchild->anchor eq "nw";
		$info->{button_center}->set_state(1) if $pchild->anchor eq "center";
		
		$info->{button_expand}->set_state($pchild->options->{expand} || 0);
		$info->{button_fillx}->set_state($pchild->options->{fill_x} || 0);
		$info->{button_filly}->set_state($pchild->options->{fill_y} || 0);
		
		$w->set_sensitive(0);
		
		foreach (@{$info->{widgets}}) {
			next if $_ eq $info->{current};
			
			$_->set_state(0);
			$_->set_sensitive(1);
		}
		
	}
}

use vars '$add_widget_n';

sub add_widget {
	my($w, $info) = @_;
	
	my($packer) = $info->{packer};
	
	$main::add_widget_n ||= 0;
	
	my($widget) = new Gtk::ToggleButton "$main::add_widget_n";
	$widget->set_usize(50, 50);
	$packer->Gtk::Container::add($widget);
	$widget->show;
	
	$widget->signal_connect(toggled => \&set_widget, $info);
	
	push @{$info->{widgets}}, $widget;
	$widget->set_state(1);
	
	set_widget($widget, $info);
	
	$main::add_widget_n++;
	
}