# 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 Manish Singh <yosh@gimp.org>

# Text

sub pdb_misc {
   &std_pdb_misc;
   $author = 'Martin Edlman';
   $date = '1998';
}

sub text_arg () {{
    name => 'text',
    type => 'string',
    desc => 'The text to generate'
}}

sub fontname_arg () {{
    name => 'fontname',
    type => 'string',
    desc => 'The fontname (conforming to the X Logical Font Description
    	     Conventions)'
}}

sub size_args () {(
    { name => 'size', type => '0 < float',
      desc => 'The size of text in either pixels or points' },
    { name => 'size_type', type => 'enum SizeType',
      desc => 'The units of specified size: %%desc%%' }
)}

sub render_args () {(
    &std_image_arg,
    { name => 'drawable', type => 'drawable',
      desc => 'The affected drawable: (-1 for a new text layer)',
      no_success => 1 },
    { name => 'x', type => 'float',
      desc => 'The x coordinate for the left of the text bounding box' },
    { name => 'y', type => 'float',
      desc => 'The y coordinate for the top of the text bounding box' },
    &text_arg,
    { name => 'border', type => '-1 <= int32',
      desc => 'The size of the border: %%desc%%' },
    &std_antialias_arg,
    &size_args
)}

@props = qw(foundry family weight slant set_width spacing registry encoding);

sub font_prop_args {
   my @result;
   foreach (@props) {
	(my $desc = $_) =~ s/_/-/g;
	push @result, { name => $_, type => 'string',
			desc => qq/The font $desc, "*" for any/ }
   }
   @result;
}

sub fontname_makearg {
    my $arg = { type => 'string', code => "%%arg%% =\n  text_xlfd_create (" };
    foreach (@props) { $arg->{code} .= "\t\t    $_,\n" }
    $arg->{code} =~ s/\(\s+/(/;
    $arg->{code} =~ s/,\n$/);\n/s;
    $arg;
}

sub render_outargs {
   @outargs = (
	{ name => 'text_layer', type => 'layer',
	  desc => 'The new text layer', init => 1 }
   );
}

sub extents_outargs {
    foreach (qw(width height ascent descent)) {
	push @outargs, { name => $_, type => 'int32',
			 desc => "The $_ of the specified font" }
    }
}

sub text_fontname {
    $blurb = <<'BLURB';
Add text at the specified location as a floating selection or a new layer.
BLURB

    $help = <<'HELP';
This tool requires font information as a fontname conforming to the 'X Logical
Font Description Conventions'. You can specify the fontsize in units of pixels
or points, and the appropriate metric is specified using the size_type
argument. The x and y parameters together control the placement of the new
text by specifying the upper left corner of the text bounding box. If the
antialias parameter is non-zero, the generated text will blend more smoothly
with underlying layers. This option requires more time and memory to compute
than non-antialiased text; the resulting floating selection or layer, however,
will require the same amount of memory with or without antialiasing. If the
specified drawable parameter is valid, the text will be created as a floating
selection attached to the drawable. If the drawable parameter is not valid
(-1), the text will appear as a new layer. Finally, a border can be specified
around the final rendered text. The border is measured in pixels. If the
border is specified as -1, empty spaces around the text will not be cropped.

HELP

    &pdb_misc;
    $author .= ' & Sven Neumann';

    @inargs = (
        &render_args,
	&fontname_arg
    );

    &render_outargs;

    %invoke = (
	vars => [ 'gchar *real_fontname' ],
	code => <<'CODE'
{
  /*  default to pixels by passing 0.0 as resolution  */
  real_fontname = text_xlfd_insert_size (fontname, size, size_type,
					 0.0, 0.0, antialias);

  text_layer = text_render (gimage, drawable, x, y, real_fontname, text,
			    border, antialias);

  if (text_layer == NULL)
    success = FALSE;

  g_free (real_fontname);
}
CODE
    );
}

sub text_get_extents_fontname {
    $blurb = 'Get extents of the bounding box for the specified text.';

    $help = <<'HELP';
This tool returns the width and height of a bounding box for the specified text
string with the specified font information. Ascent and descent for the
specified font are returned as well.
HELP

    &pdb_misc;
    $author .= ' & Sven Neumann';
 
    @inargs = (
	&text_arg,
	&size_args,
	&fontname_arg
    );

    &extents_outargs;

    %invoke = (
	vars => [ 'gchar *real_fontname' ],
	code => <<'CODE'
{
  /*  default to pixels by passing 0.0 as resolution  */
  real_fontname = text_xlfd_insert_size (fontname, size, size_type,
					 0.0, 0.0, FALSE);

  success = text_get_extents (real_fontname, text,
			      &width, &height,
			      &ascent, &descent);

  g_free (real_fontname);
}
CODE
    );
}

sub text {
    $blurb = <<'BLURB';
Add text at the specified location as a floating selection or a new layer.
BLURB

    $help = <<'HELP';
This tool requires font information in the form of nine parameters: size,
foundry, family, weight, slant, set_width, spacing, registry, encoding. The
font size can either be specified in units of pixels or points, and the
appropriate metric is specified using the size_type argument. The x and y
parameters together control the placement of the new text by specifying the
upper left corner of the text bounding box. If the antialias parameter is
non-zero, the generated text will blend more smoothly with underlying layers.
This option requires more time and memory to compute than non-antialiased text;
the resulting floating selection or layer, however, will require the same
amount of memory with or without antialiasing. If the specified drawable
parameter is valid, the text will be created as a floating selection attached
to the drawable. If the drawable parameter is not valid (-1), the text will
appear as a new layer. Finally, a border can be specified around the final
rendered text. The border is measured in pixels. If the border is specified 
as -1, empty spaces around the text will not be cropped.
HELP

    &pdb_misc;

    @inargs = (
	&render_args,
        &font_prop_args
    );

    &render_outargs;

    %invoke = (
	pass_through => 'text_fontname',
	pass_args => [ 0..8 ],
	make_args => [ &fontname_makearg ]
   );
}

sub text_get_extents {
    $blurb = 'Get extents of the bounding box for the specified text.';

    $help = <<'HELP';
This tool returns the width and height of a bounding box for the specified text
string with the specified font information. Ascent and descent for the
specified font are returned as well.
HELP

    &pdb_misc;

    @inargs = (
	&text_arg,
	&size_args,
	&font_prop_args
    );

    &extents_outargs;

    %invoke = (
	pass_through => 'text_get_extents_fontname',
	pass_args => [ 0..2 ],
	make_args => [ &fontname_makearg ]
    );
}

@headers = qw("appenv.h" "text_tool.h" "libgimp/gimplimits.h"
	      <stdio.h> <string.h>);

$extra{app}->{code} = <<'CODE';
static gchar *
text_xlfd_insert_size (gchar    *fontname,
		       gdouble   size,
		       SizeType  metric,
		       gdouble   xresolution,
		       gdouble   yresolution,
		       gboolean  antialias)
{
  gchar *newfont, *workfont;
  gchar size_buffer[16];
  gchar xres_buffer[16];
  gchar yres_buffer[16];
  gint pos = 0;

  if (size <= 0)
    return NULL;

  if (xresolution < GIMP_MIN_RESOLUTION ||
      yresolution < GIMP_MIN_RESOLUTION ||
      metric == PIXELS)
    {
      xresolution = yresolution = 0.0;
    }
  else
    {
      xresolution = MIN (xresolution, GIMP_MAX_RESOLUTION);
      yresolution = MIN (yresolution, GIMP_MAX_RESOLUTION);
    }

  if (antialias)
    size *= SUPERSAMPLE;

  /*  Note: if metric == POINTS we either use the passed resolution (if
   *        statement below) or we (implicitly) use the resolution hidden
   *        in the fontname.
   */
  if (metric == POINTS && xresolution != 0.0)
    {
      /*  the xlfd uses decipoints  */
      size *= 10;

      /*  X allows only integer resolution values, so we do some
       *  ugly calculations (starting with yres because the size of
       *  a font is it's height)
       */
      if (yresolution < 1.0)
	{
	  size /= (1.0 / yresolution);
	  xresolution *= (1.0 / yresolution);
	  yresolution = 1.0;
	}

      /*  res may be != (int) res
       *  (important only for very small resolutions)
       */
      size *= yresolution / (double) (int) yresolution;
      xresolution /= yresolution / (double) (int) yresolution;

      /*  finally, if xres became invalid by the above calculations  */
      xresolution = CLAMP (xresolution, 1.0, GIMP_MAX_RESOLUTION);
    }

  sprintf (size_buffer, "%d", (int) size);
  sprintf (xres_buffer, "%d", (int) xresolution);
  sprintf (yres_buffer, "%d", (int) yresolution);

  newfont = workfont = g_new (char, strlen (fontname) + 32);

  while (*fontname)
    {
      *workfont++ = *fontname;

      if (*fontname++ == '-')
	{
	  pos++;
	  if ((pos == 7 && metric == PIXELS) ||
	      (pos == 8 && metric == POINTS))
	    {
	      int len = strlen (size_buffer);
	      memcpy (workfont, size_buffer, len);
	      workfont += len;

	      while (*fontname != '-')
		fontname++;
	    }
	  else if (pos == 9 && metric == POINTS && xresolution != 0.0)
	    {
	      int len = strlen (xres_buffer);
	      memcpy (workfont, xres_buffer, len);
	      workfont += len;

	      while (*fontname != '-')
		fontname++;
	    }
	  else if (pos == 10 && metric == POINTS && yresolution != 0.0)
	    {
	      int len = strlen (yres_buffer);
	      memcpy (workfont, yres_buffer, len);
	      workfont += len;

	      while (*fontname != '-')
		fontname++;
	    }
	}
    }

   *workfont = '\0';
   return newfont;
}

static gchar *
text_xlfd_create (gchar    *foundry,
		  gchar    *family,
		  gchar    *weight,
		  gchar    *slant,
		  gchar    *set_width,
		  gchar    *spacing,
		  gchar    *registry,
		  gchar    *encoding)
{
  /* create the fontname */
  return g_strdup_printf ("-%s-%s-%s-%s-%s-*-*-*-*-*-%s-*-%s-%s",
			  foundry, family, weight, slant, set_width,
			  spacing, registry, encoding);
}
CODE

@procs = qw(text_fontname text_get_extents_fontname text text_get_extents);
%exports = (app => [@procs]);

$desc = 'Text procedures';

1;
