use strict; use warnings; use IUP ':all'; my $mainplot; my $mainfunc; my ($dial1, $dial2); # dials for zooming my ($tgg1, $tgg2); # auto scale on|off toggles my ($tgg3, $tgg4); # grid show|hide toggles my $tgg5; # legend show|hide toggle sub delete_cb { my ($self, $index, $sample_index, $x, $y) = @_; printf STDERR "DELETE_CB(%d, %d, %g, %g)\n", $index, $sample_index, $x, $y; return IUP_DEFAULT; } sub select_cb { my ($self, $index, $sample_index, $x, $y, $select) = @_; printf STDERR "SELECT_CB(%d, %d, %g, %g, %d)\n", $index, $sample_index, $x, $y, $select; return IUP_DEFAULT; } sub edit_cb { # xxxTODO: references # perhaps - return (IUP_DEFAULT, $new_x, $new_y); my ($self, $index, $sample_index, $x, $y, $new_x, $new_y) = @_; printf STDERR "EDIT_CB(%d, %d, %g, %g, %g, %g)\n", $index, $sample_index, $x, $y, $new_x, $new_y; return IUP_DEFAULT; } sub postdraw_cb { my ($self, $cnv) = @_; #my ($ix, $iy) = $self->PlotTransform(0.003, 0.02); #$cnv->cdFont(undef, CD_BOLD, 10); #$cnv->cdTextAlignment(CD_SOUTH); #$cnv->cdText($ix, $iy, "My Inline Legend"); return IUP_DEFAULT; } sub predraw_cb { my ($self, $cnv) = @_; #printf STDERR "PREDRAW_CB()\n"; return IUP_DEFAULT; } sub InitPlot { my $theFac; $mainplot->SetAttribute("TITLE", "Sample Plot"); $mainplot->TITLEFONTSIZE(12); $mainplot->TITLEFONTSTYLE('BOLD'); $mainplot->SetAttribute("MARGINTOP", "40"); $theFac = 100.0/(100*100*100); $mainplot->PlotBegin(0); for (my $theI=-10; $theI<=10; $theI++) { my $x = (0.001*$theI); my $y = (0.01+$theFac*$theI*$theI*$theI); $mainplot->PlotAdd($x, $y); } $mainplot->PlotEnd(); #$mainplot->SetAttribute("DS_COLOR", "100 100 200"); #$mainplot->SetAttribute("DS_EDIT", "YES"); $mainplot->SetCallback("DELETE_CB", \&delete_cb); $mainplot->SetCallback("SELECT_CB", \&select_cb); $mainplot->SetCallback("POSTDRAW_CB", \&postdraw_cb); $mainplot->SetCallback("PREDRAW_CB", \&predraw_cb); $mainplot->SetCallback("EDIT_CB", \&edit_cb); } # show/hide V grid sub tgg3_cb { my ($self, $v) = @_; if ($v) { #checked $mainplot->GRID( ($tgg4->VALUE eq 'ON') ? "YES" : "VERTICAL" ); } else { #unchecked $mainplot->GRID( ($tgg4->VALUE eq 'OFF') ? "NO" : "HORIZONTAL" ); } $mainplot->REDRAW(1); return IUP_DEFAULT; } # show/hide H grid sub tgg4_cb { my ($self, $v) = @_; if ($v) { #checked $mainplot->GRID( ($tgg3->VALUE eq 'ON') ? "YES" : "HORIZONTAL" ); } else { #unchecked $mainplot->GRID( ($tgg3->VALUE eq 'OFF') ? "NO" : "VERTICAL" ); } $mainplot->REDRAW(1); return IUP_DEFAULT; } # show/hide legend sub tgg5_cb { my ($self, $v) = @_; $mainplot->LEGENDSHOW($v ? "YES" : "NO"); $mainplot->REDRAW(1); return IUP_DEFAULT; } # autoscale Y sub tgg1_cb { my ($self, $v) = @_; if ($v) { $dial1->SetAttribute("ACTIVE", "NO"); $mainplot->SetAttribute("AXS_YAUTOMIN", "YES"); $mainplot->SetAttribute("AXS_YAUTOMAX", "YES"); } else { $dial1->SetAttribute("ACTIVE", "YES"); $mainplot->SetAttribute("AXS_YAUTOMIN", "NO"); $mainplot->SetAttribute("AXS_YAUTOMAX", "NO"); } $mainplot->REDRAW(1); return IUP_DEFAULT; } # autoscale X sub tgg2_cb { my ($self, $v) = @_; if ($v) { $dial2->SetAttribute("ACTIVE", "NO"); $mainplot->SetAttribute("AXS_XAUTOMIN", "YES"); $mainplot->SetAttribute("AXS_XAUTOMAX", "YES"); } else { $dial2->SetAttribute("ACTIVE", "YES"); $mainplot->SetAttribute("AXS_XAUTOMIN", "NO"); $mainplot->SetAttribute("AXS_XAUTOMAX", "NO"); } $mainplot->REDRAW(1); return IUP_DEFAULT; } # Y zoom sub dial1_btndown_cb { my ($self, $angle) = @_; warn "***DEBUG*** dial1_btndown_cb: ", $mainplot->GetAttribute("AXS_YMIN"), ":", $mainplot->GetAttribute("AXS_YMAX"), "\n"; $mainplot->SetAttribute("OLD_YMIN", $mainplot->GetAttribute("AXS_YMIN")); $mainplot->SetAttribute("OLD_YMAX", $mainplot->GetAttribute("AXS_YMAX")); return IUP_DEFAULT; } sub dial1_btnup_cb { my ($self, $angle) = @_; my ($x1, $x2, $xm); my $ss; $x1 = $mainplot->GetAttribute("OLD_YMIN"); $x2 = $mainplot->GetAttribute("OLD_YMAX"); $ss = $mainplot->GetAttribute("AXS_YMODE"); if ( $ss && substr($ss,3,1) eq '2' ) { # LOG2: one circle will zoom 2 times $xm = 4.0 * abs($angle) / 3.141592; if ($angle>0.0) { $x2 /= $xm; $x1 *= $xm; } else { $x2 *= $xm; $x1 /= $xm; } } if ( $ss && substr($ss,3,1) eq '1' ) { # LOG10: one circle will zoom 10 times $xm = 10.0 * abs($angle) / 3.141592; if ($angle>0.0) { $x2 /= $xm; $x1 *= $xm; } else { $x2 *= $xm; $x1 /= $xm; } } else { # LIN: one circle will zoom 2 times $xm = ($x1 + $x2) / 2.0; $x1 = $xm - ($xm - $x1)*(1.0-$angle*1.0/3.141592); $x2 = $xm + ($x2 - $xm)*(1.0-$angle*1.0/3.141592); } if ($x1<$x2) { $mainplot->SetAttribute("AXS_YMIN", $x1); $mainplot->SetAttribute("AXS_YMAX", $x2); } $mainplot->REDRAW(1); return IUP_DEFAULT; } # X zoom sub dial2_btndown_cb { my ($self, $angle) = @_; $mainplot->SetAttribute("OLD_XMIN", $mainplot->GetAttribute("AXS_XMIN")); $mainplot->SetAttribute("OLD_XMAX", $mainplot->GetAttribute("AXS_XMAX")); return IUP_DEFAULT; } sub dial2_btnup_cb { my ($self, $angle) = @_; my ($x1, $x2, $xm); $x1 = $mainplot->GetAttribute("OLD_XMIN"); $x2 = $mainplot->GetAttribute("OLD_XMAX"); $xm = ($x1 + $x2) / 2.0; $x1 = $xm - ($xm - $x1)*(1.0-$angle*1.0/3.141592); # one circle will zoom 2 times $x2 = $xm + ($x2 - $xm)*(1.0-$angle*1.0/3.141592); $mainplot->SetAttribute("AXS_XMIN", $x1); $mainplot->SetAttribute("AXS_XMAX", $x2); $mainplot->REDRAW(1); return IUP_DEFAULT; } sub bt1_cb { my $self = shift; my $filename = "testfile"; #BEWARE: no spaces use IUP::Canvas::FileVector; my $cnv1 = IUP::Canvas::FileVector->new(format=>"SVG", filename=>"$filename.svg", width=>300, height=>210, resolution=>4); $mainplot->PlotPaintTo($cnv1); $cnv1->cdKillCanvas(); my $cnv2 = IUP::Canvas::FileVector->new(format=>"EMF", filename=>"$filename.emf", width=>'800', height=>600); $mainplot->PlotPaintTo($cnv2); $cnv2->cdKillCanvas(); IUP->Message("Warning", "Exported to '$filename.emf' + '$filename.svg'!"); return IUP_DEFAULT; } sub bt2_cb { my $self = shift; warn "Auto\n"; $mainplot->SetAttribute("AXS_XAUTOMIN", "YES"); $mainplot->SetAttribute("AXS_XAUTOMAX", "YES"); $mainplot->REDRAW(1); } sub bt3_cb { my $self = shift; warn "Draw '", $mainfunc->VALUE, "'\n"; my @values; my $y; for (my $x=-10; $x<=10; $x+=0.1) { $y = eval $mainfunc->VALUE; if ($@) { my $msg = $@; $msg =~ s/[\r\n]*"/"/g; IUP->Message("ERROR", $msg); last; } push @values, $x, $y; } $mainplot->CLEAR(1); $mainplot->PlotBegin(0); my $index = $mainplot->PlotEnd(); $mainplot->PlotAddPoints($index, \@values); $mainplot->SetAttribute("TITLE", 'func: $y='.$mainfunc->VALUE); $mainplot->SetAttribute("AXS_XAUTOMIN", "YES"); $mainplot->SetAttribute("AXS_XAUTOMAX", "YES"); $mainplot->REDRAW(1); } ### main ### ### left panel: plot control # Y zooming $dial1 = IUP::Dial->new( TYPE=>"VERTICAL", ACTIVE=>"NO", SIZE=>"20x52", BUTTON_PRESS_CB =>\&dial1_btndown_cb, MOUSEMOVE_CB =>\&dial1_btnup_cb, BUTTON_RELEASE_CB=>\&dial1_btnup_cb ); $tgg1 = IUP::Toggle->new( TITLE=>"Y Autoscale", ACTION=>\&tgg1_cb, VALUE=>"ON" ); my $boxinfo = IUP::Vbox->new( child=>[ IUP::Label->new( TITLE=>"-", EXPAND=>"NO" ), IUP::Fill->new(), IUP::Label->new( TITLE=>"+", EXPAND=>"NO" ) ], ALIGNMENT=>"ACENTER", SIZE=>"20x52", GAP=>"2", MARGIN=>"4", EXPAND=>"YES" ); my $boxdial1 = IUP::Hbox->new( child=>[$boxinfo, $dial1], ALIGNMENT=>"ACENTER" ); my $f1 = IUP::Frame->new( child=>IUP::Vbox->new( child=>[$boxdial1, $tgg1] ), TITLE=>"Y Zoom" ); # X zooming $dial2 = IUP::Dial->new( TYPE=>"HORIZONTAL", ACTIVE=>"NO", SIZE=>"64x16", BUTTON_PRESS_CB =>\&dial2_btndown_cb, MOUSEMOVE_CB =>\&dial2_btnup_cb, BUTTON_RELEASE_CB=>\&dial2_btnup_cb ); $tgg2 = IUP::Toggle->new( TITLE=>"X Autoscale", ACTION=>\&tgg2_cb, VALUE=>"ON" ); my $boxinfoxxx = IUP::Hbox->new( child=>[ IUP::Label->new( TITLE=>"-", EXPAND=>"NO" ), IUP::Fill->new(), IUP::Label->new( TITLE=>"+", EXPAND=>"NO" ) ], ALIGNMENT=>"ACENTER", SIZE=>"64x16", GAP=>"2", MARGIN=>"4", EXPAND=>"HORIZONTAL" ); my $boxdial2 = IUP::Vbox->new( child=>[$dial2, $boxinfoxxx], ALIGNMENT=>"ACENTER" ); my $f2 = IUP::Frame->new( child=>IUP::Vbox->new( child=>[$boxdial2, $tgg2] ), TITLE=>"X Zoom" ); # checkboxes + buttons $tgg3 = IUP::Toggle->new( TITLE=>"Vertical Grid", ACTION=>\&tgg3_cb ); $tgg4 = IUP::Toggle->new( TITLE=>"Horizontal Grid", ACTION=>\&tgg4_cb ); $tgg5 = IUP::Toggle->new( TITLE=>"Legend", ACTION=>\&tgg5_cb ); my $lbl1 = IUP::Label->new( TITLE=>"", SEPARATOR=>"HORIZONTAL" ); my $lbl2 = IUP::Label->new( TITLE=>"", SEPARATOR=>"HORIZONTAL" ); my $lbl3 = IUP::Label->new( TITLE=>"", SEPARATOR=>"HORIZONTAL" ); my $bt1 = IUP::Button->new( TITLE=>"Export EMF", ACTION=>\&bt1_cb ); my $bt2 = IUP::Button->new( TITLE=>"Autofocus", ACTION=>\&bt2_cb ); my $vboxl = IUP::Vbox->new( child=>[$f1, $f2, $lbl1, $tgg3, $tgg4, $lbl2, $tgg5, $lbl3, $bt1, $bt2], GAP=>"4", EXPAND=>"NO" ); ### right panel: plot control $mainplot = IUP::PPlot->new(); $mainfunc = IUP::Text->new( VALUE=>'sin($x)', VISIBLECOLUMNS=>50, VISIBLELINES=>3, MULTILINE=>'YES', EXPAND=>'YES'); ### the main dialog my $hbox1 = IUP::Hbox->new( child=>[$vboxl, $mainplot], MARGIN=>"4x4", GAP=>"10" ); my $hbox2 = IUP::Hbox->new( child=>[ IUP::Label->new( TITLE=>'$y =' ), $mainfunc, IUP::Button->new( TITLE=>"Draw", ACTION=>\&bt3_cb ), ], MARGIN=>"4x4", GAP=>"2" ); my $dlg = IUP::Dialog->new( child=>IUP::Vbox->new([$hbox1, $hbox2]), SIZE=>"500x300", TITLE=>"IupPlot Example" ); InitPlot(); # It must be able to be done independent of dialog Mapping $dlg->ShowXY(IUP_CENTER, IUP_CENTER); $dlg->SetAttribute("SIZE", undef); # autofit trick ### the main loop IUP->MainLoop;