film.c 43 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2 3 4 5
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 * Film plug-in (C) 1997 Peter Kirchgessner
 * e-mail: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg
 *
6
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
Elliot Lee's avatar
Elliot Lee committed
9 10 11 12 13 14 15 16
 * (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
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
18 19 20 21 22 23
 */

/*
 * This plug-in generates a film roll with several images
 */

24 25
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
26
#include <string.h>
27

28 29
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
Elliot Lee's avatar
Elliot Lee committed
30

31
#include "libgimp/stdplugins-intl.h"
Elliot Lee's avatar
Elliot Lee committed
32

33

34 35 36
#define PLUG_IN_PROC        "plug-in-film"
#define PLUG_IN_BINARY      "film"

37 38 39 40
/* Maximum number of pictures per film */
#define MAX_FILM_PICTURES   64
#define COLOR_BUTTON_WIDTH  50
#define COLOR_BUTTON_HEIGHT 20
Elliot Lee's avatar
Elliot Lee committed
41

42 43
#define FONT_LEN            256

Elliot Lee's avatar
Elliot Lee committed
44 45
/* Define how the plug-in works. Values marked (r) are with regard */
/* to film_height (i.e. it should be a value from 0.0 to 1.0) */
46 47 48
typedef struct
{
  gint     film_height;           /* height of the film */
Sven Neumann's avatar
Sven Neumann committed
49
  GimpRGB  film_color;            /* color of film */
50 51 52 53 54 55 56 57
  gdouble  picture_height;        /* height of picture (r) */
  gdouble  picture_space;         /* space between pictures (r) */
  gdouble  hole_offset;           /* distance from hole to edge of film (r) */
  gdouble  hole_width;            /* width of hole (r) */
  gdouble  hole_height;           /* height of holes (r) */
  gdouble  hole_space;            /* distance of holes (r) */
  gdouble  number_height;         /* height of picture numbering (r) */
  gint     number_start;          /* number for first picture */
Sven Neumann's avatar
Sven Neumann committed
58
  GimpRGB  number_color;          /* color of number */
59
  gchar    number_font[FONT_LEN]; /* font family to use for numbering */
60 61 62 63
  gint     number_pos[2];         /* flags where to draw numbers (top/bottom) */
  gint     keep_height;           /* flag if to keep max. image height */
  gint     num_images;            /* number of images */
  gint32   image[MAX_FILM_PICTURES]; /* list of image IDs */
Elliot Lee's avatar
Elliot Lee committed
64 65 66 67 68
} FilmVals;

/* Data to use for the dialog */
typedef struct
{
69 70 71
  GtkObject    *advanced_adj[7];
  GtkTreeModel *image_list_all;
  GtkTreeModel *image_list_film;
Elliot Lee's avatar
Elliot Lee committed
72 73 74
} FilmInterface;


75 76 77
/* Declare local functions
 */
static void      query  (void);
78
static void      run    (const gchar      *name,
79 80 81 82
                         gint              nparams,
                         const GimpParam  *param,
                         gint             *nreturn_vals,
                         GimpParam       **return_vals);
83

Elliot Lee's avatar
Elliot Lee committed
84

85
static gint32    create_new_image   (const gchar    *filename,
86 87 88 89 90 91
                                     guint           width,
                                     guint           height,
                                     GimpImageType   gdtype,
                                     gint32         *layer_ID,
                                     GimpDrawable  **drawable,
                                     GimpPixelRgn   *pixel_rgn);
Elliot Lee's avatar
Elliot Lee committed
92

93
static gchar   * compose_image_name (gint32          image_ID);
Elliot Lee's avatar
Elliot Lee committed
94

95
static gint32    film               (void);
Elliot Lee's avatar
Elliot Lee committed
96

97
static gboolean  check_filmvals     (void);
Elliot Lee's avatar
Elliot Lee committed
98

99
static void      set_pixels         (gint            numpix,
100 101
                                     guchar         *dst,
                                     GimpRGB        *color);
Elliot Lee's avatar
Elliot Lee committed
102

103
static guchar  * create_hole_rgb    (gint            width,
104
                                     gint            height);
Elliot Lee's avatar
Elliot Lee committed
105

106
static void      draw_hole_rgb      (GimpDrawable   *drw,
107 108 109 110 111
                                     gint            x,
                                     gint            y,
                                     gint            width,
                                     gint            height,
                                     guchar         *hole);
Elliot Lee's avatar
Elliot Lee committed
112

113
static void      draw_number        (gint32          layer_ID,
114 115 116 117
                                     gint            num,
                                     gint            x,
                                     gint            y,
                                     gint            height);
Elliot Lee's avatar
Elliot Lee committed
118 119


120
static void        add_list_item_callback (GtkWidget        *widget,
121
                                           GtkTreeSelection *sel);
122
static void        del_list_item_callback (GtkWidget        *widget,
123
                                           GtkTreeSelection *sel);
Elliot Lee's avatar
Elliot Lee committed
124

125
static GtkTreeModel * add_image_list      (gboolean        add_box_flag,
126 127 128
                                           gint            n,
                                           gint32         *image_id,
                                           GtkWidget      *hbox);
Elliot Lee's avatar
Elliot Lee committed
129

130 131 132 133 134 135 136
static gboolean    film_dialog               (gint32                image_ID);
static void        film_reset_callback       (GtkWidget            *widget,
                                              gpointer              data);
static void        film_font_select_callback (GimpFontSelectButton *button,
                                              const gchar          *name,
                                              gboolean              closing,
                                              gpointer              data);
Elliot Lee's avatar
Elliot Lee committed
137 138


139
const GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
140
{
141 142 143 144 145 146 147 148 149 150 151 152 153 154
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
};

static gdouble advanced_defaults[] =
{
  0.695,           /* Picture height */
  0.040,           /* Picture spacing */
  0.058,           /* Hole offset to edge of film */
  0.052,           /* Hole width */
  0.081,           /* Hole height */
  0.081,           /* Hole distance */
Michael Natterer's avatar
Michael Natterer committed
155
  0.052            /* Image number height */
Elliot Lee's avatar
Elliot Lee committed
156 157 158 159
};

static FilmVals filmvals =
{
160
  256,             /* Height of film */
Sven Neumann's avatar
Sven Neumann committed
161
  { 0.0, 0.0, 0.0, 1.0 }, /* Color of film */
162 163 164 165 166 167 168 169
  0.695,           /* Picture height */
  0.040,           /* Picture spacing */
  0.058,           /* Hole offset to edge of film */
  0.052,           /* Hole width */
  0.081,           /* Hole height */
  0.081,           /* Hole distance */
  0.052,           /* Image number height */
  1,               /* Start index of numbering */
Sven Neumann's avatar
Sven Neumann committed
170
  { 0.93, 0.61, 0.0, 1.0 }, /* Color of number */
171
  "Monospace",     /* Font family for numbering */
172 173 174 175
  { TRUE, TRUE },  /* Numbering on top and bottom */
  0,               /* Dont keep max. image height */
  0,               /* Number of images */
  { 0 }            /* Input image list */
Elliot Lee's avatar
Elliot Lee committed
176 177 178 179 180
};


static FilmInterface filmint =
{
181
  { NULL },   /* advanced adjustments */
182
  NULL, NULL  /* image list widgets */
Elliot Lee's avatar
Elliot Lee committed
183 184 185
};


186
static GimpRunMode run_mode;
Elliot Lee's avatar
Elliot Lee committed
187 188 189 190 191


MAIN ()

static void
192
query (void)
Elliot Lee's avatar
Elliot Lee committed
193
{
194
  static const GimpParamDef args[] =
Elliot Lee's avatar
Elliot Lee committed
195
  {
196
    { GIMP_PDB_INT32,      "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
197 198 199 200 201 202 203 204 205 206
    { GIMP_PDB_IMAGE,      "image",        "Input image (only used as default image in interactive mode)" },
    { GIMP_PDB_DRAWABLE,   "drawable",     "Input drawable (not used)" },
    { GIMP_PDB_INT32,      "film-height",  "Height of film (0: fit to images)" },
    { GIMP_PDB_COLOR,      "film-color",   "Color of the film" },
    { GIMP_PDB_INT32,      "number-start", "Start index for numbering" },
    { GIMP_PDB_STRING,     "number-font",  "Font for drawing numbers" },
    { GIMP_PDB_COLOR,      "number-color", "Color for numbers" },
    { GIMP_PDB_INT32,      "at-top",       "Flag for drawing numbers at top of film" },
    { GIMP_PDB_INT32,      "at-bottom",    "Flag for drawing numbers at bottom of film" },
    { GIMP_PDB_INT32,      "num-images",   "Number of images to be used for film" },
207
    { GIMP_PDB_INT32ARRAY, "image-ids",    "num-images image IDs to be used for film" }
Elliot Lee's avatar
Elliot Lee committed
208
  };
209

210
  static const GimpParamDef return_vals[] =
Elliot Lee's avatar
Elliot Lee committed
211
  {
212
    { GIMP_PDB_IMAGE, "new-image", "Output image" }
Elliot Lee's avatar
Elliot Lee committed
213 214
  };

215
  gimp_install_procedure (PLUG_IN_PROC,
216 217 218 219 220 221 222 223 224
                          N_("Combine several images on a film strip"),
                          "Compose several images to a roll film",
                          "Peter Kirchgessner",
                          "Peter Kirchgessner (peter@kirchgessner.net)",
                          "1997",
                          N_("_Filmstrip..."),
                          "INDEXED*, GRAY*, RGB*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (args),
225
                          G_N_ELEMENTS (return_vals),
226
                          args, return_vals);
227

228
  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Combine");
Elliot Lee's avatar
Elliot Lee committed
229 230 231
}

static void
232 233 234 235 236
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
237
{
238
  static GimpParam  values[2];
Sven Neumann's avatar
Sven Neumann committed
239
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
240 241
  gint32            image_ID;
  gint              k;
Elliot Lee's avatar
Elliot Lee committed
242

243
  INIT_I18N ();
244

Elliot Lee's avatar
Elliot Lee committed
245 246 247
  run_mode = param[0].data.d_int32;

  *nreturn_vals = 2;
248
  *return_vals  = values;
Elliot Lee's avatar
Elliot Lee committed
249

250
  values[0].type          = GIMP_PDB_STATUS;
Elliot Lee's avatar
Elliot Lee committed
251
  values[0].data.d_status = status;
252 253
  values[1].type          = GIMP_PDB_IMAGE;
  values[1].data.d_int32  = -1;
Elliot Lee's avatar
Elliot Lee committed
254 255 256

  switch (run_mode)
    {
Sven Neumann's avatar
Sven Neumann committed
257
    case GIMP_RUN_INTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
258
      /*  Possibly retrieve data  */
259
      gimp_get_data (PLUG_IN_PROC, &filmvals);
Elliot Lee's avatar
Elliot Lee committed
260 261 262

      /*  First acquire information with a dialog  */
      if (! film_dialog (param[1].data.d_int32))
263
        return;
Elliot Lee's avatar
Elliot Lee committed
264 265
      break;

Sven Neumann's avatar
Sven Neumann committed
266
    case GIMP_RUN_NONINTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
267 268 269
      /*  Make sure all the arguments are there!  */
      /* Also we want to have some images to compose */
      if ((nparams != 12) || (param[10].data.d_int32 < 1))
270 271 272
        {
          status = GIMP_PDB_CALLING_ERROR;
        }
273
      else
274
        {
275 276
          filmvals.keep_height       = (param[3].data.d_int32 <= 0);
          filmvals.film_height       = (filmvals.keep_height ?
277 278
                                        128 : param[3].data.d_int32);
          filmvals.film_color        = param[4].data.d_color;
279
          filmvals.number_start      = param[5].data.d_int32;
280
          g_strlcpy (filmvals.number_font, param[6].data.d_string, FONT_LEN);
281
          filmvals.number_color      = param[7].data.d_color;
282 283 284
          filmvals.number_pos[0]     = param[8].data.d_int32;
          filmvals.number_pos[1]     = param[9].data.d_int32;
          filmvals.num_images        = param[10].data.d_int32;
Elliot Lee's avatar
Elliot Lee committed
285 286 287 288
          if (filmvals.num_images > MAX_FILM_PICTURES)
            filmvals.num_images = MAX_FILM_PICTURES;
          for (k = 0; k < filmvals.num_images; k++)
            filmvals.image[k] = param[11].data.d_int32array[k];
289
        }
Elliot Lee's avatar
Elliot Lee committed
290 291
      break;

Sven Neumann's avatar
Sven Neumann committed
292
    case GIMP_RUN_WITH_LAST_VALS:
Elliot Lee's avatar
Elliot Lee committed
293
      /*  Possibly retrieve data  */
294
      gimp_get_data (PLUG_IN_PROC, &filmvals);
Elliot Lee's avatar
Elliot Lee committed
295 296 297 298 299 300
      break;

    default:
      break;
    }

301
  if (! check_filmvals ())
Sven Neumann's avatar
Sven Neumann committed
302
    status = GIMP_PDB_CALLING_ERROR;
Elliot Lee's avatar
Elliot Lee committed
303

Sven Neumann's avatar
Sven Neumann committed
304
  if (status == GIMP_PDB_SUCCESS)
Elliot Lee's avatar
Elliot Lee committed
305
    {
306
      gimp_progress_init (_("Composing images"));
Elliot Lee's avatar
Elliot Lee committed
307 308 309

      image_ID = film ();

310
      if (image_ID < 0)
311 312 313
        {
          status = GIMP_PDB_EXECUTION_ERROR;
        }
Elliot Lee's avatar
Elliot Lee committed
314
      else
315 316 317 318 319 320 321
        {
          values[1].data.d_int32 = image_ID;
          gimp_image_undo_enable (image_ID);
          gimp_image_clean_all (image_ID);
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
            gimp_display_new (image_ID);
        }
Elliot Lee's avatar
Elliot Lee committed
322 323

      /*  Store data  */
Sven Neumann's avatar
Sven Neumann committed
324
      if (run_mode == GIMP_RUN_INTERACTIVE)
325
        gimp_set_data (PLUG_IN_PROC, &filmvals, sizeof (FilmVals));
Elliot Lee's avatar
Elliot Lee committed
326 327 328 329 330 331 332 333 334
    }

  values[0].data.d_status = status;
}

/* Compose a roll film image from several images */
static gint32
film (void)
{
335 336 337 338 339 340 341 342 343 344 345 346 347
  gint          width, height, tile_height;
  guchar       *hole;
  gint          film_height, film_width;
  gint          picture_width, picture_height;
  gint          picture_space, picture_x0, picture_y0;
  gint          hole_offset, hole_width, hole_height, hole_space, hole_x;
  gint          number_height, num_images, num_pictures;
  gint          j, k, picture_count;
  gdouble       f;
  gint          num_layers;
  gint32       *image_ID_src, image_ID_dst, layer_ID_src, layer_ID_dst;
  gint          image_ID_tmp;
  gint32       *layers;
Sven Neumann's avatar
Sven Neumann committed
348
  GimpDrawable *drawable_dst;
349 350 351
  GimpPixelRgn  pixel_rgn_dst;
  gint          new_layer;
  gint          floating_sel;
352 353 354 355 356 357 358 359 360 361 362

  /* initialize */

  layers = NULL;

  num_images = filmvals.num_images;
  image_ID_src = filmvals.image;

  if (num_images <= 0)
    return (-1);

363 364
  gimp_context_push ();
  gimp_context_set_foreground (&filmvals.number_color);
365
  gimp_context_set_background (&filmvals.film_color);
366

367 368 369 370 371 372
  tile_height = gimp_tile_height ();

  if (filmvals.keep_height) /* Search maximum picture height */
    {
      picture_height = 0;
      for (j = 0; j < num_images; j++)
373 374 375 376
        {
          height = gimp_image_height (image_ID_src[j]);
          if (height > picture_height) picture_height = height;
        }
377 378 379 380 381 382 383 384
      film_height = (int)(picture_height / filmvals.picture_height + 0.5);
      filmvals.film_height = film_height;
    }
  else
    {
      film_height = filmvals.film_height;
      picture_height = (int)(film_height * filmvals.picture_height + 0.5);
    }
385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
  picture_space = (int)(film_height * filmvals.picture_space + 0.5);
  picture_y0 = (film_height - picture_height)/2;

  number_height = film_height * filmvals.number_height;

  /* Calculate total film width */
  film_width = 0;
  num_pictures = 0;
  for (j = 0; j < num_images; j++)
    {
      layers = gimp_image_get_layers (image_ID_src[j], &num_layers);
      /* Get scaled image size */
      width = gimp_image_width (image_ID_src[j]);
      height = gimp_image_height (image_ID_src[j]);
      f = ((double)picture_height) / (double)height;
      picture_width = width * f;

      for (k = 0; k < num_layers; k++)
404 405 406
        {
          if (gimp_layer_is_floating_sel (layers[k]))
            continue;
407

408 409 410 411 412
          film_width += (picture_space/2);  /* Leading space */
          film_width += picture_width;      /* Scaled image width */
          film_width += (picture_space/2);  /* Trailing space */
          num_pictures++;
        }
413

414
      g_free (layers);
415
    }
416

Elliot Lee's avatar
Elliot Lee committed
417
#ifdef FILM_DEBUG
418 419 420 421
  g_printerr ("film_height = %d, film_width = %d\n", film_height, film_width);
  g_printerr ("picture_height = %d, picture_space = %d, picture_y0 = %d\n",
              picture_height, picture_space, picture_y0);
  g_printerr ("Number of pictures = %d\n", num_pictures);
Elliot Lee's avatar
Elliot Lee committed
422 423
#endif

Michael Natterer's avatar
Michael Natterer committed
424
  image_ID_dst = create_new_image (_("Untitled"),
425 426 427
                                   (guint) film_width, (guint) film_height,
                                   GIMP_RGB_IMAGE, &layer_ID_dst,
                                   &drawable_dst, &pixel_rgn_dst);
Elliot Lee's avatar
Elliot Lee committed
428

429
  /* Fill film background */
430
  gimp_drawable_fill (layer_ID_dst, GIMP_BACKGROUND_FILL);
Elliot Lee's avatar
Elliot Lee committed
431

432 433 434 435 436 437
  /* Draw all the holes */
  hole_offset = film_height * filmvals.hole_offset;
  hole_width = film_height * filmvals.hole_width;
  hole_height = film_height * filmvals.hole_height;
  hole_space = film_height * filmvals.hole_space;
  hole_x = hole_space / 2;
Elliot Lee's avatar
Elliot Lee committed
438 439

#ifdef FILM_DEBUG
440 441
  g_printerr ("hole_x %d hole_offset %d hole_width %d hole_height %d hole_space %d\n",
              hole_x, hole_offset, hole_width, hole_height, hole_space );
Elliot Lee's avatar
Elliot Lee committed
442 443
#endif

444 445 446 447
  hole = create_hole_rgb (hole_width, hole_height);
  if (hole)
    {
      while (hole_x < film_width)
448 449 450 451 452 453 454 455 456 457
        {
          draw_hole_rgb (drawable_dst, hole_x,
                         hole_offset,
                         hole_width, hole_height, hole);
          draw_hole_rgb (drawable_dst, hole_x,
                         film_height-hole_offset-hole_height,
                         hole_width, hole_height, hole);

          hole_x += hole_width + hole_space;
        }
458 459 460
      g_free (hole);
    }
  gimp_drawable_detach (drawable_dst);
Elliot Lee's avatar
Elliot Lee committed
461

462

463 464 465 466 467
  /* Compose all images and layers */
  picture_x0 = 0;
  picture_count = 0;
  for (j = 0; j < num_images; j++)
    {
468 469 470
      image_ID_tmp = gimp_image_duplicate (image_ID_src[j]);
      width = gimp_image_width (image_ID_tmp);
      height = gimp_image_height (image_ID_tmp);
Michael Natterer's avatar
Michael Natterer committed
471
      f = ((gdouble) picture_height) / (gdouble) height;
472
      picture_width = width * f;
473
      if (gimp_image_base_type (image_ID_tmp) != GIMP_RGB_IMAGE)
David Odin's avatar
David Odin committed
474
        gimp_image_convert_rgb (image_ID_tmp);
475
      gimp_image_scale (image_ID_tmp, picture_width, picture_height);
Elliot Lee's avatar
Elliot Lee committed
476

477
      layers = gimp_image_get_layers (image_ID_tmp, &num_layers);
478
      for (k = 0; k < num_layers; k++)
479 480 481 482 483 484 485
        {
          if (gimp_layer_is_floating_sel (layers[k]))
            continue;

          picture_x0 += picture_space / 2;

          layer_ID_src = layers[k];
David Odin's avatar
David Odin committed
486 487 488
          gimp_layer_resize_to_image_size (layer_ID_src);
          new_layer = gimp_layer_new_from_drawable (layer_ID_src,
                                                    image_ID_dst);
489
          gimp_image_insert_layer (image_ID_dst, new_layer, -1, -1);
David Odin's avatar
David Odin committed
490
          gimp_layer_set_offsets (new_layer, picture_x0, picture_y0);
491 492 493 494 495 496 497

          /* Draw picture numbers */
          if ((number_height > 0) &&
              (filmvals.number_pos[0] || filmvals.number_pos[1]))
            {
              if (filmvals.number_pos[0])
                draw_number (layer_ID_dst,
David Odin's avatar
David Odin committed
498
                             filmvals.number_start + picture_count,
499 500 501 502
                             picture_x0 + picture_width/2,
                             (hole_offset-number_height)/2, number_height);
              if (filmvals.number_pos[1])
                draw_number (layer_ID_dst,
David Odin's avatar
David Odin committed
503
                             filmvals.number_start + picture_count,
504 505 506 507 508 509
                             picture_x0 + picture_width/2,
                             film_height - (hole_offset + number_height)/2,
                             number_height);
            }

          picture_x0 += picture_width + (picture_space/2);
510

511 512
          gimp_progress_update (((gdouble) (picture_count + 1)) /
                                (gdouble) num_pictures);
513

514 515 516 517 518
          picture_count++;
        }

      g_free (layers);
      gimp_image_delete (image_ID_tmp);
519 520
    }

521
  gimp_image_flatten (image_ID_dst);
Elliot Lee's avatar
Elliot Lee committed
522

523
  /* Drawing text/numbers leaves us with a floating selection. Stop it */
524 525 526
  floating_sel = gimp_image_get_floating_sel (image_ID_dst);
  if (floating_sel != -1)
    gimp_floating_sel_anchor (floating_sel);
527

528
  gimp_context_pop ();
Elliot Lee's avatar
Elliot Lee committed
529

530
  return image_ID_dst;
Elliot Lee's avatar
Elliot Lee committed
531 532 533
}

/* Check filmvals. Unreasonable values are reset to a default. */
534 535
/* If this is not possible, FALSE is returned. Otherwise TRUE is returned. */
static gboolean
Elliot Lee's avatar
Elliot Lee committed
536 537
check_filmvals (void)
{
538 539 540 541 542 543
  if (filmvals.film_height < 10)
    filmvals.film_height = 10;

  if (filmvals.number_start < 0)
    filmvals.number_start = 0;

544 545
  if (filmvals.number_font[0] == '\0')
    strcpy (filmvals.number_font, "Monospace");
546 547

  if (filmvals.num_images < 1)
548
    return FALSE;
549

550
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
551 552 553 554
}

/* Assigns numpix pixels starting at dst with color r,g,b */
static void
Sven Neumann's avatar
Sven Neumann committed
555 556 557
set_pixels (gint     numpix,
            guchar  *dst,
            GimpRGB *color)
558
{
559
  register gint   k;
560
  register guchar ur, ug, ub, *udest;
Elliot Lee's avatar
Elliot Lee committed
561

Sven Neumann's avatar
Sven Neumann committed
562 563 564
  ur = color->r * 255.999;
  ug = color->g * 255.999;
  ub = color->b * 255.999;
565 566
  k = numpix;
  udest = dst;
Sven Neumann's avatar
Sven Neumann committed
567

568 569 570 571 572 573
  while (k-- > 0)
    {
      *(udest++) = ur;
      *(udest++) = ug;
      *(udest++) = ub;
    }
Elliot Lee's avatar
Elliot Lee committed
574 575 576
}

/* Create the RGB-pixels that make up the hole */
577 578
static guchar *
create_hole_rgb (gint width,
579
                 gint height)
580 581
{
  guchar *hole, *top, *bottom;
582
  gint    radius, length, k;
583 584 585 586 587 588 589 590 591 592 593 594

  hole = g_new (guchar, width * height * 3);

  /* Fill a rectangle with white */
  memset (hole, 255, width * height * 3);
  radius = height / 4;
  if (radius > width / 2)
    radius = width / 2;
  top = hole;
  bottom = hole + (height-1)*width*3;
  for (k = radius-1; k > 0; k--)  /* Rounding corners */
    {
595
      length = (int)(radius - sqrt ((gdouble) (radius * radius - k * k))
David Odin's avatar
David Odin committed
596
                     - 0.5);
597
      if (length > 0)
598 599 600 601 602 603
        {
          set_pixels (length, top, &filmvals.film_color);
          set_pixels (length, top + (width-length)*3, &filmvals.film_color);
          set_pixels (length, bottom, &filmvals.film_color);
          set_pixels (length, bottom + (width-length)*3, &filmvals.film_color);
        }
604 605 606 607 608
      top += width*3;
      bottom -= width*3;
    }

  return hole;
Elliot Lee's avatar
Elliot Lee committed
609 610 611 612
}

/* Draw the hole at the specified position */
static void
Sven Neumann's avatar
Sven Neumann committed
613
draw_hole_rgb (GimpDrawable *drw,
614 615 616 617 618
               gint          x,
               gint          y,
               gint          width,
               gint          height,
               guchar       *hole)
619
{
620 621 622 623 624 625
  GimpPixelRgn    rgn;
  guchar         *data;
  gint            tile_height = gimp_tile_height ();
  gint            i, j, scan_lines;
  gint            d_width = gimp_drawable_width (drw->drawable_id);
  gint            length;
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

  if ((width <= 0) || (height <= 0))
    return;
  if ((x+width <= 0) || (x >= d_width))
    return;
  length = width;   /* Check that we dont draw past the image */
  if ((x+length) >= d_width)
    length = d_width-x;

  data = g_new (guchar, length * tile_height * drw->bpp);

  gimp_pixel_rgn_init (&rgn, drw, x, y, length, height, TRUE, FALSE);

  i = 0;
  while (i < height)
    {
      scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
      if (length == width)
644 645 646
        {
          memcpy (data, hole + 3*width*i, width*scan_lines*3);
        }
647
      else  /* We have to do some clipping */
648 649 650 651
        {
          for (j = 0; j < scan_lines; j++)
            memcpy (data + j*length*3, hole + (i+j)*width*3, length*3);
        }
652
      gimp_pixel_rgn_set_rect (&rgn, data, x, y+i, length, scan_lines);
Elliot Lee's avatar
Elliot Lee committed
653

654 655
      i += scan_lines;
    }
Elliot Lee's avatar
Elliot Lee committed
656

657
  g_free (data);
Elliot Lee's avatar
Elliot Lee committed
658 659 660 661 662
}

/* Draw the number of the picture onto the film */
static void
draw_number (gint32 layer_ID,
663 664 665 666 667
             gint   num,
             gint   x,
             gint   y,
             gint   height)
{
668
  gchar         buf[32];
669
  GimpDrawable *drw;
670 671 672 673 674
  gint          k, delta, max_delta;
  gint32        image_ID;
  gint32        text_layer_ID;
  gint          text_width, text_height, text_ascent, descent;
  gchar        *fontname = filmvals.number_font;
675 676 677 678

  g_snprintf (buf, sizeof (buf), "%d", num);

  drw = gimp_drawable_get (layer_ID);
679
  image_ID = gimp_item_get_image (layer_ID);
680 681 682 683 684 685

  max_delta = height / 10;
  if (max_delta < 1)
    max_delta = 1;

  /* Numbers dont need the descent. Inquire it and move the text down */
686 687 688 689 690
  for (k = 0; k < max_delta * 2 + 1; k++)
    {
      /* Try different font sizes if inquire of extent failed */
      gboolean success;

691
      delta = (k+1) / 2;
692 693

      if ((k & 1) == 0)
694
        delta = -delta;
695 696

      success = gimp_text_get_extents_fontname (buf,
697 698 699 700
                                                height + delta, GIMP_PIXELS,
                                                fontname,
                                                &text_width, &text_height,
                                                &text_ascent, &descent);
701 702

      if (success)
703 704 705 706
        {
          height += delta;
          break;
        }
707
    }
Elliot Lee's avatar
Elliot Lee committed
708

709
  text_layer_ID = gimp_text_fontname (image_ID, layer_ID,
710 711 712 713
                                      x, y + descent / 2,
                                      buf, 1, FALSE,
                                      height, GIMP_PIXELS,
                                      fontname);
714 715 716

  if (text_layer_ID == -1)
    g_message ("draw_number: Error in drawing text\n");
717 718

  gimp_drawable_detach (drw);
Elliot Lee's avatar
Elliot Lee committed
719 720 721 722
}

/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
static gint32
723
create_new_image (const gchar    *filename,
724 725
                  guint           width,
                  guint           height,
Sven Neumann's avatar
Sven Neumann committed
726
                  GimpImageType   gdtype,
727
                  gint32         *layer_ID,
728 729
                  GimpDrawable  **drawable,
                  GimpPixelRgn   *pixel_rgn)
Elliot Lee's avatar
Elliot Lee committed
730
{
731
  gint32            image_ID;
Sven Neumann's avatar
Sven Neumann committed
732
  GimpImageBaseType gitype;
Elliot Lee's avatar
Elliot Lee committed
733

Sven Neumann's avatar
Sven Neumann committed
734 735 736 737
  if ((gdtype == GIMP_GRAY_IMAGE) || (gdtype == GIMP_GRAYA_IMAGE))
    gitype = GIMP_GRAY;
  else if ((gdtype == GIMP_INDEXED_IMAGE) || (gdtype == GIMP_INDEXEDA_IMAGE))
    gitype = GIMP_INDEXED;
738
  else
Sven Neumann's avatar
Sven Neumann committed
739
    gitype = GIMP_RGB;
Elliot Lee's avatar
Elliot Lee committed
740

741 742
  image_ID = gimp_image_new (width, height, gitype);
  gimp_image_set_filename (image_ID, filename);
Elliot Lee's avatar
Elliot Lee committed
743

744
  gimp_image_undo_disable (image_ID);
745
  *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
746
                              gdtype, 100, GIMP_NORMAL_MODE);
747
  gimp_image_insert_layer (image_ID, *layer_ID, -1, 0);
Elliot Lee's avatar
Elliot Lee committed
748

749
  if (drawable)
750 751 752
    {
      *drawable = gimp_drawable_get (*layer_ID);
      if (pixel_rgn != NULL)
753 754
        gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
                             (*drawable)->height, TRUE, FALSE);
755
    }
Elliot Lee's avatar
Elliot Lee committed
756

757
  return image_ID;
Elliot Lee's avatar
Elliot Lee committed
758 759
}

760 761
static gchar *
compose_image_name (gint32 image_ID)
Elliot Lee's avatar
Elliot Lee committed
762
{
763 764
  gchar *image_name;
  gchar *name;
Elliot Lee's avatar
Elliot Lee committed
765

766
  /* Compose a name of the basename and the image-ID */
Elliot Lee's avatar
Elliot Lee committed
767

768 769 770
  name = gimp_image_get_name (image_ID);

  image_name = g_strdup_printf ("%s-%d", name, image_ID);
Elliot Lee's avatar
Elliot Lee committed
771

772
  g_free (name);
Elliot Lee's avatar
Elliot Lee committed
773

774
  return image_name;
Elliot Lee's avatar
Elliot Lee committed
775 776 777
}

static void
778 779
add_list_item_callback (GtkWidget        *widget,
                        GtkTreeSelection *sel)
Elliot Lee's avatar
Elliot Lee committed
780
{
781 782 783
  GtkTreeModel *model;
  GList        *paths;
  GList        *list;
Elliot Lee's avatar
Elliot Lee committed
784

785
  paths = gtk_tree_selection_get_selected_rows (sel, &model);
Elliot Lee's avatar
Elliot Lee committed
786

787
  for (list = paths; list; list = g_list_next (list))
788
    {
789 790 791 792
      GtkTreeIter iter;

      if (gtk_tree_model_get_iter (model, &iter, list->data))
        {
793
          gint32  image_ID;
794 795
          gchar  *name;

796 797 798 799
          gtk_tree_model_get (model, &iter,
                              0, &image_ID,
                              1, &name,
                              -1);
800

801 802
          gtk_list_store_append (GTK_LIST_STORE (filmint.image_list_film),
                                 &iter);
803

804 805 806 807 808
          gtk_list_store_set (GTK_LIST_STORE (filmint.image_list_film),
                              &iter,
                              0, image_ID,
                              1, name,
                              -1);
809

810
          g_free (name);
811
        }
812

813
      gtk_tree_path_free (list->data);
814
    }
815 816

  g_list_free (paths);
Elliot Lee's avatar
Elliot Lee committed
817 818 819
}

static void
820 821
del_list_item_callback (GtkWidget        *widget,
                        GtkTreeSelection *sel)
Elliot Lee's avatar
Elliot Lee committed
822
{
823 824 825 826
  GtkTreeModel *model;
  GList        *paths;
  GList        *references = NULL;
  GList        *list;
Elliot Lee's avatar
Elliot Lee committed
827

828
  paths = gtk_tree_selection_get_selected_rows (sel, &model);
Elliot Lee's avatar
Elliot Lee committed
829

830
  for (list = paths; list; list = g_list_next (list))
831
    {
832 833 834 835 836
      GtkTreeRowReference *ref;

      ref = gtk_tree_row_reference_new (model, list->data);
      references = g_list_prepend (references, ref);
      gtk_tree_path_free (list->data);
837
    }
Elliot Lee's avatar
Elliot Lee committed
838

839 840 841 842 843 844 845 846
  g_list_free (paths);

  for (list = references; list; list = g_list_next (list))
    {
      GtkTreePath *path;
      GtkTreeIter  iter;

      path = gtk_tree_row_reference_get_path (list->data);
Elliot Lee's avatar
Elliot Lee committed
847

848 849 850 851 852 853
      if (gtk_tree_model_get_iter (model, &iter, path))
        gtk_list_store_remove (GTK_LIST_STORE (model), &iter);

      gtk_tree_path_free (path);
      gtk_tree_row_reference_free (list->data);
    }
Elliot Lee's avatar
Elliot Lee committed
854

855
  g_list_free (references);
Elliot Lee's avatar
Elliot Lee committed
856 857
}

858
static GtkTreeModel *
859
add_image_list (gboolean   add_box_flag,
860 861 862
                gint       n,
                gint32    *image_id,
                GtkWidget *hbox)
Elliot Lee's avatar
Elliot Lee committed
863
{
864 865 866 867 868 869 870 871
  GtkWidget        *vbox;
  GtkWidget        *label;
  GtkWidget        *scrolled_win;
  GtkWidget        *tv;
  GtkWidget        *button;
  GtkListStore     *store;
  GtkTreeSelection *sel;
  gint              i;
Elliot Lee's avatar
Elliot Lee committed
872

873
  vbox = gtk_vbox_new (FALSE, 12);
874 875
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
  gtk_widget_show (vbox);
Elliot Lee's avatar
Elliot Lee committed
876

877
  label = gtk_label_new (add_box_flag ?
878 879
                         _("Available images:") :
                         _("On film:"));
Elliot Lee's avatar
Elliot Lee committed
880
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
881
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
882 883 884
  gtk_widget_show (label);

  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
885 886
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win),
                                       GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
887 888
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
889
  gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
Elliot Lee's avatar
Elliot Lee committed
890 891
  gtk_widget_show (scrolled_win);

892 893 894 895 896 897 898 899
  store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
  tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
  g_object_unref (store);

  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), FALSE);

  if (! add_box_flag)
    gtk_tree_view_set_reorderable (GTK_TREE_VIEW (tv), TRUE);
Elliot Lee's avatar
Elliot Lee committed
900

901 902 903 904 905 906 907 908 909 910
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv), 0, NULL,
                                               gtk_cell_renderer_text_new (),
                                               "text", 1,
                                               NULL);

  gtk_container_add (GTK_CONTAINER (scrolled_win), tv);
  gtk_widget_show (tv);

  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
  gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
911

Elliot Lee's avatar
Elliot Lee committed
912
  for (i = 0; i < n; i++)
913
    {
914 915
      GtkTreeIter  iter;
      gchar       *name;
916

917
      gtk_list_store_append (store, &iter);
918

919 920 921 922 923 924
      name = compose_image_name (image_id[i]);

      gtk_list_store_set (store, &iter,
                          0, image_id[i],
                          1, name,
                          -1);
Elliot Lee's avatar
Elliot Lee committed
925

926
      g_free (name);
927
    }
Elliot Lee's avatar
Elliot Lee committed
928

929 930
  button = gtk_button_new_from_stock (add_box_flag ?
                                      GTK_STOCK_ADD : GTK_STOCK_REMOVE);
931
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
932 933
  gtk_widget_show (button);

934
  g_signal_connect (button, "clicked",
935 936 937
                    add_box_flag ?
                    G_CALLBACK (add_list_item_callback) :
                    G_CALLBACK (del_list_item_callback),
938
                    sel);
939

940
  return GTK_TREE_MODEL (store);
Elliot Lee's avatar
Elliot Lee committed
941 942
}

943
static void
944
create_selection_tab (GtkWidget *notebook,
945
                      gint32     image_ID)
Elliot Lee's avatar
Elliot Lee committed
946
{
947 948 949 950 951 952 953 954 955 956 957
  GtkSizeGroup *group;
  GtkWidget    *vbox;
  GtkWidget    *vbox2;
  GtkWidget    *hbox;
  GtkWidget    *table;
  GtkWidget    *label;
  GtkWidget    *frame;
  GtkWidget    *toggle;
  GtkWidget    *spinbutton;
  GtkObject    *adj;
  GtkWidget    *button;
958
  GtkWidget    *font_button;
959 960 961 962 963
  gint32       *image_id_list;
  gint          nimages, j;

  hbox = gtk_hbox_new (FALSE, 12);
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
964
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), hbox,
965
                            gtk_label_new_with_mnemonic (_("Selection")));
Elliot Lee's avatar
Elliot Lee committed
966 967
  gtk_widget_show (hbox);

968
  vbox2 = gtk_vbox_new (FALSE, 12);
969 970
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
  gtk_widget_show (vbox2);
Elliot Lee's avatar
Elliot Lee committed
971

972 973
  group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);

Elliot Lee's avatar
Elliot Lee committed
974
  /* Film height/colour */
975
  frame = gimp_frame_new (_("Filmstrip"));
976
  gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
977
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
978

979
  vbox = gtk_vbox_new (FALSE, 6);
Elliot Lee's avatar
Elliot Lee committed
980
  gtk_container_add (GTK_CONTAINER (frame), vbox);
981
  gtk_widget_show (vbox);
Elliot Lee's avatar
Elliot Lee committed
982

983
  /* Keep maximum image height */
984
  toggle = gtk_check_button_new_with_mnemonic (_("_Fit height to images"));
985
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
986 987
  gtk_widget_show (toggle);

988
  g_signal_connect (toggle, "toggled",
989 990 991
                    G_CALLBACK (gimp_toggle_button_update),
                    &filmvals.keep_height);

Elliot Lee's avatar
Elliot Lee committed
992
  table = gtk_table_new (2, 2, FALSE);
993 994
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
995
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
996 997 998
  gtk_widget_show (table);

  /* Film height */
999
  spinbutton = gimp_spin_button_new (&adj, filmvals.film_height, 10,
1000
                                     GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 0);
1001 1002 1003 1004 1005
  label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
                                     _("_Height:"), 0.0, 0.5,
                                     spinbutton, 1, TRUE);
  gtk_size_group_add_widget (group, label);
  g_object_unref (group);
1006

1007
  g_signal_connect (adj, "value-changed",
1008 1009 1010 1011 1012 1013
                    G_CALLBACK (gimp_int_adjustment_update),
                    &filmvals.film_height);

  g_object_set_data (G_OBJECT (toggle), "inverse_sensitive", spinbutton);
  g_object_set_data
    (G_OBJECT (spinbutton), "inverse_sensitive",
1014
     /* FIXME: eeeeeek */
1015
     g_list_nth_data (gtk_container_get_children (GTK_CONTAINER (table)), 1));
1016
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1017
                                filmvals.keep_height);
Elliot Lee's avatar
Elliot Lee committed
1018

1019 1020
  /* Film color */
  button = gimp_color_button_new (_("Select Film Color"),
1021 1022 1023
                                  COLOR_BUTTON_WIDTH, COLOR_BUTTON_HEIGHT,
                                  &filmvals.film_color,
                                  GIMP_COLOR_AREA_FLAT);
1024 1025 1026 1027
  label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
                                     _("Co_lor:"), 0.0, 0.5,
                                     button, 1, FALSE);
  gtk_size_group_add_widget (group, label);
Elliot Lee's avatar
Elliot Lee committed
1028

1029
  g_signal_connect (button, "color-changed",
1030 1031 1032
                    G_CALLBACK (gimp_color_button_get_color),
                    &filmvals.film_color);

Elliot Lee's avatar
Elliot Lee committed
1033
  /* Film numbering: Startindex/Font/colour */
1034
  frame = gimp_frame_new (_("Numbering"));
1035
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, 0);
1036
  gtk_widget_show (frame);
1037