PDL-Graphics-Prima
view release on metacpan or search on metacpan
lib/PDL/Graphics/Prima.pm view on Meta::CPAN
# PDL
use PDL::Lite;
use PDL::NiceSlice;
use PDL::Drawing::Prima;
# library-specific modules whose functionality I need
use PDL::Graphics::Prima::Axis;
use PDL::Graphics::Prima::DataSet;
# Next: use block-comments to describe the purpose of each method.
######################################
# Usage : ????
# Purpose : ????
# Arguments : ????
# Returns : ????
# Side Effects : none
# Throws : no exceptions
# Comments : none
# See Also : n/a
######################################
# Usage : Not used directly; this is invoked by Prima's inherited
# : constructor.
# Purpose : Sets up a default profile for a graph widget
# Arguments : The (completely uninitialized) object
# Returns : a hashref
# Side Effects : none
# Throws : never
# Comments : none
# See Also : init
sub profile_default {
my %def = %{$_[ 0]-> SUPER::profile_default};
return {
%def,
# default properties follow
# Title basics
title => '',
titleSpace => '1line',
titleFont => { height => '10%height' },
backColor => cl::White,
# default color map
color_map => pal::BlackToWhite,
# replot duration in milliseconds
replotDuration => 30,
# Blank profiles for the axes:
x => {},
y => {},
# Other important and basic settings
selectable => 1,
buffered => 1,
popupItems => default_popup_items(),
};
}
sub default_popup_items
{[
['~Copy' => 'copy_to_clipboard' ],
['P~rint' => 'print' ],
['~Export to' => [
[ '~Image' => 'save_to_image' ],
[ '~Postscript' => 'save_to_ps' ],
[ '~EPS' => 'save_to_eps' ],
[ 'P~DF' => 'save_to_pdf' ],
]],
['~Autoscale' => 'autoscale' ],
['~Properties' => 'set_properties_dialog' ]
]}
######################################
# Usage : Not used directly; this is invoked by Prima's inherited
# : constructor.
# Purpose : Initializes self's data from the profile.
# Arguments : $self, as yet uninitialized
# : a list of key => value pairs corresponding to the list of
# : arguments provided to the constructor, merged with the default
# : profile.
# Returns : A list of key => value pairs suitable for a profile hash.
# Side Effects : none
# Throws : if unable to initialize the x/y axes from their associated
# : constructor hashrefs
# Comments : This has a lot of logic for setting defaults. It might not be
# : a bad idea to refactor some of this out, so that a Plot widget
# : can be reset to a default state.
# See Also : profile_default
sub init {
my $self = shift;
my %profile = $self->SUPER::init(@_);
# Set the title properties
$self->_title($profile{title});
$self->_titleSpace($profile{titleSpace});
$self->_titleFont(%{$profile{titleFont}});
# Set the default save-as data
$self->default_save_dir($profile{default_save_dir});
$self->default_save_format($profile{default_save_format});
# Create the x- and y-axis objects, overriding the owner and axis name
# properties if they are set in the profile.
for ('x', 'y') {
if (eval{$profile{$_}->isa('PDL::Graphics::Prima::Axis')}) {
$self->{$_} = $profile{$_};
$self->{$_}->owner($self);
$self->{$_}->name($_);
}
elsif (ref ($profile{$_}) eq 'HASH') {
$self->{$_} = PDL::Graphics::Prima::Axis->create(
%{$profile{$_}}
, owner => $self
, name => $_
);
}
elsif (not ref($profile{$_})) {
lib/PDL/Graphics/Prima.pm view on Meta::CPAN
my $new_max = $self->x->relatives_to_reals(1 - $dx);
$self->x->minmax($new_min, $new_max);
}
# If the initial click was within the y-boundaries, then the y-values
# should be adjusted:
if ($y_down_rel > 0 and $y_down_rel < 1) {
# Determine the relative change and the adjusted min/max:
my $dy = $y_stop_rel - $y_start_rel;
my $new_min = $self->y->relatives_to_reals(-$dy);
my $new_max = $self->y->relatives_to_reals(1 - $dy);
$self->y->minmax($new_min, $new_max);
}
}
# Repaint if they're dragging the mouse
$self->notify('Replot') if $drag_button;
# Store the intermediate locations:
$self->{mouse_move_rel} = [$x_stop_rel, $y_stop_rel];
}
sub on_mouseup {
return unless $_[0]->enabled;
my ($self, $up_button, $up_mods, $x_stop_pixel, $y_stop_pixel) = @_;
# Remove the previous button record for left and middle buttons:
if ($up_button & mb::Left) {
delete $self->{mouse_down_rel}->{mb::Left};
}
elsif ($up_button & mb::Middle) {
delete $self->{mouse_down_rel}->{mb::Middle};
}
elsif ($up_button & mb::Right and defined $self->{mouse_down_rel}->{mb::Right}) {
# Zoom in to the requested rectangle:
my ($x_start_rel, $y_start_rel) = @{$self->{mouse_down_rel}->{mb::Right}};
my $x_stop_rel = $self->x->pixels_to_relatives($x_stop_pixel);
my $y_stop_rel = $self->y->pixels_to_relatives($y_stop_pixel);
# Only rescale if there is a legitimate x- and y- box:
if ($x_stop_rel != $x_start_rel and $y_stop_rel != $y_start_rel) {
# Reset the x min/max
my ($min_rel, $max_rel) = get_min_max_for($x_start_rel, $x_stop_rel);
# Compute the new min/max values from the axis scaling:
my $min_real = $self->x->relatives_to_reals($min_rel);
my $max_real = $self->x->relatives_to_reals($max_rel);
# Set the new min/max values:
$self->x->minmax($min_real, $max_real);
# Reset the y min/max
($min_rel, $max_rel) = get_min_max_for($y_start_rel, $y_stop_rel);
# Compute the new min/max values from the axis scaling:
$min_real = $self->y->relatives_to_reals($min_rel);
$max_real = $self->y->relatives_to_reals($max_rel);
# Set the new min/max values:
$self->y->minmax($min_real, $max_real);
$self->clear_event;
}
elsif ($x_stop_rel == $x_start_rel and $y_stop_rel == $y_start_rel) {
# Call the popup menu if it 'looks' like a right-click
# by not clearing the event
} else {
$self->clear_event;
}
# Remove the previous button record, so a zoom rectangle is not drawn:
delete $self->{mouse_down_rel}->{mb::Right};
}
}
sub autoscale
{
my $self = shift;
$self->x->minmax(lm::Auto, lm::Auto);
$self->y->minmax(lm::Auto, lm::Auto);
}
use Scalar::Util qw(looks_like_number);
sub insert_minmax_input {
my ($group_box, $method, $axis, $y_pos) = @_;
$group_box->insert(Label =>
place => { x => 45, y => $y_pos, height => 25, width => 60, anchor => 'sw', pad => 10 },
height => 30,
text => ucfirst($method) . ':',
);
# the widgets we are about to add
my ($auto_button, $inline);
# lexical state variable to bypass updates if the input line triggered
# the update
my $update_inline = 1;
# initial value and autoscaling state of the axis
my ($init_val, $is_auto) = $axis->$method;
# Attach an event listener to the axis min/max methods to keep is_auto
# up-to-date, and ensure that the input line is accurate
$axis->add_notification(ChangeBounds => sub {
# get the new min or max
(my $curr_val, $is_auto) = $axis->$method;
$inline->text($curr_val . ($is_auto ? ' (Auto)' : ''))
if $update_inline;
$auto_button->enabled(!$is_auto);
});
no PDL::NiceSlice;
my $val_is_good = $method eq 'min' ? sub { $_[0] < $axis->max }
: sub { $_[0] > $axis->min };
$inline = $group_box->insert(InputLine =>
place => { x => 110, y => $y_pos, height => 30, width => 280, anchor => 'sw' },
height => 30,
text => ($is_auto ? "$init_val (Auto)" : $init_val),
backColor => cl::White,
onEnter => sub {
if ($is_auto) {
$_[0]->text(scalar($axis->$method));
}
},
onLeave => sub {
if ($is_auto) {
my $value = $axis->$method;
( run in 1.428 second using v1.01-cache-2.11-cpan-364913b4093 )