Source

Kephra / lib / Kephra / App / Sizer.pm

Full commit
use strict;
use warnings;
use Scalar::Util qw(blessed looks_like_number);
use Kephra::API;
use Kephra::App::Util;



package Kephra::App::Sizer;
our @ISA = 'Wx::Sizer';
my $is_widget = Kephra::App::Util::get('is_widget');


sub new {
	my ($class) = shift;
	my ($orient) = shift;

	if  (substr($orient, 0, 1) eq 'h') { $orient = &Wx::wxHORIZONTAL }
	elsif (substr($orient, 0, 1) eq 'v') { $orient = &Wx::wxVERTICAL }
	else {return Kephra::Log::error("need orientation as first parameter, not $orient", 1) }

	my $self = $class->SUPER::new( $orient );
	$self->{'orient'} = $orient;
	$self->{'children'} = [];
	$self->append(@_);
	$self;
}


# syntax sugar for insert method, unless insert can take list of child items
# all these methods are ment to be chained, thatswhy the $self at the end
sub before {
	my ($self) = shift;
	my ($mark_child) = shift;
	my $pos = $self->get_position($mark_child);
	return Kephra::Log::error("bookmark child $mark_child not found", 1) unless $pos > -1;
	$self->insert($pos, 0, @_);
}
sub after {
	my ($self) = shift;
	my ($mark_child) = shift;
	my $pos = $self->get_position($mark_child);
	return Kephra::Log::error("bookmark child $mark_child not found", 1) unless $pos > -1;
	$self->insert($pos+1, 0, @_);
}
sub prepend         { my ($self) = shift; $self->insert(  0, 0, @_ ); $self }
sub append          { my ($self) = shift; $self->insert( -1, 0, @_ ); $self }
sub append_expanded { my ($self) = shift; $self->insert( -1, 1, @_ ); $self }
sub insert          {
	my ($self) = shift;
	my ($position) = shift;
	my ($proportion) = shift;
	for (@_) {
		$self->_insert( $self->_build_item($position, $proportion, $_) );
		$position++ unless $position == -1;
	}
	$self;
}

# accepted items : 
# - arrayref: sizer with crossing orientation holding the list of items in the array
# - widget: add widget without proportion
# - widgetref: add with proportion
# - int: spacer
# - intref: stretchspacer
sub _build_item {
	my ($self, $position, $proportion, $child) = @_;
	my $refcount;
	while (ref $child eq 'REF'){ $refcount++; $child = $$child; }

	if (ref $child eq 'ARRAY'){
		my $child_orient = 
			$refcount % 2                          ? $self->{'orient'} 
		  : $self->{'orient'} == &Wx::wxHORIZONTAL ? &Wx::wxVERTICAL
		  :                                          &Wx::wxHORIZONTAL;
		my @subsizer_children = @$child;
		$child = __PACKAGE__->new( $child_orient, @subsizer_children );
	}

	my %item;
	if (defined blessed($child)){
		return Kephra::Log::error("got no proper widget, but $child", 2)
			unless $is_widget->($child) or ref $child eq __PACKAGE__;
		$item{'child'} = $child;
	}
	elsif (looks_like_number($child) and int $child == $child){
		return Kephra::Log::error("got no proper widget, but $child", 2)
			unless $is_widget->($child) or ref $child eq __PACKAGE__;
		$item{'child'} = 'space';
	}
	# already assembled 
	elsif (ref $child eq 'HASH'){ %item = %$child }
	else { return Kephra::Log::error("got no proper widget, but $child", 2) }

	$item{'position'} = $position;
	$item{'proportion'} = $proportion if $proportion;
	$item{'proportion'} += $refcount if $refcount;

	my %presets = (
		position => -1, proportion => 0, style => &Wx::wxGROW, border => 0,
	);
	# fill with default settings (presets)
	for (qw/position proportion style border/)
		{ $item{$_} = $presets{$_} unless exists $item{$_} }
	$item{position} = $self->GetChildren || 0 if $item{position} == -1;


	return \%item;
}

sub _insert { # only one item
	my ($self, $item) = @_;
	return Kephra::Log::error('got hash as item def') unless ref $item eq 'HASH';

	if ($item->{'child'} eq 'space'){
		if ($item->{'proportion'}){
			$self->InsertStretchSpacer( $item->{'position'},  $item->{'proportion'} )
		} else {
			$self->InsertSpacer(        $item->{'position'},  $item->{'border'} )
		}
	} else {
		splice @{$self->{'children'}}, $item->{'position'}, 0, $item->{'child'};
		$self->Insert(
			$item->{'position'},  $item->{'child'},  $item->{'proportion'},
			$item->{'style'},     $item->{'border'}
		);
	}
	$item->{'position'};
}

sub show      {_relayout( sub { $_[0]->Show(   $_[1], 1) }, @_) }
sub hide      {_relayout( sub { $_[0]->Hide(   $_[1] )   }, @_) }
sub detach    {_relayout( sub { $_[0]->Detach( $_[1] )   }, @_) }
sub remove    {_relayout( sub { $_[0]->Remove( $_[1] )   }, @_) } # del spacer & sizer
sub _relayout {
	my ($self, $child, $call) = @_;
	return Kephra::Log::error('need a coderef, not $call', 2) unless ref $call eq 'CODE';
	$call->($self, $child);
	$self->Layout;
	$self;
}


# getter
sub get_position {                                          # number of that child
	my ($self, $child) = @_;
	my $pos = 0;
	for ($self->GetChildren){
		return $pos if defined $_->GetWindow and $_->GetWindow eq $child;
		$pos++;
	}
	return -1;
}
sub is_child     { $_[0]->get_position( $_[1] ) > -1 ? 1 : 0 }
sub get_child    { $_[0]->GetItem($_[1])->GetWindow }       # child with that number
sub get_children { shift->{'children'}   }

1;