The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Ogre::BetaGUI::Window;

### Note: this was ported to Perl from:
# /// Betajaen's GUI 016 Uncompressed
# /// Written by Robin "Betajaen" Southern 07-Nov-2006, http://www.ogre3d.org/wiki/index.php/BetaGUI
# /// This code is under the Whatevar! licence. Do what you want; but keep the original copyright header.
###

use strict;
use warnings;
use Scalar::Util qw(refaddr);   # note: in core as of Perl 5.8

use Ogre 0.33;

use Ogre::BetaGUI qw(:wt);
use Ogre::BetaGUI::Button;
use Ogre::BetaGUI::Callback;
use Ogre::BetaGUI::TextInput;


# note: $Dimensions is an array ref with 4 values (Vector4)
sub new {
    my ($pkg, $Dimensions, $Material, $t, $caption, $gui) = @_;

    # Perl doesn't have enums (:wt exported above), so this sucks
    unless ($t == NONE or $t == MOVE or $t == RESIZE or $t == RESIZE_AND_MOVE) {
        die __PACKAGE__ . ": invalid type number '$t' (see :wt in Ogre::BetaGUI)";
    }

    my $self = bless {
        'x'     => $Dimensions->[0],  # x
        'y'     => $Dimensions->[1],  # y
        'w'     => $Dimensions->[2],  # z
        'h'     => $Dimensions->[3],  # w
        mGUI  => $gui,    # GUI *
        mTB   => undef,   # Button *
        mRZ   => undef,   # Button *
        mATI  => undef,   # TextInput *
        mAB   => undef,   # Button *
        mO    => undef,   # OverlayContainer *
        mB    => [],      # Buttons
        mT    => [],      # TextInputs
    }, $pkg;

    $self->{mO} = $gui->createOverlay($gui->{mO}->getName . ".w" . $gui->{wc},
                                      [$self->{'x'}, $self->{'y'}],
                                      [$self->{'w'}, $self->{'h'}], $Material);
    $gui->{wc}++;

    if ($t >= 2) {  # RESIZE
        my $c = Ogre::BetaGUI::Callback->new();
        $c->{t} = 4;

        $self->{mRZ} = $self->createButton([($Dimensions->[2] - 16), ($Dimensions->[3] - 16), 16, 16],
                                           $Material . ".resize", "", $c);
    }

    if ($t == 1 || $t == 3) {  # MOVE or RESIZE_AND_MOVE
        my $c = Ogre::BetaGUI::Callback->new();
        $c->{t} = 3;

        $self->{mTB} = $self->createButton([0, 0, $Dimensions->[2], 22],
                                           $Material . ".titlebar", $caption, $c);
    }

    return $self;
}

sub DESTROY {
    my ($self) = @_;
    $self->{mGUI}{mO}->remove2D($self->{mO})
      if defined($self->{mGUI}) && defined($self->{mGUI}{mO}) && defined($self->{mO});
}

sub createButton {
    my ($self, $Dimensions, $Material, $Text, $callback) = @_;

    my $x = Ogre::BetaGUI::Button->new($Dimensions, $Material, $Text, $callback, $self);
    push @{ $self->{mB} }, $x;
    return $x;
}

sub createTextInput {
    my ($self, $Dimensions, $Material, $Value, $length) = @_;
    my $x = Ogre::BetaGUI::TextInput->new($Dimensions, $Material, $Value, $length, $self);
    push @{ $self->{mT} }, $x;
    return $x;
}

sub createStaticText {
    my ($self, $Dimensions, $Text) = @_;

    my $x = $self->{mGUI}->createOverlay($self->{mO}->getName . "st." . $self->{mGUI}{tc},
                                         [$Dimensions->[0], $Dimensions->[1]],
                                         [$Dimensions->[2], $Dimensions->[3]],
                                         '', $Text, 0);
    $self->{mGUI}{tc}++;

    $self->{mO}->addChild($x);
    $x->show();
    return $x;
}

sub hide { $_[0]->{mO}->hide() }
sub show { $_[0]->{mO}->show() }
sub isVisible { $_[0]->{mO}->isVisible() }

sub setPosition {
    my ($self, $X, $Y) = @_;
    $self->{'x'} = $X;
    $self->{'y'} = $Y;
    $self->{mO}->setPosition($X, $Y);
}

# these return array ref, not Vector2
sub getPosition { [$_[0]->{'x'}, $_[0]->{'y'}] }
sub getSize { [$_[0]->{'w'}, $_[0]->{'h'}] }

sub setSize {
    my ($self, $W, $H) = @_;

    $self->{'w'} = $W;
    $self->{'h'} = $H;
    $self->{mO}->setDimensions($W, $H);

    $self->{mRZ}{'x'} = $self->{'w'} - 16;
    $self->{mRZ}{'y'} = $self->{'h'} - 16;
    $self->{mRZ}{mO}->setPosition($self->{mRZ}{'x'}, $self->{mRZ}{'y'});

    if ($self->{mTB}) {
        $self->{mTB}{'w'} = $self->{'w'};
        $self->{mTB}{mO}->setWidth($self->{mTB}{'w'});
    }
}

sub check {
    my ($self, $px, $py, $lmb) = @_;

    return 0 unless $self->{mO}->isVisible;

    if (!($px >= $self->{'x'} && $py >= $self->{'y'}) ||
        !($px <= $self->{'x'} + $self->{'w'} && $py <= $self->{'y'} + $self->{'h'}))
    {
        if ($self->{mAB}) {
            my $cb = $self->{mAB}{callback};
            if ($cb->{t} == 2) {
                if (exists($cb->{LS}) && defined($cb->{LS})) {
                    $cb->{LS}->onButtonPress($self->{mAB}, 3);
                }
                else {
                    warn "onButtonPress not called: LS undef at ", __FILE__, ":", __LINE__, $/;
                }
            }

            $self->{mAB}->activate(0);
            undef $self->{mAB};
        }
        return 0;
    }

    foreach my $mb (@{ $self->{mB} }) {
        next if $mb->in($px, $py, $self->{'x'}, $self->{'y'});

        if ($self->{mAB}) {
            if (refaddr($mb) != refaddr($self->{mAB})) {
                $self->{mAB}->activate(0);

                # xxx: there's something wrong here.. when you drag a window
                # around quickly, and the mouse cursor detaches from the window
                # (which is a separate bug....) it can go across another button/window
                # and apparently get in here with $cb->{LS} undef.
                my $cb = $self->{mAB}{callback};
                if (exists($cb->{LS}) && defined($cb->{LS})) {
                    $cb->{LS}->onButtonPress($self->{mAB}, 3);
                }
                else {
                    warn "onButtonPress not called: LS undef at ", __FILE__, ":", __LINE__, $/;
                }
            }
        }

        $self->{mAB} = $mb;
        $self->{mAB}->activate(1);

        if ($self->{mATI} && $lmb) {
            $self->{mATI}{mO}->setMaterialName($self->{mATI}{mmn});
            undef $self->{mATI};
        }

        my $t = $self->{mAB}{callback}{t};
        if ($t == 1) {
            $self->{mAB}{callback}{fp}->($self->{mAB}, $lmb);
        }
        elsif ($t == 2) {
            my $cb = $self->{mAB}{callback};
            if (exists($cb->{LS}) && defined($cb->{LS})) {
                $cb->{LS}->onButtonPress($self->{mAB}, $lmb);
            }
            else {
                warn "onButtonPress not called: LS undef at ", __FILE__, ":", __LINE__, $/;
            }
        }
        elsif ($t == 3) {
            if ($lmb) {
                $self->setPosition($px - ($self->{mAB}{'w'} / 2), $py - ($self->{mAB}{'h'} / 2));
            }
        }
        elsif ($t == 4) {
            if ($lmb) {
                $self->setSize($px - $self->{'x'} + 8, $py - $self->{'y'} + 8);
            }
        }

        return 1;
    }

    return 0 unless $lmb;

    foreach my $mt (@{ $self->{mT} }) {
        next if $mt->in($px, $py, $self->{'x'}, $self->{'y'});

        $self->{mATI} = $mt;
        $self->{mATI}{mO}->setMaterialName($self->{mATI}{mma});
        return 1;
    }

    if ($self->{mATI}) {
        $self->{mATI}{mO}->setMaterialName($self->{mATI}{mmn});
        undef $self->{mATI};
        return 1;
    }

    return 0;
}

sub checkKey {
    my ($self, $key, $px, $py) = @_;

    return 0 unless $self->{mO}->isVisible;

    return 0 if !($px >= $self->{'x'} && $py >= $self->{'y'}) ||
        !($px <= $self->{'x'} + $self->{'w'} && $py <= $self->{'y'} + $self->{'h'});

    return 0 unless defined $self->{mATI};

    if ($key eq '!b') {
        chop $self->{mATI}{value};
        $self->{mATI}->setValue($self->{mATI}{value});
    }

    return 1 if length($self->{mATI}{value}) >= $self->{mATI}{length};

    $self->{mATI}{value} .= $key;
    $self->{mATI}{mCP}->setCaption($self->{mATI}{value});
    return 1;
}


1;