#!/usr/bin/perl # # PDL::Graphics::TriD::Tk - A Tk widget interface to the PDL::Graphics::TriD # visualization package: $Revision$ # # James P. Edwards # Instituto Nacional de Meteorologia # Brasilia, DF, Brasil # jedwards@inmet.gov.br # # This distribution is free software; you can # redistribute it and/or modify it under the same terms as Perl itself. # =head1 NAME PDL::Graphics::TriD::Tk - A Tk widget interface to the PDL::Graphics::TriD. =head1 SYNOPSIS =for usage # # Opens a Tk window with an embedded TriD window - that's all # see Demos/TkTriD_demo.pm for a better example # use PDL; use PDL::Graphics::TriD; use PDL::Graphics::TriD::GL; use Tk; use PDL::Graphics::TriD::Tk; my $MW = MainWindow->new(); my $TriDW = $MW->Tk( )->pack(-expand=>1, -fill=>'both'); $TriDW->MainLoop; =head1 DESCRIPTION The widget is composed of a Frame and the Display device of the TriD output. It inherits all of the attributes of a Tk Frame. All of the events associated with this window are handled through Tk with the exception of the event which must be handled by TriD because the Frame is never exposed. Default Mouse bindings, defined for button1 and button3, control TriD object orientation and size respectively. =cut package PDL::Graphics::TriD::Tk; use Tk; use PDL::Core; use PDL::Graphics::TriD; BEGIN { use PDL::Config; if ( $PDL::Config{USE_POGL} ) { eval "use OpenGL $PDL::Config{POGL_VERSION} qw(:all)"; eval 'use PDL::Graphics::OpenGL::Perl::OpenGL'; } else { eval 'use PDL::Graphics::OpenGL'; } } use strict; @PDL::Graphics::TriD::Tk::ISA = qw(Tk::Frame); $PDL::Graphics::TriD::Tk::verbose=0; Tk::Widget->Construct('Tk'); #$PDL::Graphics::TriD::Tk::VERSION = '$Revision$ ' ; #$PDL::Graphics::TriD::Tk::VERSION =~ s/\$Revision$\s*$/$1/; #sub Version {return $PDL::Graphics::TriD::Tk::VERSION;} =head1 FUNCTIONS =head2 Populate =for ref Used for widget initialization by Tk, this function should never be called directly =cut sub Populate { my($TriD, $args) = @_; if(defined $PDL::Graphics::TriD::cur){ print "Current code limitations prevent TriD:Tk from being loaded after "; print "another TriD graphics window has been defined. If you are running the "; print "PDL demo package, please start it again and run this demo first.\n"; exit; } $args->{-height}=300 unless defined $args->{-height}; $args->{-width}=300 unless defined $args->{-width}; $TriD->SUPER::Populate($args); # This bind causes GL to be initialized after the # Tk frame is ready to accept it $TriD->bind("", [ \&GLinit ]); print "Populate complete\n" if($PDL::Graphics::TriD::Tk::verbose); } =head2 MainLoop =for ref Should be used in place of the Tk MainLoop. Handles all of the Tk callbacks and calls the appropriate TriD display functions. =cut sub MainLoop { my ($self) = @_; unless ($Tk::inMainLoop) { local $Tk::inMainLoop = 1; while (Tk::MainWindow->Count) { DoOneEvent(Tk::DONT_WAIT()); if(defined $self->{GLwin}){ if( &XPending()){ my @e = &glpXNextEvent(); # if($e[0] == &ConfigureNotify) { # print "CONFIGNOTIFE\n" if($PDL::Graphics::TriD::verbose); # $self->reshape($e[1],$e[2]); # } $self->refresh(); } my $job=shift(@{$self->{WorkQue}}); if(defined $job){ my($cmd,@args) = @$job; &{$cmd}(@args); } } } } } =head2 GLinit =for ref GLinit is called internally by a Configure callback in Populate. This insures that the required Tk::Frame is initialized before the TriD::GL window that will go inside. =cut sub GLinit{ my($self,@args) = @_; if(defined $self->{GLwin}){ # print "OW= ",$self->width," OH= ",$self->height,"\n"; # $self->update; # print "NW= ",$self->width," NH= ",$self->height,"\n"; $self->{GLwin}{_GLObject}->XResizeWindow($self->width ,$self->height); $self->{GLwin}->reshape($self->width,$self->height); $self->refresh(); }else{ # width and height represent the largest size on my screen so that the # graphics window always fills the frame. my $options={parent=> ${$self->WindowId}, width=> $self->width, height=>$self->height}; $options->{mask} = ( ExposureMask ); $self->{GLwin} = PDL::Graphics::TriD::get_current_window($options); $self->{GLwin}->reshape($self->width,$self->height); # # This is an array for future expansion beyond the twiddle call. # $self->{WorkQue}= []; $self->refresh(); $self->bind("",[ \&buttonmotion, 1, Ev('x'),Ev('y')]); $self->bind("",[ \&buttonmotion, 2, Ev('x'),Ev('y')]); $self->bind("",[ \&buttonmotion, 3, Ev('x'),Ev('y')]); } } =head2 refresh =for ref refresh() causes a display event to be put at the top of the TriD work que. This should be called at the end of each user defined TriD::Tk callback. =cut sub refresh{ my($self) = @_; return unless defined $self->{GLwin}; # put a redraw command at the top of the work queue my $dcall=ref($self->{GLwin})."::display"; unshift(@{$self->{WorkQue}}, [\&{$dcall},$self->{GLwin}]); } =head2 AUTOLOAD =for ref Trys to find a subroutine in PDL::Graphics::TriD when it is not found in this package. =cut # # This AUTOLOAD allows the PDL::Graphics::TriD::Tk object to act as the PDL::Graphics::TriD # object which it contains. It seems slow and may not be a good idea. # sub AUTOLOAD { my ($self,@args)=@_; use vars qw($AUTOLOAD); my $sub = $AUTOLOAD; # get subroutine name #print "In AutoLoad $self $sub\n"; if(defined($self->{GLwin})){ $sub =~ s/.*:://; return($self->{GLwin}->$sub(@args)); } } =head2 buttonmotion =for ref Default bindings for mousemotion with buttons 1 and 3 =cut sub buttonmotion{ my($self,$but,$x,$y)=@_; $but--; foreach my $vp (@{$self->viewports()}){ # use Data::Dumper; # my $out = Dumper($vp); # print "$out\n"; # exit; next unless $vp->{Active}; next unless defined $vp->{EHandler}{Buttons}[$but]; $vp->{EHandler}{Buttons}[$but]->mouse_moved($vp->{EHandler}{X}, $vp->{EHandler}{Y}, $x,$y); $vp->{EHandler}{X} = $x; $vp->{EHandler}{Y} = $y; } $self->refresh(); } =head1 Author B jedwards@inmet.gov.br =cut 1;