App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Gtk2/View.pm view on Meta::CPAN
],
},
],
};
sub viewstyle_read {
require App::Chart::DBI;
my $str = App::Chart::DBI->read_single
('SELECT value FROM preference WHERE key=\'viewstyle\'');
if (! defined $str) { return DEFAULT_VIEWSTYLE; }
my $viewstyle = eval $str;
if (! defined $viewstyle) {
print "chart: oops, bad viewstyle in database, using default: $@";
return DEFAULT_VIEWSTYLE;
}
return $viewstyle;
}
# viewstyle_write(DEFAULT_VIEWSTYLE);
# print viewstyle_read(DEFAULT_VIEWSTYLE);
# exit 0;
sub viewstyle_write {
my ($viewstyle) = @_;
require App::Chart::DBI;
require Data::Dumper;
my $str = Data::Dumper->new([$viewstyle],['viewstyle'])->Indent(1)->Terse(1)->Sortkeys(1)->Dump;
require App::Chart::DBI;
my $dbh = App::Chart::DBI->instance;
$dbh->do ('INSERT OR REPLACE INTO preference (key, value)
VALUES (\'viewstyle\',?)', {}, $str);
App::Chart::chart_dirbroadcast()->send ('viewstyle-changed');
}
#------------------------------------------------------------------------------
sub INIT_INSTANCE {
my ($self) = @_;
$self->{'symbol'} = ''; # per property default above
$self->{'series_list'} = [];
$self->{'timebase_class'} = DEFAULT_TIMEBASE_CLASS;
$self->{'graphs'} = [];
$self->set(n_rows => 9,
n_columns => 3);
App::Chart::chart_dirbroadcast()->connect_for_object
('data-changed', \&_do_data_changed, $self);
# FIXME: this induces a rescale at a good time, but otherwise not wanted
App::Chart::chart_dirbroadcast()->connect_for_object
('latest-changed', \&_do_data_changed, $self);
App::Chart::Gtk2::GUI::chart_style_widget ('AppChartViewLabel');
my $ebox = $self->{'initial'} = Gtk2::EventBox->new;
$ebox->set_name ('AppChartViewLabel');
my $label = Gtk2::Label->new
(__('Use File/Open to open or add a symbol'));
$label->set_name ('AppChartViewLabel');
$ebox->add ($label);
$ebox->show_all;
$self->attach ($ebox, 0,3, 0,9,
['fill','shrink','expand'],
['fill','shrink','expand'], 0,0);
}
sub GET_PROPERTY {
my ($self, $pspec) = @_;
my $pname = $pspec->get_name;
if ($pname eq 'viewstyle') {
if (! $self->{'init_graphs'}) {
return viewstyle_read();
}
}
return $self->{$pname};
}
sub SET_PROPERTY {
my ($self, $pspec, $newval) = @_;
my $pname = $pspec->get_name;
my $oldval = $self->{$pname};
### View SET_PROPERTY: $pname
### $newval
if ($pname eq 'symbol') {
$self->set_symbol ($newval);
return;
}
$self->{$pname} = $newval; # per default GET_PROPERTY
if ($pname eq 'timebase_class') {
if ($oldval ne $newval) {
$self->set_symbol ($self->get('symbol'));
}
} elsif ($pname eq 'statusbar') {
# lose old id
delete $self->{'crosshair_status_id'};
} elsif ($pname eq 'viewstyle') {
if ($self->{'init_graphs'}) {
_update_attach ($self);
}
if ($self->{'symbol'}) {
_set_symbol ($self, $self->{'symbol'});
}
}
}
#------------------------------------------------------------------------------
# Crosshair
sub crosshair {
my ($self) = @_;
return ($self->{'crosshair_object'}
||= do {
_init_graphs ($self);
require Gtk2::Ex::CrossHair;
my $ch = Gtk2::Ex::CrossHair->new (widgets => $self->{'graphs'},
foreground => 'orange');
$ch->signal_connect (moved => \&_do_crosshair_moved,
App::Chart::Glib::Ex::MoreUtils::ref_weak($self));
### View created crosshair: "$ch"
lib/App/Chart/Gtk2/View.pm view on Meta::CPAN
$self->{'init_graphs'} = 1;
$self->{'viewstyle'} = viewstyle_read();
require App::Chart::Gtk2::Graph;
require App::Chart::Gtk2::HAxis;
App::Chart::Gtk2::GUI::chart_style_class ('Gtk2::Ex::NumAxis');
require App::Chart::Gtk2::Heading;
$self->{'heading'} = App::Chart::Gtk2::Heading->new;
# initial horiz scale 4 pixels per date
require App::Chart::Gtk2::HScale;
my $hadj = $self->{'hadjustment'}
= App::Chart::Gtk2::HScale->new (pixel_per_value => 4);
$self->{'haxis'} = App::Chart::Gtk2::HAxis->new (adjustment => $hadj);
$self->{'hscroll'} = Gtk2::HScrollbar->new ($hadj);
_update_attach ($self);
$self->show_all;
# # this is a nasty hack to force the Gtk2::Table to set its childrens'
# # sizes now, instead of later under the queue_resize or whatever
# $self->size_allocate ($self->allocation);
if (my $ebox = delete $self->{'initial'}) {
$self->remove ($ebox);
}
}
# 0 1 2 3
# 0 +--------------+--+--+
# | heading |
# 1 +--------------+--+--+
# | |v |v |
# | upper |a |s |
# | |x |c |
# | |i |r |
# | |s |o |
# | | |l |
# | | |l |
# 5 +--------------+--+--+
# | gap |
# 6 +--------------+--+--+
# | |v |v |
# | lower |a |s |
# | |x |b |
# 7 +--------------+--+--+
# | haxis | |
# 8 +--------------+ |
# | hscroll | |
# 9 +--------------+--+--+
#
sub _update_attach {
my ($self) = @_;
require Gtk2::Ex::TableBits;
my $y = 0;
Gtk2::Ex::TableBits::update_attach
($self, $self->{'heading'}, 0,3, $y,$y+1,
['fill','shrink','expand'], [], 0,0);
$y++;
my $graphs = $self->{'graphs'};
my @graphstyles = @{$self->{'viewstyle'}->{'graphs'}};
while ($#$graphs > max (0, $#graphstyles)) {
my $graph = pop @$graphs;
$self->remove ($graph);
$self->remove ($graph->{'noshrink'});
$self->remove ($graph->{'vscroll'});
}
$graphs->[0] ||= do {
my $upper = _make_graph($self);
delete $upper->{'heading_in_graph'};
$self->{'hadjustment'}->set (widget => $upper);
Glib::Ex::ConnectProperties->new ([$upper,'series-list'],
[$self->{'heading'},'series-list']);
$upper;
};
for (my $i = 0; $i < @graphstyles; $i++) {
my $graph = ($graphs->[$i] ||= _make_graph($self));
### now graphs: "@$graphs"
if ($i > 0) {
my $gap = ($graph->{'gap'} ||= Glib::Object::new ('Gtk2::DrawingArea',
height_request => 2));
Gtk2::Ex::TableBits::update_attach
($self, $gap, 0,3, $y,$y+1,
[], [], 0,0);
$y++;
}
my $graphstyle = $graphstyles[$i];
my $size = $graphstyle->{'size'};
Gtk2::Ex::TableBits::update_attach
($self, $graph, 0,1, $y,$y+$size,
['fill','shrink','expand'],
['fill','shrink','expand'], 0,0);
Gtk2::Ex::TableBits::update_attach
($self, $graph->{'noshrink'},
1,2, $y,$y+$size,
['fill','shrink'],
['fill','shrink','expand'], 0,0);
Gtk2::Ex::TableBits::update_attach
($self, $graph->{'vscroll'},
2,3, $y,$y+$size,
['fill','shrink'],
['fill','shrink','expand'], 0,0);
$y += $size;
}
Gtk2::Ex::TableBits::update_attach
($self, $self->{'haxis'}, 0,1, $y,$y+1,
['fill','shrink','expand'],
['fill','shrink'], 0,0);
$y++;
Gtk2::Ex::TableBits::update_attach
($self, $self->{'hscroll'}, 0,1, $y,$y+1,
['fill','shrink','expand'],
['fill','shrink'], 0,0);
$y++;
if (my $cross = $self->{'crosshair_object'}) {
### _update_attach() cross widgets: "@$graphs"
$cross->set (widgets => $graphs);
}
$self->resize (3, $y);
}
sub _make_graph {
my ($self) = @_;
require App::Chart::Gtk2::Graph;
require App::Chart::Gtk2::AdjScale;
my $vadj = App::Chart::Gtk2::AdjScale->new (orientation => 'vertical',
inverted => 1);
my $graph = App::Chart::Gtk2::Graph->new (hadjustment => $self->{'hadjustment'},
vadjustment => $vadj);
$graph->{'heading_in_graph'} = 1;
$vadj->set (widget => $graph);
$graph->signal_connect (button_press_event => \&_do_graph_button_press);
require Gtk2::Ex::NumAxis;
my $vaxis = $graph->{'vaxis'}
= Gtk2::Ex::NumAxis->new (adjustment => $vadj,
inverted => 1);
$vaxis->signal_connect (number_to_text => \&_vaxis_number_to_text);
require Gtk2::Ex::NoShrink;
$graph->{'noshrink'} = Gtk2::Ex::NoShrink->new (child => $vaxis);
my $vscroll = $graph->{'vscroll'} = Gtk2::VScrollbar->new ($vadj);
$vscroll->set_inverted (1);
$vaxis->add_events (['button-press-mask',
'button-motion-mask',
'button-release-mask']);
$vaxis->signal_connect (button_press_event => \&_do_vaxis_button_press);
$graph->show_all;
return $graph;
}
sub _vaxis_number_to_text {
my ($axis, $number, $decimals) = @_;
return App::Chart::number_formatter()->format_number ($number, $decimals, 1);
}
sub _do_vaxis_button_press {
my ($vaxis, $event) = @_;
if ($event->button == 1) {
require Gtk2::Ex::Dragger;
my $dragger = ($vaxis->{'dragger'} ||=
Gtk2::Ex::Dragger->new
(widget => $vaxis,
vadjustment => $vaxis->get('adjustment'),
vinverted => 1,
cursor => 'sb-v-double-arrow',
confine => 1));
( run in 0.478 second using v1.01-cache-2.11-cpan-5623c5533a1 )