App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Gtk2/Ex/LineClipper.pm view on Meta::CPAN
=head1 SYNOPSIS
use App::Chart::Gtk2::Ex::LineClipper;
# direct draw
App::Chart::Gtk2::Ex::LineClipper::clipped_draw_lines
($drawable, $gc, $line_width, $points_list);
# OOP accumulator
my $linedrawer = App::Chart::Gtk2::Ex::LineClipper->new (drawable => $drawable);
$linedrawer->add ($gc, $x1, $y1);
$linedrawer->add ($gc, $x2, $y2);
$linedrawer->end;
=head1 DESCRIPTION
C<App::Chart::Gtk2::Ex::LineClipper> helps you draw connected line segments like
C<< Gtk2::Drawable->draw_lines >> does, but with benefits of clipping wild
coordinates (and not even sent to the server if not visible), and an
accumulator mechanism to build line sequences.
Clipping wild X,Y values on the client side is important because Gdk
silently takes just the low 16 bits of each. For example if you draw a line
from 100,50 to 65736,50 you'll be unpleasantly surprised to find X=65736
comes out as X=200 (its low 16 bits), instead of extending to the far right
hand end of the window.
The object-oriented accumulator is helpful if you've got a tricky loop
generating points and colours for each segment and want someone else to keep
track of what, if anything, you build up to draw.
=head1 DIRECT DRAWING
=over 4
=item C<< App::Chart::Gtk2::Ex::LineClipper::clipped_draw_lines ($drawable, $gc, $line_width, $points) >>
Draw lines connecting the X,Y points in C<$points>, like
C<Gtk2::Drawable::draw_lines> does, but clipping to the size of the drawable
so huge coordinate values don't wrap around, and indeed are not sent to the
server at all if completely off-screen.
C<$points> is a reference to an array of X,Y values, one after the other.
C<$drawable> is a C<Gtk2::Gdk::Drawable> (window, pixmap, etc) and C<$gc> is
a C<Gtk2::Gdk::GC>. Eg.
App::Chart::Gtk2::Ex::LineClipper::clipped_draw_lines
($drawable, $gc, 1, [ 100,100, 200,200, 300,100 ]);
C<$line_width> should be the width in pixels of the lines C<$gc> will draw.
This is used to know how far off the drawable the clipping must extend so
the C<cap_style> doesn't show. C<clipped_draw_lines> doesn't simply read
C<$line_width> from C<< $gc->get_values >> because that call does a
round-trip to the X server. A width bigger than actually in use is fine;
for instance you might just pass 20 pixels if you know you never draw lines
wider than that. A width 0 is interpreted as a 1 pixel "thin line", the
same as happens in the GC.
If C<$points> is an empty array, or an array of just one X,Y point, then
nothing at all is drawn. This handling of one point adds certainty to what
plain C<< $win->draw_lines >> does; for it a single X,Y of a 0-width "thin
line" might or might not be drawn, depending on the server.
=back
=head1 ACCUMULATOR OBJECT
=over 4
=item C<< App::Chart::Gtk2::Ex::LineClipper->new (drawable => $drawable, ...) >>
Create and return a new LineClipper object to accumulate and draw connected
line segments on C<$drawable> using C<clipped_draw_lines> above.
C<$drawable> is a C<Gtk2::Gdk::Drawable> object as above, and a
C<line_width> parameter can be passed to set that for the clipping (again as
above).
my $linedrawer = App::Chart::Gtk2::Ex::LineClipper->new
(drawable => $drawable,
line_width => 5); # pixels
By default a single solitary X,Y point is not drawn, on the principle that
it's not a line segment, but the C<draw_point> option can be set true to
have it shown as a circle of the given C<line_width>. Eg.
my $linedrawer = App::Chart::Gtk2::Ex::LineClipper->new
(drawable => $drawable,
line_width => 5, # pixels
draw_point => 1); # true
If you're wondering that C<line_width> used as a diameter won't come out
circular if the pixels aren't square, well, yes, but the same is true of the
line drawing. The single width used vertically and horizontally for the
line segments makes them appear wider or narrower according to their angle.
=item C<< $linedrawer->add ($gc, $x, $y) >>
Add a point to C<$linedrawer>. The points accumulated will have connected line
segments drawn from each to the next, in the order they're added.
C<$gc> is a C<Gtk2::Gdk::GC> for the new segment, ie. from the current
endpoint to the new C<$x>,C<$y>. Different GCs can be used for different
segments and the LineClipper takes care of passing runs of the same GC to
C<clipped_draw_lines>.
=item C<< $linedrawer->end() >>
Draw the line segments accumulated, if any, and set C<$linedrawer> back to
empty, ready to start a new completely separate sequence of points.
You can use this to force a gap between points, ie. draw everything
accumulated so far and make subsequent points a new run.
C<end> is called automatically when C<$linedrawer> is destroyed, which means
that if you've got a complicated loop generating the points then you can
just C<return> or jump out from multiple places, confident that letting the
LineClipper go out of scope will flush what you've accumulated.
=back
( run in 0.816 second using v1.01-cache-2.11-cpan-e1769b4cff6 )