# The GIMP -- an image manipulation program
# Copyright (C) 1995 Spencer Kimball and Peter Mattis

# 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 of the License, 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.

# "Perlized" from C source by Andy Thomas <alt@gimp.org>

sub pdb_misc {
    $author = $copyright = 'Andy Thomas';
    $date = '1999';
}

# The defs

sub path_list {
    $blurb = 'List the paths associated with the passed image.';

    $help = <<'HELP';
List the paths associated with the passed image.
HELP

    &pdb_misc;

    @inargs = ( &std_image_arg );
    $inargs[0]->{desc} = 'The ID of the image to list the paths from';

    @outargs = (
	{ name => 'path_list', type => 'stringarray', init => 1,
	  desc => 'List of the paths belonging to this image',
	  array => { name => 'num_paths', init => 1,
		     desc => 'The number of paths returned' } }
    );

    %invoke = (
	code => <<'CODE'
{
  num_paths = gimp_container_num_children (gimage->vectors);

  if (num_paths > 0)
    {
      gint   count = 0;
      GList *list;

      path_list = g_new (gchar *, num_paths);

      for (list = GIMP_LIST (gimage->vectors)->list;
           list;
           list = g_list_next (list))
        {
	  path_list[count++] =
            g_strdup (gimp_object_get_name (GIMP_OBJECT (list->data)));
        }
    }
}
CODE
    );
}

sub path_get_points {
    $blurb = 'List the points associated with the named path.';

    $help = <<'HELP';
List the points associated with the named path.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'pathname', type => 'string',
	  desc => 'the name of the path whose points should be listed',
	  alias => 'pname' }
    );
    $inargs[0]->{desc} = 'The ID of the image to list the paths from';

    @outargs = (
	{ name => 'path_type', type => 'int32', init => 1,
	  desc => 'The type of the path. Currently only one type (1 = Bezier)
		   is supported' },
	{ name => 'path_closed', type => 'int32', init => 1,
	  desc => 'Return if the path is closed. (0 = path open, 1 = path
		   closed)' },
	{ name => 'points_pairs', type => 'floatarray',
	  desc => 'The points in the path represented as 3 floats. The first is
		   the x pos, next is the y pos, last is the type of the pnt.
		   The type field is dependant on the path type. For beziers
		   (type 1 paths) the type can either be (1.0 = BEZIER_ANCHOR,
		   2.0 = BEZIER_CONTROL). Note all points are returned in pixel
		   resolution',
	  init => 1,
	  array => { name => 'num_path_point_details',
		     desc => 'The number of points returned. Each point is
			      made up of (x, y, pnt_type) of floats',
		     alias => 'num_points', init => 1 } }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = gimp_image_get_active_vectors (gimage);

  if (vectors)
    {
      GimpVectorsCompatPoint *points;

      path_type = 1; /* BEZIER (1.2 compat) */

      points = gimp_vectors_compat_get_points (vectors, &num_points,
                                               &path_closed);

      if (points)
        {
          gdouble *curr_point;
          gint     i;

          points_pairs = g_new0 (gdouble, num_points * 3);

          for (i = 0, curr_point = points_pairs;
               i < num_points;
               i++, curr_point += 3)
            {
              curr_point[0] = points[i].x;
              curr_point[1] = points[i].y;
              curr_point[2] = points[i].type;
            }

          g_free (points);
        }
      else
        success = FALSE;
    }
  else
    success = FALSE;
}
CODE
    );
}

sub path_get_current {
    $blurb = 'The name of the current path. Error if no paths.';

    $help = <<'HELP';
The name of the current path. Error if no paths.
HELP

    &pdb_misc;

    @inargs = ( &std_image_arg );
    $inargs[0]->{desc} = 'The ID of the image to get the current paths from';

    @outargs = (
	{ name => 'current_path_name', type => 'string',
	  desc => 'The name of the current path',
	  alias => 'pname', init => 1 }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = gimp_image_get_active_vectors (gimage);

  if (vectors)
    pname = g_strdup (gimp_object_get_name (GIMP_OBJECT (vectors)));
  else
    success = FALSE;
}
CODE
    );
}

sub path_set_current {
    $blurb = 'List the paths associated with the passed image.';

    $help = <<'HELP';
List the paths associated with the passed image.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'set_current_path_name', type => 'string',
	  desc => 'The name of the path to set the current path to',
	  alias => 'pname' }	
    );
    $inargs[0]->{desc} = 'The ID of the image to list set the paths in';

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = gimp_image_get_vectors_by_name (gimage, pname);

  if (vectors)
    gimp_image_set_active_vectors (gimage, vectors);
  else
    success = FALSE;
}
CODE
    );
}

sub path_set_points {
    $blurb = 'Set the points associated with the named path.';

    $help = <<'HELP';
Set the points associated with the named path.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'pathname', type => 'string',
	  desc => 'The name of the path to create (if it exists then a unique
		   name will be created - query the list of paths if you want
		   to make sure that the name of the path you create is 
		   unique. This will be set as the current path.',
	  alias => 'pname', init => 1 },
	{ name => 'ptype', type => 'int32',
	  desc => 'The type of the path. Currently only one type (1 = Bezier)
		   is supported' },
	{ name => 'points_pairs', type => 'floatarray',
	  desc => 'The points in the path represented as 3 floats. The first is
		   the x pos, next is the y pos, last is the type of the pnt.
		   The type field is dependant on the path type. For beziers
		   (type 1 paths) the type can either be (1.0 = BEZIER_ANCHOR,
		   2.0 = BEZIER_CONTROL). Note all points are returned in pixel
		   resolution',
	  array => { name => 'num_path_points',
		     desc => 'The number of points in the path. Each point is
			      made up of (x, y, type) of floats. Currently only 
			      the creation of bezier curves is allowed. The type
			      parameter must be set to (1) to indicate a BEZIER
			      type curve. For BEZIERS. Note the that points
			      must be given in the following order... ACCACCAC
			      ... If the path is not closed the last control
			      point is missed off. Points consist of three
			      control points (control/anchor/control) so for a
			      curve that is not closed there must be at least
			      two points passed (2 x,y pairs). If num_path_pnts
			      % 3 = 0 then the path is assumed to be closed
			      and the points are ACCACCACCACC.',
		     init => 1 } }
    );
    $inargs[0]->{desc} = 'The ID of the image to set the paths in';

    %invoke = (
	vars => [ 'gboolean closed = FALSE' ],
	code  => <<'CODE'
{
  if ((num_path_points / 3) % 3 == 0)
    closed = TRUE;
  else if ((num_path_points / 3) % 3 != 2)
    success = FALSE;

  if (success)
    {
      GimpVectors            *vectors;
      gdouble                *curr_point_pair;
      GimpVectorsCompatPoint *points;
      gint                    n_points;
      gint                    i;

      n_points = num_path_points / 3;

      points = g_new0 (GimpVectorsCompatPoint, n_points);

      for (i = 0, curr_point_pair = points_pairs;
           i < n_points;
           i++, curr_point_pair += 3)
        {
          points[i].x    = curr_point_pair[0];
          points[i].y    = curr_point_pair[1];
          points[i].type = curr_point_pair[2];
        }

      vectors = gimp_vectors_compat_new (gimage, pname, points, n_points,
                                         closed);

      g_free (points);

      if (vectors)
        gimp_image_add_vectors (gimage, vectors, 0);
      else
        success = FALSE;
    }
}
CODE
    );
}

sub path_stroke_current {
    $blurb = 'Stroke the current path in the passed image.';

    $help = <<'HELP';
Stroke the current path in the passed image.
HELP

    &pdb_misc;

    @inargs = ( &std_image_arg );
    $inargs[0]->{desc} = 'The ID of the image which contains the path to
			  stroke';

    %invoke = (
	vars => [ 'GimpVectors *vectors', 'GimpDrawable *drawable' ],
	code => <<'CODE'
{
  vectors  = gimp_image_get_active_vectors (gimage);
  drawable = gimp_image_active_drawable (gimage);

  if (vectors && drawable)
    {
      GimpToolInfo     *tool_info;
      GimpPaintOptions *paint_options;
      GimpPaintCore    *core;

      tool_info = gimp_context_get_tool (gimp_get_current_context (gimp));

      if (! (tool_info && GIMP_IS_PAINT_OPTIONS (tool_info->tool_options)))
        {
          tool_info = (GimpToolInfo *)
            gimp_container_get_child_by_name (gimp->tool_info_list,
                                              "gimp-paintbrush-tool");
        }

      paint_options = GIMP_PAINT_OPTIONS (tool_info->tool_options);

      core = g_object_new (tool_info->paint_info->paint_type, NULL);

      gimp_paint_core_stroke_vectors (core, drawable, paint_options, vectors);

      g_object_unref (core);
    }
  else
    success = FALSE;
}
CODE
    );
}

sub  path_get_point_at_dist {
    $blurb = 'Get point on a path at a specified distance along the path.';

    $help = <<'HELP';
This will return the x,y position of a point at a given distance along the
bezier curve. The distance will the obtained by first digitizing the 
curve internally an then walking along the curve. For a closed curve the
start of the path is the first point on the path that was created. This might
not be obvious. Note the current path is used.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'distance', type => 'float',
	  desc => 'The distance along the path' }
    );
    $inargs[0]->{desc} = 'The ID of the image the paths belongs to';

    @outargs = (
	{ name => 'x_point', type => 'int32',
	  desc => 'The x position of the point', init => 1 },
	{ name => 'y_point', type => 'int32',
	  desc => 'The y position of the point', init => 1 },
	{ name => 'gradient', type => 'float',
	  desc => 'The gradient at the specified point', init => 1 }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = gimp_image_get_active_vectors (gimage);

  if (vectors)
    {
      g_warning ("FIXME: path_get_point_at_dist() is unimplemented");
      success = FALSE;
    }
  else
    success = FALSE;
}
CODE
    );
}

sub path_get_tattoo {
    $blurb = 'Returns the tattoo associated with the name path.';

    $help = <<'HELP';
This procedure returns the tattoo associated with the specified path.  A tattoo is a unique and permanent identifier attached to a path that can be used to uniquely identify a path within an image even between sessions.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'pathname', type => 'string',
	  desc => 'the name of the path whose tattoo should be obtained',
	  alias => 'pname' }
    );

    @outargs = (
	{ name => 'tattoo', type => 'int32',
	  desc => 'The tattoo associated with the name path', init => 1  }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = (GimpVectors *)
    gimp_container_get_child_by_name (gimage->vectors, pname);

  if (vectors)
    tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors));
  else
    success = FALSE;
}
CODE
    );
}

sub path_set_tattoo {
    $blurb = 'Sets the tattoo associated with the name path.';

    $help = <<'HELP';
This procedure sets the tattoo associated with the specified path.  A tattoo is a unique and permenant identifier attached to a path that can be used to uniquely identify a path within an image even between sessions. Note that the value passed to this function must have been obtained from a previous call to path_get_tattoo.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'pathname', type => 'string',
	  desc => 'the name of the path whose tattoo should be set',
	  alias => 'pname' },
        { name => 'tattovalue', type => 'int32',
	  desc => 'The tattoo associated with the name path. Only values returned from \'path_get_tattoo\' should be used here', init => 1  }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = (GimpVectors *)
    gimp_container_get_child_by_name (gimage->vectors, pname);

  if (vectors)
    gimp_item_set_tattoo (GIMP_ITEM (vectors), tattovalue);
  else
    success = FALSE;
}
CODE
    );
}


sub get_path_by_tattoo {
    $blurb = 'Return the name of the path with the given tattoo.';

    $help = <<'HELP';
The procedure returns the name of the path in the specified image which has the passed tattoo. The tattoos are unique within the image and will be preserved across sessions and through renaming of the path. An error is returned if no path woth the specified tattoo can be found.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'tattoo', type => 'int32',
	  desc => 'The tattoo of the required path' }
    );

    @outargs = (
	{ name => 'path_name', type => 'string', init => 1,
	  desc => 'The name of the path with the specified tattoo' }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = gimp_image_get_vectors_by_tattoo (gimage, tattoo);

  if (vectors)
    path_name = g_strdup (gimp_object_get_name (GIMP_OBJECT (vectors)));
  else
    success = FALSE;
}
CODE
    );
}

sub path_delete {
    $blurb = 'Delete the named paths associated with the passed image.';

    $help = <<'HELP';
Delete the named path.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'path_name_to_del', type => 'string',
	  desc => 'The name of the path to delete',
	  alias => 'pname' }	
    );
    $inargs[0]->{desc} = 'The ID of the image to list delete the paths from';

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = (GimpVectors *)
    gimp_container_get_child_by_name (gimage->vectors, pname);

  if (vectors)
    gimp_image_remove_vectors (gimage, vectors);
  else
    success = FALSE;
}
CODE
    );
}

sub path_get_locked {
    $blurb = 'Returns the locked status associated with the name path.';

    $help = <<'HELP';
This procedure returns the lock status associated with the specified path.  A path can be "locked" which means that the transformation tool operations will also apply to the path.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'pathname', type => 'string',
	  desc => 'the name of the path whose locked status should be obtained',
	  alias => 'pname' }
    );

    @outargs = (
	{ name => 'lockstatus', type => 'int32',
	  desc => 'The lock status associated with the name path. 0 returned if the path is not locked. 1 is returned if the path is locked', init => 1  }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = (GimpVectors *)
    gimp_container_get_child_by_name (gimage->vectors, pname);

  if (vectors)
    lockstatus = gimp_item_get_linked (GIMP_ITEM (vectors));
  else
    success = FALSE;
}
CODE
    );
}

sub path_set_locked {
    $blurb = 'Set the locked status associated with the name path.';

    $help = <<'HELP';
This procedure sets the lock status associated with the specified path.  A path can be "locked" which means that the transformation tool operations will also apply to the path.
HELP

    &pdb_misc;

    @inargs = (
	&std_image_arg,
	{ name => 'pathname', type => 'string',
	  desc => 'the name of the path whose locked status should be set',
	  alias => 'pname' },
	{ name => 'lockstatus', type => 'int32',
	  desc => 'The lock status associated with the name path. 0 if the path is not locked. 1 if the path is to be locked', init => 1  }
    );

    %invoke = (
	vars => [ 'GimpVectors *vectors' ],
	code => <<'CODE'
{
  vectors = (GimpVectors *)
    gimp_container_get_child_by_name (gimage->vectors, pname);

  if (vectors)
    gimp_item_set_linked (GIMP_ITEM (vectors), lockstatus, TRUE);
  else
    success = FALSE;
}
CODE
    );
}

@headers = qw(<string.h> "core/gimp.h" "core/gimpcontext.h" "core/gimplist.h"
              "core/gimppaintinfo.h" "core/gimptoolinfo.h"
              "paint/gimppaintcore-stroke.h" "paint/gimppaintoptions.h"
              "vectors/gimpanchor.h" "vectors/gimpbezierstroke.h"
              "vectors/gimpvectors.h" "vectors/gimpvectors-compat.h");

@procs = qw(path_list path_get_current path_set_current path_delete
	    path_get_points path_set_points
            path_stroke_current path_get_point_at_dist
	    path_get_tattoo path_set_tattoo get_path_by_tattoo
            path_get_locked path_set_locked);
%exports = (app => [@procs], lib => [@procs]);

$desc = 'Paths';

1;
