PIKApp/plug-ins/pikaressionist/sizemap.c

557 lines
17 KiB
C

/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "pikaressionist.h"
#include "ppmtool.h"
#include "size.h"
#include "infile.h"
#include "preview.h"
#include "libpika/stdplugins-intl.h"
#define RESPONSE_APPLY 1
#define MAPFILE "data.out"
static GtkWidget *smwindow;
static GtkWidget *smvectorprev;
static GtkWidget *smpreviewprev;
static GtkWidget *prev_button;
static GtkWidget *next_button;
static GtkWidget *add_button;
static GtkWidget *kill_button;
static GtkAdjustment *smvectprevbrightadjust = NULL;
static GtkWidget *sizadjust = NULL;
static GtkWidget *smstradjust = NULL;
static GtkWidget *smstrexpadjust = NULL;
static GtkWidget *size_voronoi = NULL;
#define OMWIDTH 150
#define OMHEIGHT 150
static smvector_t smvector[MAXSIZEVECT];
static int numsmvect = 0;
static double
getsiz_from_gui (double x, double y)
{
return getsiz_proto (x,y, numsmvect, smvector,
pika_label_spin_get_value (PIKA_LABEL_SPIN (smstrexpadjust)),
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (size_voronoi)));
}
static void
updatesmpreviewprev (void)
{
gint x, y;
static ppm_t nsbuffer;
guchar black[3] = {0, 0, 0};
guchar gray[3] = {120, 120, 120};
if (! PPM_IS_INITED (&nsbuffer))
{
ppm_new (&nsbuffer, OMWIDTH, OMHEIGHT);
}
fill (&nsbuffer, black);
for (y = 6; y < OMHEIGHT-4; y += 10)
{
for (x = 6; x < OMWIDTH-4; x += 10)
{
gdouble siz = 5 * getsiz_from_gui (x / (double)OMWIDTH,
y / (double)OMHEIGHT);
ppm_drawline (&nsbuffer, x-siz, y-siz, x+siz, y-siz, gray);
ppm_drawline (&nsbuffer, x+siz, y-siz, x+siz, y+siz, gray);
ppm_drawline (&nsbuffer, x+siz, y+siz, x-siz, y+siz, gray);
ppm_drawline (&nsbuffer, x-siz, y+siz, x-siz, y-siz, gray);
}
}
pika_preview_area_draw (PIKA_PREVIEW_AREA (smpreviewprev),
0, 0, OMWIDTH, OMHEIGHT,
PIKA_RGB_IMAGE,
nsbuffer.col,
OMWIDTH * 3);
}
static gint selectedsmvector = 0;
static ppm_t update_vector_preview_backup = {0,0,NULL};
static ppm_t update_vector_preview_sbuffer = {0,0,NULL};
static void
updatesmvectorprev (void)
{
static int ok = 0;
gint i, x, y;
gdouble val;
static gdouble last_val = 0.0;
guchar gray[3] = {120, 120, 120};
guchar red[3] = {255, 0, 0};
guchar white[3] = {255, 255, 255};
if (smvectprevbrightadjust)
val = 1.0 - gtk_adjustment_get_value (smvectprevbrightadjust) / 100.0;
else
val = 0.5;
if (!ok || (val != last_val))
{
#if 0
if (!PPM_IS_INITED (&infile))
updatepreview (NULL, (void *)2); /* Force grabarea () */
ppm_copy (&infile, &update_vector_preview_backup);
#else
infile_copy_to_ppm (&update_vector_preview_backup);
#endif
ppm_apply_brightness (&update_vector_preview_backup, val, 1,1,1);
if (update_vector_preview_backup.width != OMWIDTH ||
update_vector_preview_backup.height != OMHEIGHT)
resize_fast (&update_vector_preview_backup, OMWIDTH, OMHEIGHT);
ok = 1;
}
ppm_copy (&update_vector_preview_backup, &update_vector_preview_sbuffer);
for (i = 0; i < numsmvect; i++)
{
x = smvector[i].x * OMWIDTH;
y = smvector[i].y * OMHEIGHT;
if (i == selectedsmvector)
{
ppm_drawline (&update_vector_preview_sbuffer, x-5, y, x+5, y, red);
ppm_drawline (&update_vector_preview_sbuffer, x, y-5, x, y+5, red);
}
else
{
ppm_drawline (&update_vector_preview_sbuffer, x-5, y, x+5, y, gray);
ppm_drawline (&update_vector_preview_sbuffer, x, y-5, x, y+5, gray);
}
ppm_put_rgb (&update_vector_preview_sbuffer, x, y, white);
}
pika_preview_area_draw (PIKA_PREVIEW_AREA (smvectorprev),
0, 0, OMWIDTH, OMHEIGHT,
PIKA_RGB_IMAGE,
update_vector_preview_sbuffer.col,
OMWIDTH * 3);
gtk_widget_set_sensitive (prev_button, (numsmvect > 1));
gtk_widget_set_sensitive (next_button, (numsmvect > 1));
gtk_widget_set_sensitive (add_button, (numsmvect < MAXORIENTVECT));
gtk_widget_set_sensitive (kill_button, (numsmvect > 1));
}
void
size_map_free_resources (void)
{
ppm_kill (&update_vector_preview_backup);
ppm_kill (&update_vector_preview_sbuffer);
}
static gboolean smadjignore = FALSE;
static void
updatesmsliders (void)
{
smadjignore = TRUE;
pika_label_spin_set_value (PIKA_LABEL_SPIN (sizadjust), smvector[selectedsmvector].siz);
pika_label_spin_set_value (PIKA_LABEL_SPIN (smstradjust), smvector[selectedsmvector].str);
smadjignore = FALSE;
}
static void
smprevclick (GtkWidget *w, gpointer data)
{
selectedsmvector--;
if (selectedsmvector < 0)
selectedsmvector = numsmvect-1;
updatesmsliders ();
updatesmvectorprev ();
}
static void
smnextclick (GtkWidget *w, gpointer data)
{
selectedsmvector++;
if (selectedsmvector == numsmvect)
selectedsmvector = 0;
updatesmsliders ();
updatesmvectorprev ();
}
static void
smaddclick (GtkWidget *w, gpointer data)
{
smvector[numsmvect].x = 0.5;
smvector[numsmvect].y = 0.5;
smvector[numsmvect].siz = 50.0;
smvector[numsmvect].str = 1.0;
selectedsmvector = numsmvect;
numsmvect++;
updatesmsliders ();
updatesmvectorprev ();
updatesmpreviewprev ();
}
static void
smdeleteclick (GtkWidget *w, gpointer data)
{
int i;
for (i = selectedsmvector; i < numsmvect-1; i++)
{
smvector[i] = smvector[i+1];
}
numsmvect--;
if (selectedsmvector >= numsmvect)
selectedsmvector = 0;
updatesmsliders ();
updatesmvectorprev ();
updatesmpreviewprev ();
}
static void
smmapclick (GtkWidget *w, GdkEventButton *event)
{
if (event->button == 1)
{
smvector[selectedsmvector].x = event->x / (double)OMWIDTH;
smvector[selectedsmvector].y = event->y / (double)OMHEIGHT;
}
else if (event->button == 2)
{
if (numsmvect + 1 == MAXSIZEVECT)
return;
smvector[numsmvect].x = event->x / (double)OMWIDTH;
smvector[numsmvect].y = event->y / (double)OMHEIGHT;
smvector[numsmvect].siz = 0.0;
smvector[numsmvect].str = 1.0;
selectedsmvector = numsmvect;
numsmvect++;
updatesmsliders ();
}
#if 0
else if (event->button == 3)
{
double d;
d = atan2 (OMWIDTH * smvector[selectedsmvector].x - event->x,
OMHEIGHT * smvector[selectedsmvector].y - event->y);
smvector[selectedsmvector].dir = radtodeg (d);
updatesmsliders ();
*/
}
#endif
updatesmvectorprev ();
updatesmpreviewprev ();
}
static void
angsmadjmove (GtkWidget *w, gpointer data)
{
if (!smadjignore)
{
smvector[selectedsmvector].siz = pika_label_spin_get_value (PIKA_LABEL_SPIN (sizadjust));
updatesmvectorprev ();
updatesmpreviewprev ();
}
}
static void
strsmadjmove (GtkWidget *w, gpointer data)
{
if (!smadjignore)
{
smvector[selectedsmvector].str = pika_label_spin_get_value (PIKA_LABEL_SPIN (smstradjust));
updatesmvectorprev ();
updatesmpreviewprev ();
}
}
static void
smstrexpsmadjmove (GtkWidget *w, gpointer data)
{
if (!smadjignore)
{
updatesmvectorprev ();
updatesmpreviewprev ();
}
}
static void
smresponse (GtkWidget *widget,
gint response_id,
gpointer data)
{
switch (response_id)
{
case RESPONSE_APPLY:
case GTK_RESPONSE_OK:
{
gint i;
for (i = 0; i < numsmvect; i++)
pcvals.size_vectors[i] = smvector[i];
pcvals.num_size_vectors = numsmvect;
pcvals.size_strength_exponent = pika_label_spin_get_value (PIKA_LABEL_SPIN (smstrexpadjust));
pcvals.size_voronoi = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (size_voronoi));
}
break;
}
if (response_id != RESPONSE_APPLY)
gtk_widget_hide (widget);
}
static void
initsmvectors (void)
{
if (pcvals.num_size_vectors)
{
gint i;
numsmvect = pcvals.num_size_vectors;
for (i = 0; i < numsmvect; i++)
{
smvector[i] = pcvals.size_vectors[i];
}
}
else
{
/* Shouldn't happen */
numsmvect = 1;
smvector[0].x = 0.5;
smvector[0].y = 0.5;
smvector[0].siz = 0.0;
smvector[0].str = 1.0;
}
if (selectedsmvector >= numsmvect)
selectedsmvector = numsmvect-1;
}
#if 0
static void
update_sizemap_dialog (void)
{
if (smwindow)
{
initsmvectors ();
gtk_adjustment_set_value (smstrexpadjust, pcvals.size_strength_exponent);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_voronoi),
pcvals.size_voronoi);
updatesmvectorprev ();
updatesmpreviewprev ();
}
}
#endif
void
create_sizemap_dialog (GtkWidget *parent)
{
GtkWidget *tmpw, *tmpw2;
GtkWidget *grid1;
GtkWidget *grid2;
GtkWidget *hbox;
initsmvectors ();
if (smwindow)
{
updatesmvectorprev ();
updatesmpreviewprev ();
gtk_window_present (GTK_WINDOW (smwindow));
return;
}
smwindow = pika_dialog_new (_("Size Map Editor"), PLUG_IN_ROLE,
gtk_widget_get_toplevel (parent), 0,
pika_standard_help_func, PLUG_IN_PROC,
_("_Apply"), RESPONSE_APPLY,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (smwindow),
GTK_RESPONSE_OK,
RESPONSE_APPLY,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (smwindow, "response",
G_CALLBACK (smresponse),
NULL);
g_signal_connect (smwindow, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&smwindow);
grid1 = gtk_grid_new ();
gtk_container_set_border_width (GTK_CONTAINER (grid1), 6);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (smwindow))),
grid1, TRUE, TRUE, 0);
gtk_widget_show (grid1);
tmpw2 = tmpw = gtk_frame_new (_("Smvectors"));
gtk_container_set_border_width (GTK_CONTAINER (tmpw), 2);
gtk_grid_attach (GTK_GRID (grid1), tmpw, 0, 0, 1, 1);
gtk_widget_show (tmpw);
tmpw = hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,0);
gtk_container_add (GTK_CONTAINER (tmpw2), tmpw);
gtk_widget_show (tmpw);
tmpw = gtk_event_box_new ();
pika_help_set_help_data (tmpw, _("The smvector-field. Left-click to move selected smvector, Right-click to point it towards mouse, Middle-click to add a new smvector."), NULL);
gtk_box_pack_start (GTK_BOX (hbox), tmpw, FALSE, FALSE, 0);
tmpw2 = tmpw;
tmpw = smvectorprev = pika_preview_area_new ();
gtk_widget_set_size_request (tmpw, OMWIDTH, OMHEIGHT);
gtk_container_add (GTK_CONTAINER (tmpw2), tmpw);
gtk_widget_show (tmpw);
gtk_widget_add_events (tmpw2, GDK_BUTTON_PRESS_MASK);
g_signal_connect (tmpw2, "button-press-event",
G_CALLBACK (smmapclick), NULL);
gtk_widget_show (tmpw2);
smvectprevbrightadjust =
gtk_adjustment_new (50.0, 0.0, 100.0, 1.0, 1.0, 1.0);
tmpw = gtk_scale_new (GTK_ORIENTATION_VERTICAL, smvectprevbrightadjust);
gtk_scale_set_draw_value (GTK_SCALE (tmpw), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), tmpw,FALSE,FALSE,0);
gtk_widget_show (tmpw);
g_signal_connect (smvectprevbrightadjust, "value-changed",
G_CALLBACK (updatesmvectorprev), NULL);
pika_help_set_help_data (tmpw, _("Adjust the preview's brightness"), NULL);
tmpw2 = tmpw = gtk_frame_new (_("Preview"));
gtk_container_set_border_width (GTK_CONTAINER (tmpw), 2);
gtk_grid_attach (GTK_GRID (grid1), tmpw, 1, 0, 1, 1);
gtk_widget_show (tmpw);
tmpw = smpreviewprev = pika_preview_area_new ();
gtk_widget_set_size_request (tmpw, OMWIDTH, OMHEIGHT);
gtk_container_add (GTK_CONTAINER (tmpw2), tmpw);
gtk_widget_show (tmpw);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
gtk_grid_attach (GTK_GRID (grid1), hbox, 0, 1, 1, 1);
gtk_widget_show (hbox);
prev_button = tmpw = gtk_button_new_with_mnemonic ("_<<");
gtk_box_pack_start (GTK_BOX (hbox), tmpw, FALSE, TRUE, 0);
gtk_widget_show (tmpw);
g_signal_connect (tmpw, "clicked",
G_CALLBACK (smprevclick), NULL);
pika_help_set_help_data (tmpw, _("Select previous smvector"), NULL);
next_button = tmpw = gtk_button_new_with_mnemonic ("_>>");
gtk_box_pack_start (GTK_BOX (hbox),tmpw,FALSE,TRUE,0);
gtk_widget_show (tmpw);
g_signal_connect (tmpw, "clicked",
G_CALLBACK (smnextclick), NULL);
pika_help_set_help_data (tmpw, _("Select next smvector"), NULL);
add_button = tmpw = gtk_button_new_with_mnemonic ( _("A_dd"));
gtk_box_pack_start (GTK_BOX (hbox),tmpw,FALSE,TRUE,0);
gtk_widget_show (tmpw);
g_signal_connect (tmpw, "clicked",
G_CALLBACK (smaddclick), NULL);
pika_help_set_help_data (tmpw, _("Add new smvector"), NULL);
kill_button = tmpw = gtk_button_new_with_mnemonic (_("_Kill"));
gtk_box_pack_start (GTK_BOX (hbox),tmpw,FALSE,TRUE,0);
gtk_widget_show (tmpw);
g_signal_connect (tmpw, "clicked",
G_CALLBACK (smdeleteclick), NULL);
pika_help_set_help_data (tmpw, _("Delete selected smvector"), NULL);
grid2 = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid2), 4);
gtk_grid_attach (GTK_GRID (grid1), grid2, 0, 2, 2, 1);
gtk_widget_show (grid2);
sizadjust =
pika_scale_entry_new (_("_Size:"), 50.0, 0.0, 100.0, 1);
pika_help_set_help_data (sizadjust,
_("Change the angle of the selected smvector"),
NULL);
g_signal_connect (sizadjust, "value-changed",
G_CALLBACK (angsmadjmove), NULL);
gtk_grid_attach (GTK_GRID (grid2), sizadjust, 0, 0, 3, 1);
gtk_widget_show (sizadjust);
smstradjust =
pika_scale_entry_new (_("S_trength:"), 1.0, 0.1, 5.0, 1);
pika_label_spin_set_increments (PIKA_LABEL_SPIN (smstradjust), 0.1, 0.5);
pika_help_set_help_data (smstradjust,
_("Change the strength of the selected smvector"),
NULL);
g_signal_connect (smstradjust, "value-changed",
G_CALLBACK (strsmadjmove), NULL);
gtk_grid_attach (GTK_GRID (grid2), smstradjust, 0, 1, 3, 1);
gtk_widget_show (smstradjust);
smstrexpadjust =
pika_scale_entry_new (_("St_rength exp.:"), 1.0, 0.1, 10.9, 1);
pika_label_spin_set_increments (PIKA_LABEL_SPIN (smstradjust), 0.1, 0.5);
pika_help_set_help_data (smstrexpadjust,
_("Change the exponent of the strength"),
NULL);
g_signal_connect (smstrexpadjust, "value-changed",
G_CALLBACK (smstrexpsmadjmove), NULL);
gtk_grid_attach (GTK_GRID (grid2), smstrexpadjust, 0, 2, 3, 1);
gtk_widget_show (smstrexpadjust);
size_voronoi = tmpw = gtk_check_button_new_with_mnemonic ( _("_Voronoi"));
gtk_grid_attach (GTK_GRID (grid2), tmpw, 3, 0, 1, 1);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tmpw), FALSE);
gtk_widget_show (tmpw);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tmpw), pcvals.size_voronoi);
g_signal_connect (tmpw, "clicked",
G_CALLBACK (smstrexpsmadjmove), NULL);
pika_help_set_help_data (tmpw, _("Voronoi-mode makes only the smvector closest to the given point have any influence"), NULL);
gtk_widget_show (smwindow);
updatesmvectorprev ();
updatesmpreviewprev ();
}