package IUP::Internal::Element;
use strict;
use warnings;
use IUP::Internal::LibraryIup;
use IUP::Internal::Callback;
use IUP::Constants qw(IUP_CURRENT);
use Carp;
use Scalar::Util qw(blessed looks_like_number);
sub import {
my $p = shift;
#warn "### IUP::Internal::Element->import($p) called";
# callback accessors
if (my $c = IUP::Internal::Callback::_get_cb_eval_code($p)) {
eval($c);
die "###ERROR### import failed(cb) '$p': " . $@ if $@;
}
}
sub AUTOLOAD {
my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
die "FATAL: unknown method '$name'" unless $name =~ /^[A-Z0-9_]+$/;
my $method = sub {
return $_[0]->GetAttribute($name) if scalar(@_) == 1;
return $_[0]->SetAttribute($name, $_[1]) if scalar(@_) > 1;
};
no strict 'refs';
*{$AUTOLOAD} = $method;
goto &$method;
}
sub BEGIN {
#warn "***DEBUG*** IUP::Internal::Element::BEGIN() started\n";
IUP::Internal::LibraryIup::_IupControlsOpen();
}
# constructor
sub new {
my $class = shift;
my $argc = scalar @_;
my %args = ();
my $firstonly;
my $self = { class => $class };
bless($self, $class);
if ($argc == 1) {
$firstonly = shift;
}
elsif ($argc > 1 && $argc % 2 == 0) {
%args = @_;
}
elsif ($argc > 0) {
carp "Warning: $class->new() odd number of arguments ($argc), ignoring all parameters";
}
$self->ihandle($self->_create_element(\%args, $firstonly));
unless ($self->ihandle) {
carp "Error: $class->new() failed";
return;
}
if (!$self->HasValidClassName) {
my $c = $self->GetClassName || '';
carp "Warning: $class->new() classname mismatch '$class' vs. '$c'";
}
my @cb;
my @at;
while (@_) { # keep original order
my $k = shift;
my $v = shift;
next unless defined $k;
next unless exists $args{$k}; #some values may be deleted during _create_element()
if ($self->IsValidCallbackName($k)) {
push(@cb, $k, $v);
}
elsif ($k eq 'name') {
$self->SetName($v);
}
elsif ($k eq uc($k)) {
push(@at, $k, $v); # assuming an attribute
}
else {
carp "Warning: $class->new() ignoring unknown parameter '$k'";
}
}
$self->SetCallback(@cb) if scalar(@cb);
$self->SetAttribute(@at) if scalar(@at);
return $self;
}
# constructor
sub new_no_ihandle {
my $class = shift;
my $self = { class => $class };
bless($self, $class);
return $self;
}
# constructor
sub new_from_ihandle {
my ($class, $ih) = @_;
my $self = { class => $class };
bless($self, $class);
$self->ihandle($ih);
if (!$self->HasValidClassName) {
my $c = $_[0]->GetClassName || '';
carp "Warning: $class->new_from_ihandle() classname mismatch '$class' vs. '$c'";
}
return $self;
}
# accessor
sub ihandle {
if ($_[1]) {
IUP::Internal::LibraryIup::_register_ih($_[1], $_[0]);
return $_[0]->{'!int!ihandle'} = $_[1]
}
else {
return $_[0]->{'!int!ihandle'};
}
}
sub GetName {
#char* IupGetName(Ihandle* ih); [in C]
#iup.GetName(ih: ihandle) -> (name: string) [in Lua]
my $self = shift;
return IUP::Internal::LibraryIup::_IupGetName($self->ihandle);
}
sub SetName {
#Ihandle *IupSetHandle(const char *name, Ihandle *ih); [in C]
#iup.SetHandle(name: string, ih: ihandle) -> old_ih: ihandle [in Lua]
my ($self, $name) = @_;
my $ih = IUP::Internal::LibraryIup::_IupSetHandle($name, $self->ihandle);
return IUP->GetByIhandle($ih);
}
sub SetAttribute {
#void IupSetAttribute(Ihandle *ih, const char *name, const char *value); [in C]
#iup.SetAttribute(ih: iulua_tag, name: string, value: string) [in Lua]
#void IupStoreAttribute(Ihandle *ih, const char *name, const char *value); [in C]
#iup.StoreAttribute(ih: iulua_tag, name: string, value: string) [in Lua]
my $self = shift;
#BEWARE: we need to keep the order of attribute assignment - thus cannot use for (keys %args) {...}
while(1) {
my $k = shift;
carp("Warning: invalid attribute name"), last unless defined $k;
my $v = shift;
if (!ref($v)) {
IUP::Internal::LibraryIup::_IupStoreAttribute($self->ihandle, $k, $v);
}
elsif (blessed($v) && $v->can('ihandle')) {
#carp "Debug: attribute '$k' is a refference '" . ref($v) . "'";
IUP::Internal::LibraryIup::_IupSetAttributeHandle($self->ihandle, $k, $v->ihandle);
#assuming any element ref stored into iup attribute to be a child
unless($self->_get_child_ref($v)) {
#XXX-FIXME - child element destruction: happens for: MENU, MDIMENU, IMAGE*, PARENTDIALOG (can cause memory leaks)
#during Destroy() we might destroy elements shared by more dialogs
#warn "***DEBUG*** Unexpected situation elem='".ref($self)."' attr='$k'";
$self->_store_child_ref($v); #xxx(ANTI)DESTROY-MAGIC
}
}
else {
carp "[warning] cannot set attribute '$k' to '$v'";
}
last unless @_;
}
return $self;
}
sub SetAttributeId {
#void IupSetAttributeId(Ihandle *ih, const char *name, int id, const char *value); [in C]
#iup.SetAttributeId(ih: ihandle, name: string, id: number, value: string) [in Lua]
#void IupStoreAttributeId(Ihandle *ih, const char *name, int id, const char *value); [in C]
#iup.StoreAttributeId(ih: ihandle, name: string, id: number, value: string) [in Lua]
my ($self, $name, $id, $v) = @_;
IUP::Internal::LibraryIup::_IupStoreAttributeId($self->ihandle, $name, $id, $v);
return $self;
}
sub SetAttributeId2 {
#void IupStoreAttributeId2(Ihandle* ih, const char* name, int lin, int col, const char* value);
my ($self, $name, $lin, $col, $v) = @_;
IUP::Internal::LibraryIup::_IupStoreAttributeId2($self->ihandle, $name, $lin, $col, $v);
return $self;
}
sub GetAttribute {
#Ihandle* IupGetAttributeHandle(Ihandle *ih, const char *name); [in C]
#char *IupGetAttribute(Ihandle *ih, const char *name); [in C]
#iup.GetAttribute(ih: ihandle, name: string) -> value: string [in Lua]
my ($self, @names) = @_;
my @rv = ();
push(@rv, IUP::Internal::LibraryIup::_IupGetAttribute($self->ihandle, $_)) for (@names);
return (scalar(@names) == 1) ? $rv[0] : @rv; #xxxCHECKLATER not sure if this is a good idea
}
sub GetAttributeAsElement {
#special perl method
#XXX-FIXME needs testin g
my ($self, @names) = @_;
my @rv = ();
for (@names) {
my $v = IUP::Internal::LibraryIup::_IupGetAttribute($self->ihandle, $_);
push(@rv, defined $v ? IUP->GetByName($v) : undef);
}
return (scalar(@names) == 1) ? $rv[0] : @rv; #xxxCHECKLATER not sure if this is a good idea
}
sub GetAttributeId {
#char *IupGetAttributeId(Ihandle *ih, const char *name, int id); [in C]
#iup.GetAttributeId(ih: ihandle, name: string, id: number) -> value: string [in Lua]
my ($self, $name, @ids) = @_;
my @rv = ();
push(@rv, IUP::Internal::LibraryIup::_IupGetAttributeId($self->ihandle, $name, $_)) for (@ids);
return (scalar(@ids) == 1) ? $rv[0] : @rv; #xxxCHECKLATER not sure if this is a good idea
}
sub GetAttributeId2 {
#char* IupGetAttributeId2(Ihandle* ih, const char* name, int lin, int col);
my ($self, $name, $lin, $col) = @_;
return IUP::Internal::LibraryIup::_IupGetAttributeId2($self->ihandle, $name, $lin, $col);
}
sub SetCallback {
my ($self, %args) = @_;
for (keys %args) {
my ($action, $func) = ($_, $args{$_});
my $cb_init_func = IUP::Internal::Callback::_get_cb_init_function(ref($self), $action);
if (ref($cb_init_func) eq 'CODE') {
if (defined $func) {
#set callback
$self->{"!int!cb!$action!func"} = $func;
$self->{"!int!cb!$action!related"}->{$self->ihandle} = $self; #intentional circular dependency #xxx(ANTI)DESTROY-MAGIC
&$cb_init_func($self->ihandle);
}
else {
#clear (unset) callback
#warn("***DEBUG*** gonna unset callback '$action'\n");
IUP::Internal::Callback::_clear_cb($self->ihandle,$action);
for (keys %$self) {
#clear all related values
delete $self->{$_} if (/^!int!cb!\Q$action\E!/);
}
}
}
else {
carp "Warning: ignoring unknown callback '$action' (".ref($self).")";
}
}
return $self;
}
sub IsValidCallbackName {
return IUP::Internal::Callback::_is_cb_valid(ref($_[0]), $_[1]);
}
sub HasValidClassName {
my $p = lc(ref($_[0])); #perl class name
my $c = $_[0]->GetClassName || ''; #iup internal class name
# we are using IUP::Image for all - image, imagergb, imagergba
$c = 'image' if $c eq 'imagergb';
$c = 'image' if $c eq 'imagergba';
$c = 'canvasgl' if $c eq 'glcanvas';
$p = 'iup::dialog' if ($p eq 'iup::layoutdialog') && ($c eq 'dialog'); #xxxCHECKLATER seems like a bug
$p =~ s/^iup::gl::/gl/;
$p =~ s/^iup:://;
return $p eq $c ? 1 : 0;
}
sub Append {
#Ihandle* IupAppend(Ihandle* ih, Ihandle* new_child); [in C]
#iup.Append(ih, new_child: ihandle) -> (parent: ihandle) [in Lua]
my ($self, $new_child) = @_;
return unless ref $new_child;
my $ih = IUP::Internal::LibraryIup::_IupAppend($self->ihandle, $new_child->ihandle);
return IUP->GetByIhandle($ih);
}
sub ConvertXYToPos {
#int IupConvertXYToPos(Ihandle *ih, int x, int y); [in C]
#iup.ConvertXYToPos(ih: ihandle, x, y: number) -> (ret: number) [in Lua]
#It can be used for IupText (returns a position in the string), IupList (returns an item) or IupTree (returns a node identifier).
my ($self, $x, $y) = @_;
return IUP::Internal::LibraryIup::_IupConvertXYToPos($self->ihandle, $x, $y);
}
sub Destroy {
#void IupDestroy(Ihandle *ih); [in C]
#iup.Destroy(ih: ihandle) [in Lua]
my $self = shift;
my $ih = $self->ihandle;
#destroy all perl related stuff on element + its children
$self->_internal_destroy();
#BEWARE: at this point $self->ihandle is undef
IUP::Internal::LibraryIup::_unregister_ih($ih); #xxxCHECKLATER not necessary if weaken refs stored in global register
IUP::Internal::LibraryIup::_IupDestroy($ih);
return $self;
}
sub Detach {
#void IupDetach(Ihandle *child); [in C]
#iup.Detach(child: ihandle) or child:detach() [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupDetach($self->ihandle);
return $self;
}
sub GetAllAttributes {
#int IupGetAllAttributes(Ihandle* ih, char** names, int max_n); [in C]
#iup.GetAllAttributes(ih: ihandle, max_n: number) -> (names: table, n: number) [in Lua]
my ($self, $max_n) = @_;
return IUP::Internal::LibraryIup::_IupGetAllAttributes($self->ihandle, $max_n);
}
sub GetAttributes {
#char* IupGetAttributes (Ihandle *ih); [in C]
#iup.GetAttributes(ih: iulua_tag) -> (ret: string) [in Lua]
#NOT USING original C API - different approach
my $self = shift;
my $result = { };
$result->{$_} = $self->GetAttribute($_) for ($self->GetAllAttributes);
return $result;
}
sub GetBrother {
#Ihandle* IupGetBrother(Ihandle* ih); [in C]
#iup.GetBrother(ih: ihandle) -> brother: ihandle [in Lua]
my $self = shift;
my $ih = IUP::Internal::LibraryIup::_IupGetBrother($self->ihandle);
return IUP->GetByIhandle($ih);
}
sub GetClassName {
#char* IupGetClassName(Ihandle* ih); [in C]
#iup.GetClassName(ih: ihandle) -> (name: string) [in Lua]
my $self = shift;
return IUP::Internal::LibraryIup::_IupGetClassName($self->ihandle);
}
sub GetClassType {
#char* IupGetClassType(Ihandle* ih); [in C]
#iup.GetClassType(ih: ihandle) -> (name: string) [in Lua]
my $self = shift;
return IUP::Internal::LibraryIup::_IupGetClassType($self->ihandle);
}
sub GetChildCount {
#int IupGetChildCount(Ihandle* ih); [in C]
#iup.GetChildCount(ih: ihandle) -> pos: number [in Lua]
my $self = shift;
return IUP::Internal::LibraryIup::_IupGetChildCount($self->ihandle);
}
sub Map {
#int IupMap(Ihandle* ih); [in C]
#iup.Map(ih: iuplua-tag) -> ret: number [in Lua]
my $self = shift;
return IUP::Internal::LibraryIup::_IupMap($self->ihandle);
}
sub Redraw {
#void IupRedraw(Ihandle* ih, int children); [in C]
#iup.Redraw(ih: ihandle, children: boolen) [in Lua]
my ($self, $children) = @_;
IUP::Internal::LibraryIup::_IupRedraw($self->ihandle, $children);
return $self;
}
sub Refresh {
#void IupRefresh(Ihandle *ih); [in C]
#iup.Refresh(ih: ihandle) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupRefresh($self->ihandle);
return $self;
}
sub RefreshChildren {
#void IupRefreshChildren(Ihandle *ih); [in C]
#iup.RefreshChildren(ih: ihandle) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupRefreshChildren($self->ihandle);
return $self;
}
sub Reparent {
#int IupReparent(Ihandle* ih, Ihandle* new_parent, Ihandle* ref_child);
#iup.Reparent(child, parent: ihandle) [in Lua]
my ($self, $new_parent, $ref_child) = @_;
return IUP::Internal::LibraryIup::_IupReparent($self->ihandle, $new_parent->ihandle, $ref_child->ihandle);
}
sub ResetAttribute {
#void IupResetAttribute(Ihandle *ih, const char *name); [in C]
#iup.ResetAttribute(ih: iulua_tag, name: string) [in Lua]
my ($self, $name) = @_;
IUP::Internal::LibraryIup::_IupResetAttribute($self->ihandle, $name);
return $self;
}
sub SaveClassAttributes {
#void IupSaveClassAttributes(Ihandle* ih); [in C]
#iup.SaveClassAttributes(ih: ihandle) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupSaveClassAttributes($self->ihandle);
return $self;
}
sub SetFocus {
#Ihandle *IupSetFocus(Ihandle *ih); [in C]
#iup.SetFocus(ih: ihandle) -> ih: ihandle [in Lua]
my $self = shift;
my $ih = IUP::Internal::LibraryIup::_IupSetFocus($self->ihandle);
return IUP->GetByIhandle($ih);
}
sub Unmap {
#void IupUnmap(Ihandle* ih); [in C]
#iup.Unmap(ih: iuplua-tag) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupUnmap($self->ihandle);
return $self;
}
sub Update {
#void IupUpdate(Ihandle* ih); [in C]
#iup.Update(ih: ihandle) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupUpdate($self->ihandle);
return $self;
}
sub UpdateChildren {
#void IupUpdateChildren(Ihandle* ih); [in C]
#iup.UpdateChildren(ih: ihandle) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupUpdateChildren($self->ihandle);
return $self;
}
sub Hide {
#int IupHide(Ihandle *ih); [in C]
#iup.Hide(ih: ihandle) -> (ret: number) [in Lua]
my $self = shift;
IUP::Internal::LibraryIup::_IupHide($self->ihandle);
return $self;
}
sub Popup {
#int IupPopup(Ihandle *ih, int x, int y); [in C]
#iup.Popup(ih: ihandle[, x, y: number]) -> (ret: number) [in Lua]
#or ih:popup([x, y: number]) -> (ret: number) [in Lua]
my ($self, $x, $y) = @_;
$x = IUP_CURRENT unless defined $x;
$y = IUP_CURRENT unless defined $y;
return IUP::Internal::LibraryIup::_IupPopup($self->ihandle, $x, $y);
}
sub Show {
#int IupShow(Ihandle *ih); [in C]
#iup.Show(ih: ihandle) -> (ret: number) [in Lua]
#or ih:show() -> (ret: number) [in IupLua]
my $self = shift;
return IUP::Internal::LibraryIup::_IupShow($self->ihandle);
}
sub ShowXY {
#int IupShowXY(Ihandle *ih, int x, int y); [in C]
#iup.ShowXY(ih: ihandle[, x, y: number]) -> (ret: number) [in Lua]
#or ih:showxy([x, y: number]) -> (ret: number) [in Lua]
my ($self, $x, $y) = @_;
$x = IUP_CURRENT unless defined $x;
$y = IUP_CURRENT unless defined $y;
return IUP::Internal::LibraryIup::_IupShowXY($self->ihandle, $x, $y);
}
sub GetNextChild {
#Ihandle *IupGetNextChild(Ihandle* ih, Ihandle* child); [in C]
#iup.GetNextChild(ih, child: ihandle) -> next_child: ihandle [in Lua]
my ($self, $child) = @_;
my $ih;
#xxxCHECKLATER check this - kind of a hack (now more or less works)
if (defined $child) {
$ih = IUP::Internal::LibraryIup::_IupGetNextChild($self->ihandle, $child->ihandle);
}
else {
$ih = IUP::Internal::LibraryIup::_IupGetNextChild($self->ihandle, undef);
}
return IUP->GetByIhandle($ih);
}
sub PreviousField {
#Ihandle* IupPreviousField(Ihandle* ih); [in C]
#iup.PreviousField(ih: ihandle) -> (previous: ihandle) [in Lua]
my $self = shift;
my $ih = IUP::Internal::LibraryIup::_IupPreviousField($self->ihandle);
return IUP->GetByIhandle($ih);
}
sub GetChildPos {
#int IupGetChildPos(Ihandle* ih, Ihandle* child); [in C]
#iup.GetChildPos(ih, child: ihandle) -> pos: number [in Lua]
my ($self, $child) = @_;
return IUP::Internal::LibraryIup::_IupGetChildPos($self->ihandle, $child->ihandle);
}
sub GetDialog {
#Ihandle* IupGetDialog(Ihandle *ih); [in C]
#iup.GetDialog(ih: ihandle) -> (ih: ihandle) [in Lua]
my $self = shift;
my $ih = IUP::Internal::LibraryIup::_IupGetDialog($self->ihandle);
return IUP->GetByIhandle($ih);
}
sub GetDialogChild {
#Ihandle* IupGetDialogChild(Ihandle *ih, const char* name); [in C]
#iup.GetDialogChild(ih: ihandle, name: string) -> (ih: ihandle) [in Lua]
my ($self, $name) = @_;
my $ih = IUP::Internal::LibraryIup::_IupGetDialogChild($self->ihandle, $name);
return IUP->GetByIhandle($ih);
}
sub GetParamParam {
#iup.GetParamParam(dialog: ihandle, param_index: number)-> (param: ihandle) [in Lua]
my ($self, $param_index) = @_;
my $ih = IUP::Internal::LibraryIup::_IupGetAttributeIH($self->ihandle, "PARAM" . $param_index);
return IUP->GetByIhandle($ih);
}
sub GetParamValue {
# extra function - not in standard iup C API
#iup.GetParamParam(dialog: ihandle, param_index: number)-> (param: ihandle) [in Lua]
my ($self, $param_index, $newval) = @_;
my $ih = IUP::Internal::LibraryIup::_IupGetAttributeIH($self->ihandle, "PARAM" . $param_index);
my $ct = IUP::Internal::LibraryIup::_IupGetAttributeIH($ih, "CONTROL");
if (defined $newval) {
#xxxWORKAROUND
#when setting listindex values there is a mismatch 0-based vs 1-based indexes
#setting VALUE to 1 selects the first item - there seems not to be an easy workaround
my $t = IUP::Internal::LibraryIup::_IupGetAttribute($ih, "TYPE");
$newval++ if ($t && $t eq 'LIST' && looks_like_number($newval) && $newval >=0);
#xxxWORKAROUND-FINISHED
IUP::Internal::LibraryIup::_IupStoreAttribute($ih, "VALUE", $newval);
IUP::Internal::LibraryIup::_IupStoreAttribute($ct, "VALUE", $newval);
}
else {
return IUP::Internal::LibraryIup::_IupGetAttribute($ih, "VALUE"); #usually the new value
#XXX-beware it might be dufferent from:
#return IUP::Internal::LibraryIup::_IupGetAttribute($ct, "VALUE"); #usually the old value
}
}
sub GetChild {
#Ihandle *IupGetChild(Ihandle* ih, int pos); [in C]
#iup.GetChild(ih: ihandle, pos: number) -> child: ihandle [in Lua]
my ($self, $pos) = @_;
my $ih = IUP::Internal::LibraryIup::_IupGetChild($self->ihandle, $pos);
return IUP->GetByIhandle($ih);
}
sub GetParent {
#Ihandle* IupGetParent(Ihandle *ih); [in C]
#iup.GetParent(ih: ihandle) -> parent: ihandle [in Lua]
my $self = shift;
my $ih = IUP::Internal::LibraryIup::_IupGetParent($self->ihandle);
return IUP->GetByIhandle($ih);
}
sub Insert {
#Ihandle* IupInsert(Ihandle* ih, Ihandle* ref_child, Ihandle* new_child); [in C]
#iup.Append(ih, ref_child, new_child: ihandle) -> (parent: ihandle) [in Lua]
my ($self, $ref_child, $new_child) = @_;
return unless ref $ref_child && ref $new_child;
my $ih = IUP::Internal::LibraryIup::_IupInsert($self->ihandle, $ref_child->ihandle, $new_child->ihandle);
return IUP->GetByIhandle($ih);
}
sub NextField {
#Ihandle* IupNextField(Ihandle* ih); [in C]
#iup.NextField(ih: ihandle) -> (next: ihandle) [in Lua]
my $self = shift;
my $ih = IUP::Internal::LibraryIup::_IupNextField($self->ihandle);
return IUP->GetByIhandle($ih);
}
sub DESTROY {
#IMPORTANT: do not automatically destroy iup elements
#warn "XXX-DEBUG: IUP::Internal::Element::DESTROY(): " . ref($_[0]) . " [" . $_[0]->ihandle . "]\n";
}
###### INTERNAL HELPER FUNCTIONS
sub _create_element {
my ($self, @args) = @_;
die "Function _create_element() not implemented in IUP::Internal::Element";
}
sub _get_child_ref {
#xxx(ANTI)DESTROY-MAGIC
my ($self, $ih) = @_;
return $self->{'!int!child'}->{$ih};
}
sub _store_child_ref {
#xxx(ANTI)DESTROY-MAGIC
my $self = shift;
#warn("***DEBUG*** _store_child_ref started\n");
for (@_) {
next unless blessed($_);
$self->{'!int!child'}->{$_->ihandle} = $_;
}
}
sub _internal_destroy {
my $self = shift;
#unset all callbacks
#warn("***DEBUG*** _internal_destroy ".$self->ihandle." started\n");
for (keys %$self) {
$self->SetCallback($1, undef) if (/^!int!cb!([^!]+)!func$/);
}
#go through all children #xxx(ANTI)DESTROY-MAGIC
for (keys %{$self->{'!int!child'}}) {
$self->{'!int!child'}->{$_}->_internal_destroy()
}
#in the last step destroy $self->ihandle
#warn("***DEBUG*** _internal_destroy ".$self->ihandle." finished\n");
$self->ihandle(undef);
}
sub _proc_child_param {
#handling new(child=>$child) or new(child=>[...]) of new($child) or new([...])
#warn "***DEBUG*** _proc_child_param started\n";
my ($self, $func, $args, $firstonly) = @_;
my @list;
my @ihlist;
if (defined $firstonly) {
@list = (ref($firstonly) eq 'ARRAY') ? @$firstonly : ($firstonly);
}
elsif (defined $args && defined $args->{child}) {
if (ref($args->{child}) eq 'ARRAY') {
@list = @{$args->{child}};
}
elsif (blessed($args->{child}) && $args->{child}->can('ihandle')) {
@list = ($args->{child});
}
else {
carp "Warning: 'child' parameter has to be a reference to IUP element";
}
delete $args->{child};
}
for (@list) {
if (blessed($_) && $_->can('ihandle')) {
push @ihlist, $_->ihandle;
$self->_store_child_ref($_); #xxx(ANTI)DESTROY-MAGIC
}
else {
carp "warning: undefined item passed as 'child' parameter of ",ref($self),"->new()";
}
}
return &$func(@ihlist);
}
#internal helper func
sub _proc_child_param_single {
#handling new(child=>$child, ...) or new($child)
#warn "***DEBUG*** _proc_child_param_single started\n";
my ($self, $func, $args, $firstonly) = @_;
my $ih;
if (defined $firstonly) {
if (blessed($firstonly) && $firstonly->can('ihandle')) {
$ih = &$func($firstonly->ihandle); #call func
$self->_store_child_ref($firstonly); #xxx(ANTI)DESTROY-MAGIC
}
else {
carp "Warning: parameter 'child' has to be a reference to IUP element";
$ih = &$func(undef); #call func
}
}
elsif (defined $args && defined $args->{child}) {
if (blessed($args->{child}) && $args->{child}->can('ihandle')) {
$ih = &$func($args->{child}->ihandle); #call func
$self->_store_child_ref($args->{child}); #xxx(ANTI)DESTROY-MAGIC
}
else {
carp "Warning: 'child' parameter has to be a reference to IUP element";
$ih = &$func(undef); #call func
}
delete $args->{child};
}
else {
$ih = &$func(undef); #call func
}
return $ih;
}
1;
=pod
=head1 NAME
IUP::Internal::Element - [internal only] DO NOT USE this unless you know what could happen!
=cut