Graphics-Grid

 view release on metacpan or  search on metacpan

lib/Graphics/Grid.pm  view on Meta::CPAN

has _gp_stack => (
    is      => 'ro',
    traits  => ['Array'],
    default => sub { [] },
    handles => {
        _push_gp  => 'push',
        _pop_gp   => 'pop',
        _clear_gp => 'clear',
    }
);

sub _build_driver {
    my $driver_cls = 'Graphics::Grid::Driver::Cairo';
    load $driver_cls;
    return $driver_cls->new();
}

sub _build__vptree {
    my ($self) = @_;
    return Graphics::Grid::ViewportTree->new(
        node => Graphics::Grid::Viewport->new(
            name => 'ROOT',
            gp   => $self->driver->default_gpar()
        )
    );
}

sub _build__current_vptree { $_[0]->_vptree }


method current_vptree( $all = true ) {
    return ( $all ? $self->_vptree : $self->_current_vptree );
}


method current_viewport() {
    return $self->_current_vptree->node;
}

method _push_vp($vp) {

    # Viewports in a stack are pushed in series.
    # Viewports in a list are pushed in parallel.
    # For a tree of viewports, the parent is pushed then the children are
    #  pushed in parallel.

    # Push a list of viewpoints in parallel, and move current to last node.
    my $push_node = sub {
        my (@vps) = @_;
        return unless @vps;

        my @trees =
          map { Graphics::Grid::ViewportTree->new( node => $_ ) } @vps;
        $self->_current_vptree->add_children(@trees);
        $self->_current_vptree( $trees[-1] );
    };

    if ( $vp->$_isa('Graphics::Grid::Viewport') ) {
        &$push_node($vp);
    }
    elsif ( Ref::Util::is_arrayref($vp) ) {
        &$push_node(@$vp);
    }
    elsif ( $vp->$_isa('Graphics::Grid::ViewportTree') ) {
        my $t = $vp;
        $self->_current_vptree->add_child($t);

        # go right-then-down in the sub-tree
        while ( my $child_count = $t->child_count ) {
            $t = $t->get_child_at( $child_count - 1 );
        }
        $self->_current_vptree($t);
    }
}


method push_viewport(@vps) {
    for my $vp (@vps) {
        $self->_push_vp($vp);
    }
    $self->_set_vptree( $self->_current_vptree );
}

sub _up_viewport {
    my ( $self, $n, $is_pop ) = @_;

    return if ( $n == 0 );
    return unless ( $self->_current_vptree->has_parent );

    $self->_current_vptree( $self->_current_vptree->parent );
    if ($is_pop) {
        $self->_current_vptree->children( [] );
    }
    $self->_up_viewport( $n - 1, $is_pop );
}


method pop_viewport( $n = 1 ) {
    if ( $n < 0 ) {
        die "must pop at least one viewport";
    }
    if ( $n == 0 ) {

        # retain only the root node
        $self->_current_vptree( $self->_vptree );
        $self->_current_vptree->children( [] );
    }
    else {    # $n > 0
        $self->_up_viewport( $n, true );
    }
    $self->_set_vptree( $self->_current_vptree );
}


method up_viewport( $n = 1 ) {
    if ( $n < 0 ) {
        die "must navigate at least one viewport";
    }
    if ( $n == 0 ) {
        $self->_current_vptree( $self->_vptree );
    }



( run in 2.160 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )