package CanvasBezierCurve;
#
# canvas-curve.c: bezier curve demo.
#
# Copyright (C) 2002 Mark McLoughlin
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
# Authors:
# Mark McLoughlin <mark@skynet.ie>
# muppet <scott at asofyet dot org> (gtk2-perl port)
#
# FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
#
# there's a nasty workaround in here.
#
# you can't set or get the bpath property of the GnomeCanvasBpath via
# Glib::Object->get or Glib::Object->set (of course, that includes
# Gnome::Canvas::Item->new) -- you have to use $bpath->set_path_def and
# $bpath->get_path_def.
#
# the problem is that the bpath property of of GnomeCanvasBpath is defined as a
# G_TYPE_POINTER, rather than a G_TYPE_BOXED as it should be. we can't register
# copy/free/whatever functions for pointer values, so we can't use any of our
# way-cool Glib binding tools. thus, until libgnomecanvas fixes this bug,
# we have to work around at this level.
#
# FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
use strict;
use Carp;
use Glib qw(TRUE FALSE);
use Gnome2::Canvas;
use constant STATE_INIT => 0;
use constant STATE_FIRST_PRESS => 1;
use constant STATE_FIRST_RELEASE => 2;
use constant STATE_SECOND_PRESS => 3;
my $current_state = STATE_INIT;
my $current_item;
my @current_points = ();
sub draw_curve {
my ($item, $x, $y) = @_;
my $root = $item->parent;
if ($current_state == STATE_INIT) {
$current_points[0] = $x;
$current_points[1] = $y;
} elsif ($current_state == STATE_FIRST_PRESS) {
$current_points[2] = $x;
$current_points[3] = $y;
my $path_def = Gnome2::Canvas::PathDef->new;
$path_def->moveto ($current_points[0], $current_points[1]);
$path_def->lineto ($current_points[2], $current_points[3]);
if ($current_item) {
##$current_item->set (bpath => $path_def);
$current_item->set_path_def ($path_def);
} else {
$current_item = Gnome2::Canvas::Item->new (
$root,
'Gnome2::Canvas::Bpath',
### can't do this here, see below
### bpath => $path_def,
outline_color => 'blue',
width_pixels => 5,
cap_style => 'round');
# hack, see above
$current_item->set_path_def ($path_def);
$current_item->signal_connect (event => \&item_event);
}
} elsif ($current_state == STATE_FIRST_RELEASE) {
$current_points[4] = $x;
$current_points[5] = $y;
my $path_def = Gnome2::Canvas::PathDef->new;
$path_def->moveto ($current_points[0], $current_points[1]);
$path_def->curveto ($current_points[4], $current_points[5],
$current_points[4], $current_points[5],
$current_points[2], $current_points[3]);
###$current_item->set (bpath => $path_def);
$current_item->set_path_def ($path_def);
} elsif ($current_state == STATE_SECOND_PRESS) {
$current_points[6] = $x;
$current_points[7] = $y;
my $path_def = Gnome2::Canvas::PathDef->new;
$path_def->moveto ($current_points[0], $current_points[1]);
$path_def->curveto ($current_points[4], $current_points[5],
$current_points[6], $current_points[7],
$current_points[2], $current_points[3]);
####$current_item->set (bpath => $path_def);
$current_item->set_path_def ($path_def);
$current_item = undef;
} else {
croak "not reached";
}
}
sub item_event {
my ($item, $event) = @_;
if ($event->type eq 'button-press' &&
$event->button == 1 &&
$event->state >= 'shift-mask') {
if ($item == $current_item) {
$current_item = undef;
$current_state = STATE_INIT;
}
$item->destroy;
$item = undef;
return TRUE;
}
return FALSE;
}
sub canvas_event {
my ($item, $event) = @_;
if ($event->type eq 'button-press') {
return FALSE if $event->button != 1;
if ($current_state == STATE_INIT) {
draw_curve ($item, $event->x, $event->y);
$current_state = STATE_FIRST_PRESS;
} elsif ($current_state == STATE_FIRST_RELEASE) {
draw_curve ($item, $event->x, $event->y);
$current_state = STATE_SECOND_PRESS;
} elsif ($current_state == STATE_SECOND_PRESS) {
draw_curve ($item, $event->x, $event->y);
$current_state = STATE_INIT;
} else {
croak "shouldn't have reached here $current_state";
}
} elsif ($event->type eq 'button-release') {
return FALSE if $event->button != 1;
if ($current_state == STATE_FIRST_PRESS) {
draw_curve ($item, $event->x, $event->y);
$current_state = STATE_FIRST_RELEASE;
} else {
}
} elsif ($event->type eq 'motion-notify') {
if ($current_state == STATE_FIRST_PRESS) {
draw_curve ($item, $event->x, $event->y);
}
}
return FALSE;
}
sub create_canvas {
my $aa = shift;
# gtk_widget_push_colormap (gdk_rgb_get_cmap ());
my $canvas = $aa
? Gnome2::Canvas->new_aa
: Gnome2::Canvas->new;
$canvas->set_size_request (600, 250);
$canvas->set_scroll_region (0, 0, 600, 250);
$canvas->show;
my $root = $canvas->root;
my $item = Gnome2::Canvas::Item->new ($root,
'Gnome2::Canvas::Rect',
outline_color => 'black',
fill_color => 'white',
x1 => 0.0,
y1 => 0.0,
x2 => 600.0,
y2 => 250.0);
Gnome2::Canvas::Item->new ($root,
'Gnome2::Canvas::Text',
text => ($aa ? "AntiAlias" : "Non-AntiAlias"),
x => 270.0,
y => 5.0,
font => 'Sans 12',
anchor => 'n',
fill_color => 'black');
# gtk_widget_pop_colormap ();
$item->signal_connect (event => \&canvas_event);
my $frame = Gtk2::Frame->new;
$frame->set_shadow_type ('in');
$frame->add ($canvas);
return $frame;
}
sub create {
my $vbox = Gtk2::VBox->new (FALSE, 4);
$vbox->set_border_width (4);
$vbox->show;
my $label = Gtk2::Label->new ("Drag a line with button 1. Then mark 2 control points wth\n"
."button 1. Shift+click with button 1 to destroy the curve.\n");
$vbox->pack_start ($label, FALSE, FALSE, 0);
$label->show;
my $canvas = create_canvas (FALSE);
$vbox->pack_start ($canvas, TRUE, TRUE, 0);
$canvas->show;
my $aa_canvas = create_canvas (TRUE);
$vbox->pack_start ($aa_canvas, TRUE, TRUE, 0);
$aa_canvas->show;
return $vbox;
}
1;