App::Harmonograph / lib / Wx / Perl / Smart / Sizer.pm

use v5.12;
use warnings;
use Wx;
#use Wx::Perl::Smart::LabeledBox;
#use Wx::Perl::Smart::TabbedBox;
use Wx::Perl::Smart::Factory;

#use Wx::Perl::RadioGroup;
#use Wx::Perl::TextSlider;

package Wx::Perl::Smart::Sizer;
our $VERSION = '0.23';
use base qw(Wx::BoxSizer);
use Scalar::Util qw(blessed looks_like_number);

sub new {
	my ($class, $parent, $widgets, $orientation, $init_arg) = @_;
	# complain about bad arguments
	die __PACKAGE__.'::new needs a parent widget as first parameter'
		if defined $parent and not (blessed($parent) and $parent->isa('Wx::Window') );;
	die __PACKAGE__.'::new needs a widget array as second parameter' unless ref $widgets eq 'ARRAY';
	die __PACKAGE__.'::new needs a Wx orientation constant as third parameter'
		if defined $orientation and $orientation != &Wx::wxVERTICAL and $orientation != &Wx::wxHORIZONTAL;
	die __PACKAGE__.'::new needs a hash ref as forth parameter' if defined $init_arg and ref $init_arg ne 'HASH';

	my %default_arg = (
		flags        => &Wx::wxLEFT|&Wx::wxRIGHT|&Wx::wxGROW,
		border       => 0,
		add_callback => sub {},
	);
	# sanitize arguments
	$orientation     =  &Wx::wxHORIZONTAL unless defined $orientation;
	my (%arg, @arg_stack);
	for (keys %default_arg) { $arg{$_} = defined $init_arg->{$_} ? $init_arg->{$_} : $default_arg{$_} }
	$arg{'flags'} = ${$arg{'flags'}} | $default_arg{'flags'} if ref $arg{'flags'} eq 'SCALAR';
	$arg{'add_callback'} = $default_arg{'add_callback'} unless ref $arg{'add_callback'} eq 'CODE';
	my $daddy = $parent;
	$daddy = $daddy->GetParent while $daddy->GetParent;
	$daddy = '' unless ref $daddy eq 'Wx::Perl::Smart::Frame' or ref $daddy eq 'Wx::Perl::Smart::Panel';

	my ($self) = $class->SUPER::new( $orientation );
	for (my $pos = 0; $pos < scalar @$widgets; $pos++) {
		my $widget = $widgets->[$pos];
		my ($proportion) = (0);
		$proportion++, $widget = $$widget while ref $widget eq 'REF' or ref $widget eq 'SCALAR';

		if (ref $widget eq 'HASH'){
			my %old_arg = %arg;
			push @arg_stack, \%old_arg;
			for (keys %default_arg) {$arg{$_} = $widget->{$_} if defined $widget->{$_}}
			next;
		}
		elsif (ref $widget eq 'ARRAY'){
			my $sizer = Wx::Perl::Smart::Sizer->new(
				$parent, $widget, toggle_orientation($orientation),
				{add_callback => $arg{'add_callback'}}
			);
			return $sizer if scalar @$widgets == 1;
			$widget = $sizer;
		}
		elsif (not ref $widget) {
			next unless $widget;
			if (substr($widget, 0, 1) eq '-' ) {
				($widget, my $name) = split(':', substr($widget, 1));
				if ($widget eq 'LabeledBox') {
					next unless exists $widgets->[$pos+1];
					$widget = $widgets->[$pos+1];
					next unless ref $widget eq 'ARRAY' and scalar @$widget > 0 and not ref $widget->[0];
					$pos++;
					my $label = shift @$widget;
					require Wx::Perl::Smart::LabeledBox;
					$widget = Wx::Perl::Smart::LabeledBox->new($parent, $label, $widget);
				}
				elsif ($widget eq 'TabbedBox' ) {
					next unless exists $widgets->[$pos+1];
					$widget = $widgets->[$pos+1];
					next unless ref $widget eq 'ARRAY' and scalar @$widget > 0 and not ref $widget->[0];
					$pos++;
					require Wx::Perl::Smart::TabbedBox;
					$widget = Wx::Perl::Smart::TabbedBox->new(
						$parent, $widget, toggle_orientation($orientation),
						{add_callback => $arg{'add_callback'}}
					);
				}
			}
			elsif (substr($widget, 0, 1) eq '<' and substr($widget, -1) eq '>') {
				next unless $daddy;
				$widget = $daddy->GetSubscribedWidget( substr($widget, 1, -1) );
				next unless $widget;
			}
			elsif (looks_like_number($widget)) {
				$proportion 
					? $self->AddStretchSpacer( $proportion )
					: $self->AddSpacer( $widget );
				next;
			}
			elsif (substr($widget, 0, 1) eq '-' or substr($widget, 0, 1) eq '|') {
				$widget = $orientation == &Wx::wxVERTICAL
					? Wx::StaticLine->new($parent,-1,[-1,-1],[-1,2])
					: Wx::StaticLine->new($parent,-1,[-1,-1],[2,-1]);
			}
			else {
				$widget = substr($widget,1) if substr($widget,0,1) eq '-';
				$widget = Wx::StaticText->new($parent, -1, $widget);
			}
		}
		next unless blessed($widget) and ($widget->isa('Wx::Window') or $widget->isa('Wx::Sizer'));
		$arg{'add_callback'}->($widget);
		$widget->Reparent($parent) if defined $parent and $widget->isa('Wx::Window');
		$widget->Show(1) if $widget->isa('Wx::Window');
		$self->Add( $widget, $proportion, $arg{'flags'}, $arg{'border'});
	}
	return $self;
}

sub toggle_orientation {
	die __PACKAGE__.'::toggle_orientation needs wxVERTICAL or wxHORIZONTAL as input'
		unless $_[0] == &Wx::wxVERTICAL or $_[0] == &Wx::wxHORIZONTAL;
	return $_[0] == &Wx::wxHORIZONTAL ? &Wx::wxVERTICAL : &Wx::wxHORIZONTAL;
}

1;

__DATA__

Syntax Def:

$var		Widget Ref			pointer to the self made widget object/string/number/list
<name>		named widget		these have to subscribe to the smart frame/panel first

'text'		Label				creates a static text widget
'---'		Line				creates a static line widget
'|'								(horizontal or vertical according to sizer orient)
								(use as many '-' or '|' as you prefer)
number		n px space			inserts a spacer with that number amount of pixel
\...		proportion++		all space left gets divided between the hungry according their proportion number
								(default is 0)
\n			stretching space	creates a hungry spacer (more backslashes => more proportion)

[,,]		BoxSizer			member widgets get stacked vertically, in subarray horizontally, and so on
%LabeledBox	StaticBoxSizer		arrange widgets within a labeled box
%TabbedBox	Notebook			arrange widgets within tabs of a notebook
%Grid=>[]	GridBoxSizer		arrange widgets within a table
{k=>v,}		set attributes		overwrite selected attributs, become effective with next element
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.