Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

797
app/dialogs/about-dialog.c Normal file
View File

@ -0,0 +1,797 @@
/* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "about.h"
#include "git-version.h"
#include "about-dialog.h"
#include "authors.h"
#include "pika-update.h"
#include "pika-version.h"
#include "pika-intl.h"
/* The first authors are the creators and maintainers, don't shuffle
* them
*/
#define START_INDEX (G_N_ELEMENTS (creators) - 1 /*NULL*/ + \
G_N_ELEMENTS (maintainers) - 1 /*NULL*/)
typedef struct
{
GtkWidget *dialog;
GtkWidget *update_frame;
PikaCoreConfig *config;
GtkWidget *anim_area;
PangoLayout *layout;
gint n_authors;
gint shuffle[G_N_ELEMENTS (authors) - 1]; /* NULL terminated */
guint timer;
gint index;
gint animstep;
gint state;
gboolean visible;
} PikaAboutDialog;
static void about_dialog_map (GtkWidget *widget,
PikaAboutDialog *dialog);
static void about_dialog_unmap (GtkWidget *widget,
PikaAboutDialog *dialog);
static GdkPixbuf * about_dialog_load_logo (void);
static void about_dialog_add_animation (GtkWidget *vbox,
PikaAboutDialog *dialog);
static void about_dialog_add_update (PikaAboutDialog *dialog,
PikaCoreConfig *config);
static gboolean about_dialog_anim_draw (GtkWidget *widget,
cairo_t *cr,
PikaAboutDialog *dialog);
static void about_dialog_reshuffle (PikaAboutDialog *dialog);
static gboolean about_dialog_timer (gpointer data);
#ifdef PIKA_UNSTABLE
static void about_dialog_add_unstable_message
(GtkWidget *vbox);
#endif /* PIKA_UNSTABLE */
static void about_dialog_last_release_changed
(PikaCoreConfig *config,
const GParamSpec *pspec,
PikaAboutDialog *dialog);
static void about_dialog_download_clicked
(GtkButton *button,
const gchar *link);
GtkWidget *
about_dialog_create (PikaCoreConfig *config)
{
static PikaAboutDialog dialog;
if (! dialog.dialog)
{
GtkWidget *widget;
GtkWidget *container;
GdkPixbuf *pixbuf;
GList *children;
gchar *copyright;
gchar *version;
dialog.n_authors = G_N_ELEMENTS (authors) - 1;
dialog.config = config;
pixbuf = about_dialog_load_logo ();
copyright = g_strdup_printf (PIKA_COPYRIGHT, PIKA_GIT_LAST_COMMIT_YEAR);
if (pika_version_get_revision () > 0)
/* Translators: the %s is PIKA version, the %d is the
* installer/package revision.
* For instance: "2.10.18 (revision 2)"
*/
version = g_strdup_printf (_("%s (revision %d)"), PIKA_VERSION,
pika_version_get_revision ());
else
version = g_strdup (PIKA_VERSION);
widget = g_object_new (GTK_TYPE_ABOUT_DIALOG,
"role", "pika-about",
"window-position", GTK_WIN_POS_CENTER,
"title", _("About PIKA"),
"program-name", PIKA_ACRONYM,
"version", version,
"copyright", copyright,
"comments", PIKA_NAME,
"license", PIKA_LICENSE,
"wrap-license", TRUE,
"logo", pixbuf,
"website", "https://heckin.technology/AlderconeStudio/PIKApp/",
"website-label", _("Visit the PIKA website"),
"authors", authors,
"artists", artists,
"documenters", documenters,
/* Translators: insert your names here,
separated by newline */
"translator-credits", _("translator-credits"),
NULL);
if (pixbuf)
g_object_unref (pixbuf);
g_free (copyright);
g_free (version);
g_set_weak_pointer (&dialog.dialog, widget);
g_signal_connect (widget, "response",
G_CALLBACK (gtk_widget_destroy),
NULL);
g_signal_connect (widget, "map",
G_CALLBACK (about_dialog_map),
&dialog);
g_signal_connect (widget, "unmap",
G_CALLBACK (about_dialog_unmap),
&dialog);
/* kids, don't try this at home! */
container = gtk_dialog_get_content_area (GTK_DIALOG (widget));
children = gtk_container_get_children (GTK_CONTAINER (container));
if (GTK_IS_BOX (children->data))
{
about_dialog_add_animation (children->data, &dialog);
#ifdef PIKA_UNSTABLE
about_dialog_add_unstable_message (children->data);
#endif /* PIKA_UNSTABLE */
about_dialog_add_update (&dialog, config);
}
else
g_warning ("%s: ooops, no box in this container?", G_STRLOC);
g_list_free (children);
}
return dialog.dialog;
}
static void
about_dialog_map (GtkWidget *widget,
PikaAboutDialog *dialog)
{
pika_update_refresh (dialog->config);
if (dialog->layout && dialog->timer == 0)
{
dialog->state = 0;
dialog->index = 0;
dialog->animstep = 0;
dialog->visible = FALSE;
about_dialog_reshuffle (dialog);
dialog->timer = g_timeout_add (800, about_dialog_timer, dialog);
}
}
static void
about_dialog_unmap (GtkWidget *widget,
PikaAboutDialog *dialog)
{
if (dialog->timer)
{
g_source_remove (dialog->timer);
dialog->timer = 0;
}
}
static GdkPixbuf *
about_dialog_load_logo (void)
{
GdkPixbuf *pixbuf = NULL;
GFile *file;
GInputStream *input;
file = pika_data_directory_file ("images",
#ifdef PIKA_UNSTABLE
"pika-devel-logo.png",
#else
"pika-logo.png",
#endif
NULL);
input = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
g_object_unref (file);
if (input)
{
pixbuf = gdk_pixbuf_new_from_stream (input, NULL, NULL);
g_object_unref (input);
}
return pixbuf;
}
static void
about_dialog_add_animation (GtkWidget *vbox,
PikaAboutDialog *dialog)
{
gint height;
dialog->anim_area = gtk_drawing_area_new ();
gtk_box_pack_start (GTK_BOX (vbox), dialog->anim_area, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (vbox), dialog->anim_area, 5);
gtk_widget_show (dialog->anim_area);
dialog->layout = gtk_widget_create_pango_layout (dialog->anim_area, NULL);
g_object_weak_ref (G_OBJECT (dialog->anim_area),
(GWeakNotify) g_object_unref, dialog->layout);
pango_layout_get_pixel_size (dialog->layout, NULL, &height);
gtk_widget_set_size_request (dialog->anim_area, -1, 2 * height);
g_signal_connect (dialog->anim_area, "draw",
G_CALLBACK (about_dialog_anim_draw),
dialog);
}
static void
about_dialog_add_update (PikaAboutDialog *dialog,
PikaCoreConfig *config)
{
GtkWidget *container;
GList *children;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *box;
GtkWidget *box2;
GtkWidget *label;
GtkWidget *button;
GtkWidget *button_image;
GtkWidget *button_label;
GDateTime *datetime;
gchar *date;
gchar *text;
if (dialog->update_frame)
{
gtk_widget_destroy (dialog->update_frame);
dialog->update_frame = NULL;
}
/* Get the dialog vbox. */
container = gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog));
children = gtk_container_get_children (GTK_CONTAINER (container));
g_return_if_fail (GTK_IS_BOX (children->data));
vbox = children->data;
g_list_free (children);
/* The update frame. */
frame = gtk_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 2);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), box);
/* Button in the frame. */
button = gtk_button_new ();
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
gtk_widget_show (button);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add (GTK_CONTAINER (button), box2);
gtk_widget_show (box2);
button_image = gtk_image_new_from_icon_name (NULL, GTK_ICON_SIZE_DIALOG);
gtk_box_pack_start (GTK_BOX (box2), button_image, FALSE, FALSE, 0);
gtk_widget_show (button_image);
button_label = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (box2), button_label, FALSE, FALSE, 0);
gtk_container_child_set (GTK_CONTAINER (box2), button_label, "expand", TRUE, NULL);
gtk_widget_show (button_label);
if (config->last_known_release != NULL)
{
/* There is a newer version. */
const gchar *download_url = NULL;
gchar *comment = NULL;
/* We want the frame to stand out. */
label = gtk_label_new (NULL);
text = g_strdup_printf ("<tt><b><big>%s</big></b></tt>",
_("Update available!"));
gtk_label_set_markup (GTK_LABEL (label), text);
g_free (text);
gtk_widget_show (label);
gtk_frame_set_label_widget (GTK_FRAME (frame), label);
gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
gtk_box_reorder_child (GTK_BOX (vbox), frame, 3);
/* Button is an update link. */
gtk_image_set_from_icon_name (GTK_IMAGE (button_image),
"software-update-available",
GTK_ICON_SIZE_DIALOG);
#ifdef PIKA_UNSTABLE
download_url = "https://heckin.technology/AlderconeStudio/PIKApp/downloads/devel/";
#else
download_url = "https://heckin.technology/AlderconeStudio/PIKApp/downloads/";
#endif
g_signal_connect (button, "clicked",
(GCallback) about_dialog_download_clicked,
(gpointer) download_url);
/* The preferred localized date representation without the time. */
datetime = g_date_time_new_from_unix_local (config->last_release_timestamp);
date = g_date_time_format (datetime, "%x");
g_date_time_unref (datetime);
if (config->last_revision > 0)
{
/* This is actually a new revision of current version. */
text = g_strdup_printf (_("Download PIKA %s revision %d (released on %s)\n"),
config->last_known_release,
config->last_revision,
date);
/* Finally an optional release comment. */
if (config->last_release_comment)
{
/* Translators: <> tags are Pango markup. Please keep these
* markups in your translation. */
comment = g_strdup_printf (_("<u>Release comment</u>: <i>%s</i>"), config->last_release_comment);
}
}
else
{
text = g_strdup_printf (_("Download PIKA %s (released on %s)\n"),
config->last_known_release, date);
}
gtk_label_set_text (GTK_LABEL (button_label), text);
g_free (text);
g_free (date);
if (comment)
{
label = gtk_label_new (NULL);
gtk_label_set_max_width_chars (GTK_LABEL (label), 80);
gtk_label_set_markup (GTK_LABEL (label), comment);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
g_free (comment);
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
gtk_widget_show (label);
}
}
else
{
/* Button is a "Check for updates" action. */
gtk_image_set_from_icon_name (GTK_IMAGE (button_image),
"view-refresh",
GTK_ICON_SIZE_MENU);
gtk_label_set_text (GTK_LABEL (button_label), _("Check for updates"));
g_signal_connect_swapped (button, "clicked",
(GCallback) pika_update_check, config);
}
gtk_box_reorder_child (GTK_BOX (vbox), frame, 4);
/* Last check date box. */
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
if (config->last_known_release != NULL)
gtk_widget_set_margin_top (box2, 20);
gtk_container_add (GTK_CONTAINER (box), box2);
gtk_widget_show (box2);
/* Show a small "Check for updates" button only if the big one has
* been replaced by a download button.
*/
if (config->last_known_release != NULL)
{
button = gtk_button_new_from_icon_name ("view-refresh", GTK_ICON_SIZE_MENU);
gtk_widget_set_tooltip_text (button, _("Check for updates"));
gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 0);
g_signal_connect_swapped (button, "clicked",
(GCallback) pika_update_check, config);
gtk_widget_show (button);
}
if (config->check_update_timestamp > 0)
{
gchar *subtext;
gchar *time;
datetime = g_date_time_new_from_unix_local (config->check_update_timestamp);
date = g_date_time_format (datetime, "%x");
time = g_date_time_format (datetime, "%X");
/* Translators: first string is the date in the locale's date
* representation (e.g., 12/31/99), second is the time in the
* locale's time representation (e.g., 23:13:48).
*/
subtext = g_strdup_printf (_("Last checked on %s at %s"), date, time);
g_date_time_unref (datetime);
g_free (date);
g_free (time);
text = g_strdup_printf ("<i>%s</i>", subtext);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), text);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
gtk_container_child_set (GTK_CONTAINER (box2), label, "expand", TRUE, NULL);
gtk_widget_show (label);
g_free (text);
g_free (subtext);
}
gtk_widget_show (box);
gtk_widget_show (frame);
g_set_weak_pointer (&dialog->update_frame, frame);
/* Reconstruct the dialog when release info changes. */
g_signal_connect (config, "notify::last-known-release",
(GCallback) about_dialog_last_release_changed,
dialog);
}
static void
about_dialog_reshuffle (PikaAboutDialog *dialog)
{
GRand *gr = g_rand_new ();
gint i;
for (i = 0; i < dialog->n_authors; i++)
dialog->shuffle[i] = i;
for (i = START_INDEX; i < dialog->n_authors; i++)
{
gint j = g_rand_int_range (gr, START_INDEX, dialog->n_authors);
if (i != j)
{
gint t;
t = dialog->shuffle[j];
dialog->shuffle[j] = dialog->shuffle[i];
dialog->shuffle[i] = t;
}
}
g_rand_free (gr);
}
static gboolean
about_dialog_anim_draw (GtkWidget *widget,
cairo_t *cr,
PikaAboutDialog *dialog)
{
GtkStyleContext *style = gtk_widget_get_style_context (widget);
GtkAllocation allocation;
GdkRGBA color;
gdouble alpha = 0.0;
gint x, y;
gint width, height;
if (! dialog->visible)
return FALSE;
if (dialog->animstep < 16)
{
alpha = (gfloat) dialog->animstep / 15.0;
}
else if (dialog->animstep < 18)
{
alpha = 1.0;
}
else if (dialog->animstep < 33)
{
alpha = 1.0 - ((gfloat) (dialog->animstep - 17)) / 15.0;
}
gtk_style_context_get_color (style, gtk_style_context_get_state (style),
&color);
gdk_cairo_set_source_rgba (cr, &color);
gtk_widget_get_allocation (widget, &allocation);
pango_layout_get_pixel_size (dialog->layout, &width, &height);
x = (allocation.width - width) / 2;
y = (allocation.height - height) / 2;
cairo_move_to (cr, x, y);
cairo_push_group (cr);
pango_cairo_show_layout (cr, dialog->layout);
cairo_pop_group_to_source (cr);
cairo_paint_with_alpha (cr, alpha);
return FALSE;
}
static gchar *
insert_spacers (const gchar *string)
{
GString *str = g_string_new (NULL);
gchar *normalized;
gchar *ptr;
gunichar unichr;
normalized = g_utf8_normalize (string, -1, G_NORMALIZE_DEFAULT_COMPOSE);
ptr = normalized;
while ((unichr = g_utf8_get_char (ptr)))
{
g_string_append_unichar (str, unichr);
g_string_append_unichar (str, 0x200b); /* ZERO WIDTH SPACE */
ptr = g_utf8_next_char (ptr);
}
g_free (normalized);
return g_string_free (str, FALSE);
}
static void
decorate_text (PikaAboutDialog *dialog,
gint anim_type,
gdouble time)
{
const gchar *text;
const gchar *ptr;
gint letter_count = 0;
gint cluster_start, cluster_end;
gunichar unichr;
PangoAttrList *attrlist = NULL;
PangoAttribute *attr;
PangoRectangle irect = {0, 0, 0, 0};
PangoRectangle lrect = {0, 0, 0, 0};
text = pango_layout_get_text (dialog->layout);
g_return_if_fail (text != NULL);
attrlist = pango_attr_list_new ();
switch (anim_type)
{
case 0: /* Fade in */
break;
case 1: /* Fade in, spread */
ptr = text;
cluster_start = 0;
while ((unichr = g_utf8_get_char (ptr)))
{
ptr = g_utf8_next_char (ptr);
cluster_end = (ptr - text);
if (unichr == 0x200b)
{
lrect.width = (1.0 - time) * 15.0 * PANGO_SCALE + 0.5;
attr = pango_attr_shape_new (&irect, &lrect);
attr->start_index = cluster_start;
attr->end_index = cluster_end;
pango_attr_list_change (attrlist, attr);
}
cluster_start = cluster_end;
}
break;
case 2: /* Fade in, sinewave */
ptr = text;
cluster_start = 0;
while ((unichr = g_utf8_get_char (ptr)))
{
if (unichr == 0x200b)
{
cluster_end = ptr - text;
attr = pango_attr_rise_new ((1.0 -time) * 18000 *
sin (4.0 * time +
(float) letter_count * 0.7));
attr->start_index = cluster_start;
attr->end_index = cluster_end;
pango_attr_list_change (attrlist, attr);
letter_count++;
cluster_start = cluster_end;
}
ptr = g_utf8_next_char (ptr);
}
break;
default:
g_printerr ("Unknown animation type %d\n", anim_type);
}
pango_layout_set_attributes (dialog->layout, attrlist);
pango_attr_list_unref (attrlist);
}
static gboolean
about_dialog_timer (gpointer data)
{
PikaAboutDialog *dialog = data;
gint timeout = 0;
if (dialog->animstep == 0)
{
gchar *text = NULL;
dialog->visible = TRUE;
switch (dialog->state)
{
case 0:
dialog->timer = g_timeout_add (30, about_dialog_timer, dialog);
dialog->state += 1;
return FALSE;
case 1:
text = insert_spacers (_("PIKA is brought to you by"));
dialog->state += 1;
break;
case 2:
if (! (dialog->index < dialog->n_authors))
dialog->index = 0;
text = insert_spacers (authors[dialog->shuffle[dialog->index]]);
dialog->index += 1;
break;
default:
g_return_val_if_reached (TRUE);
break;
}
g_return_val_if_fail (text != NULL, TRUE);
pango_layout_set_text (dialog->layout, text, -1);
pango_layout_set_attributes (dialog->layout, NULL);
g_free (text);
}
if (dialog->animstep < 16)
{
decorate_text (dialog, 2, ((gfloat) dialog->animstep) / 15.0);
}
else if (dialog->animstep == 16)
{
timeout = 800;
}
else if (dialog->animstep == 17)
{
timeout = 30;
}
else if (dialog->animstep < 33)
{
decorate_text (dialog, 1,
1.0 - ((gfloat) (dialog->animstep - 17)) / 15.0);
}
else if (dialog->animstep == 33)
{
dialog->visible = FALSE;
timeout = 300;
}
else
{
dialog->visible = FALSE;
dialog->animstep = -1;
timeout = 30;
}
dialog->animstep++;
gtk_widget_queue_draw (dialog->anim_area);
if (timeout > 0)
{
dialog->timer = g_timeout_add (timeout, about_dialog_timer, dialog);
return FALSE;
}
/* else keep the current timeout */
return TRUE;
}
#ifdef PIKA_UNSTABLE
static void
about_dialog_add_unstable_message (GtkWidget *vbox)
{
GtkWidget *label;
gchar *text;
text = g_strdup_printf (_("This is an unstable development release\n"
"commit %s"), PIKA_GIT_VERSION_ABBREV);
label = gtk_label_new (text);
g_free (text);
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (vbox), label, 2);
gtk_widget_show (label);
}
#endif /* PIKA_UNSTABLE */
static void
about_dialog_last_release_changed (PikaCoreConfig *config,
const GParamSpec *pspec,
PikaAboutDialog *dialog)
{
g_signal_handlers_disconnect_by_func (config,
(GCallback) about_dialog_last_release_changed,
dialog);
if (! dialog->dialog)
return;
about_dialog_add_update (dialog, config);
}
static void
about_dialog_download_clicked (GtkButton *button,
const gchar *link)
{
GtkWidget *window;
window = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_WINDOW);
if (window)
gtk_show_uri_on_window (GTK_WINDOW (window), link, GDK_CURRENT_TIME, NULL);
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __ABOUT_DIALOG_H__
#define __ABOUT_DIALOG_H__
GtkWidget * about_dialog_create (PikaCoreConfig *config);
#endif /* __ABOUT_DIALOG_H__ */

View File

@ -0,0 +1,380 @@
/* 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
*
* action-search-dialog.c
* Copyright (C) 2012-2013 Srihari Sriraman
* Suhas V
* Vidyashree K
* Zeeshan Ali Ansari
* Copyright (C) 2013-2015 Jehan <jehan at girinstud.io>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "dialogs-types.h"
#include "config/pikaguiconfig.h"
#include "core/pika.h"
#include "widgets/pikaaction.h"
#include "widgets/pikaactiongroup.h"
#include "widgets/pikaaction-history.h"
#include "widgets/pikadialogfactory.h"
#include "widgets/pikasearchpopup.h"
#include "action-search-dialog.h"
#include "pika-intl.h"
#define ACTION_SECTION_INACTIVE 7
static void action_search_history_and_actions (PikaSearchPopup *popup,
const gchar *keyword,
gpointer data);
static gboolean action_search_match_keyword (PikaAction *action,
const gchar* keyword,
gint *section,
Pika *pika);
/* Public Functions */
GtkWidget *
action_search_dialog_create (Pika *pika)
{
GtkWidget *dialog;
dialog = pika_search_popup_new (pika,
"pika-action-search-dialog",
_("Search Actions"),
action_search_history_and_actions,
pika);
return dialog;
}
/* Private Functions */
static void
action_search_history_and_actions (PikaSearchPopup *popup,
const gchar *keyword,
gpointer data)
{
gchar **actions;
GList *list;
GList *history_actions = NULL;
Pika *pika;
g_return_if_fail (PIKA_IS_PIKA (data));
pika = PIKA (data);
if (g_strcmp0 (keyword, "") == 0)
return;
history_actions = pika_action_history_search (pika,
action_search_match_keyword,
keyword);
/* 0. Top result: matching action in run history. */
for (list = history_actions; list; list = g_list_next (list))
pika_search_popup_add_result (popup, list->data,
pika_action_is_sensitive (list->data, NULL) ? 0 : ACTION_SECTION_INACTIVE);
/* 1. Then other matching actions. */
actions = g_action_group_list_actions (G_ACTION_GROUP (pika->app));
for (gint i = 0; actions[i] != NULL; i++)
{
GAction *action;
gint section;
/* The action search dialog doesn't show any non-historized
* actions, with a few exceptions. See the difference between
* pika_action_history_is_blacklisted_action() and
* pika_action_history_is_excluded_action().
*/
if (pika_action_history_is_blacklisted_action (actions[i]))
continue;
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app), actions[i]);
g_return_if_fail (PIKA_IS_ACTION (action));
if (! pika_action_is_visible (PIKA_ACTION (action)))
continue;
if (action_search_match_keyword (PIKA_ACTION (action), keyword, &section, pika))
{
GList *redundant;
/* A matching action. Check if we have not already added
* it as an history action.
*/
for (redundant = history_actions; redundant; redundant = g_list_next (redundant))
if (strcmp (pika_action_get_name (redundant->data), actions[i]) == 0)
break;
if (redundant == NULL)
pika_search_popup_add_result (popup, PIKA_ACTION (action), section);
}
}
g_strfreev (actions);
g_list_free_full (history_actions, (GDestroyNotify) g_object_unref);
}
/**
* action_search_match_keyword:
* @action: a #PikaAction to be matched.
* @keyword: free text keyword to match with @action.
* @section: relative section telling "how well" @keyword matched
* @action. The smaller the @section, the better the match. In
* particular this value can be used in the call to
* pika_search_popup_add_result() to show best matches at the
* top of the list.
* @pika: the #Pika object. This matters because we will tokenize
* keywords, labels and tooltip by language.
*
* This function will check if some freely typed text @keyword matches
* @action's label or tooltip, using a few algorithms to determine the
* best matches (order of words, start of match, and so on).
* All text (the user-provided @keyword as well as @actions labels and
* tooltips) are unicoded normalized, tokenized and case-folded before
* being compared. Comparisons with ASCII alternatives are also
* performed, providing even better matches, depending on the user
* languages (accounting for variant orthography in natural languages).
*
* @section will be set to:
* - 0 for any @action if @keyword is %NULL (match all).
* - 1 for a full initialism.
* - 4 for a partial initialism.
* - 1 if key tokens are found in the same order in the label and match
* the start of the label.
* - 2 if key tokens are found in the label order but don't match the
* start of the label.
* - 3 if key tokens are found with a different order from label.
* - 5 if @keyword matches the tooltip.
* - 6 if @keyword is a mix-match on tooltip and label.
* In the end, @section is incremented by %ACTION_SECTION_INACTIVE if
* the action is non-sensitive.
*
* Returns: %TRUE is a match was successful (in which case, @section
* will be set as well).
*/
static gboolean
action_search_match_keyword (PikaAction *action,
const gchar *keyword,
gint *section,
Pika *pika)
{
gboolean matched = FALSE;
gchar **key_tokens;
gchar **label_tokens;
gchar **label_alternates = NULL;
gchar *tmp;
if (keyword == NULL)
{
/* As a special exception, a NULL keyword means any action
* matches.
*/
if (section)
*section = pika_action_is_sensitive (action, NULL) ? 0 : ACTION_SECTION_INACTIVE;
return TRUE;
}
key_tokens = g_str_tokenize_and_fold (keyword, pika->config->language, NULL);
tmp = pika_strip_uline (pika_action_get_label (action));
label_tokens = g_str_tokenize_and_fold (tmp, pika->config->language, &label_alternates);
g_free (tmp);
/* Try to match the keyword as an initialism of the action's label.
* For instance 'gb' will match 'Gaussian Blur...'
*/
if (g_strv_length (key_tokens) == 1)
{
gchar **search_tokens[] = {label_tokens, label_alternates};
gint i;
for (i = 0; i < G_N_ELEMENTS (search_tokens); i++)
{
const gchar *key_token;
gchar **label_tokens;
for (key_token = key_tokens[0], label_tokens = search_tokens[i];
*key_token && *label_tokens;
key_token = g_utf8_find_next_char (key_token, NULL), label_tokens++)
{
gunichar key_char = g_utf8_get_char (key_token);
gunichar label_char = g_utf8_get_char (*label_tokens);
if (key_char != label_char)
break;
}
if (! *key_token)
{
matched = TRUE;
if (section)
{
/* full match is better than a partial match */
*section = ! *label_tokens ? 1 : 4;
}
else
{
break;
}
}
}
}
if (! matched && g_strv_length (label_tokens) > 0)
{
gint previous_matched = -1;
gboolean match_start;
gboolean match_ordered;
gint i;
matched = TRUE;
match_start = TRUE;
match_ordered = TRUE;
for (i = 0; key_tokens[i] != NULL; i++)
{
gint j;
for (j = 0; label_tokens[j] != NULL; j++)
{
if (g_str_has_prefix (label_tokens[j], key_tokens[i]))
{
goto one_matched;
}
}
for (j = 0; label_alternates[j] != NULL; j++)
{
if (g_str_has_prefix (label_alternates[j], key_tokens[i]))
{
goto one_matched;
}
}
matched = FALSE;
one_matched:
if (previous_matched > j)
match_ordered = FALSE;
previous_matched = j;
if (i != j)
match_start = FALSE;
continue;
}
if (matched && section)
{
/* If the key is the label start, this is a nicer match.
* Then if key tokens are found in the same order in the label.
* Finally we show at the end if the key tokens are found with a different order. */
*section = match_ordered ? (match_start ? 1 : 2) : 3;
}
}
if (! matched && key_tokens[0] && g_utf8_strlen (key_tokens[0], -1) > 2 &&
pika_action_get_tooltip (action) != NULL)
{
gchar **tooltip_tokens;
gchar **tooltip_alternates = NULL;
gboolean mixed_match;
gint i;
tooltip_tokens = g_str_tokenize_and_fold (pika_action_get_tooltip (action),
pika->config->language, &tooltip_alternates);
if (g_strv_length (tooltip_tokens) > 0)
{
matched = TRUE;
mixed_match = FALSE;
for (i = 0; key_tokens[i] != NULL; i++)
{
gint j;
for (j = 0; tooltip_tokens[j] != NULL; j++)
{
if (g_str_has_prefix (tooltip_tokens[j], key_tokens[i]))
{
goto one_tooltip_matched;
}
}
for (j = 0; tooltip_alternates[j] != NULL; j++)
{
if (g_str_has_prefix (tooltip_alternates[j], key_tokens[i]))
{
goto one_tooltip_matched;
}
}
for (j = 0; label_tokens[j] != NULL; j++)
{
if (g_str_has_prefix (label_tokens[j], key_tokens[i]))
{
mixed_match = TRUE;
goto one_tooltip_matched;
}
}
for (j = 0; label_alternates[j] != NULL; j++)
{
if (g_str_has_prefix (label_alternates[j], key_tokens[i]))
{
mixed_match = TRUE;
goto one_tooltip_matched;
}
}
matched = FALSE;
one_tooltip_matched:
continue;
}
if (matched && section)
{
/* Matching the tooltip is section 5. We don't go looking
* for start of string or token order for tooltip match.
* But if the match is mixed on tooltip and label (there are
* no match for *only* label or *only* tooltip), this is
* section 6. */
*section = mixed_match ? 6 : 5;
}
}
g_strfreev (tooltip_tokens);
g_strfreev (tooltip_alternates);
}
g_strfreev (key_tokens);
g_strfreev (label_tokens);
g_strfreev (label_alternates);
if (matched && section && ! pika_action_is_sensitive (action, NULL))
*section += ACTION_SECTION_INACTIVE;
return matched;
}

View File

@ -0,0 +1,33 @@
/* 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
*
* action-search-dialog.c
* Copyright (C) 2012-2013 Srihari Sriraman
* Suhas V
* Vidyashree K
* Zeeshan Ali Ansari
*
* 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/>.
*/
#ifndef __ACTION_SEARCH_DIALOG_H__
#define __ACTION_SEARCH_DIALOG_H__
GtkWidget * action_search_dialog_create (Pika *pika);
#endif /* __ACTION_SEARCH_DIALOG_H__ */

85
app/dialogs/authors.xsl Normal file
View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- XSL transformation to create a header file from authors.xml -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsl:output method="text" />
<xsl:template name="recent-contributor">
<xsl:param name="role" />
<xsl:apply-templates select="dc:contributor[contains(@role, $role) and
((number(@last-active) >= 2 and
number(substring-after(@last-active, &quot;.&quot;)) >= 10) or
number(@last-active) >= 3)]" >
<xsl:sort order="descending" data-type="number" select="@last-active" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/dc:pika-authors">
<xsl:text>
/* NOTE: This file is auto-generated from authors.xml, do not edit it. */
static const gchar * const creators[] =
{
</xsl:text>
<xsl:apply-templates select="dc:creator" />
<xsl:text> NULL
};
</xsl:text>
<xsl:text>
static const gchar * const maintainers[] =
{
</xsl:text>
<xsl:apply-templates select="dc:maintainer" />
<xsl:text> NULL
};
</xsl:text>
<xsl:text>
static const gchar * const authors[] =
{
</xsl:text>
<xsl:apply-templates select="dc:creator" />
<xsl:apply-templates select="dc:maintainer" />
<xsl:call-template name="recent-contributor">
<xsl:with-param name="role" select="'author'"/>
</xsl:call-template>
<xsl:text> NULL
};
</xsl:text>
<xsl:text>
static const gchar * const artists[] =
{
</xsl:text>
<xsl:call-template name="recent-contributor">
<xsl:with-param name="role" select="'artist'"/>
</xsl:call-template>
<xsl:text> NULL
};
</xsl:text>
<xsl:text>
static const gchar * const documenters[] =
{
</xsl:text>
<xsl:call-template name="recent-contributor">
<xsl:with-param name="role" select="'documenter'"/>
</xsl:call-template>
<xsl:text> NULL
};
</xsl:text>
</xsl:template>
<xsl:template match="dc:creator"> "<xsl:apply-templates />",
</xsl:template>
<xsl:template match="dc:maintainer"> "<xsl:apply-templates />",
</xsl:template>
<xsl:template match="dc:contributor"> "<xsl:apply-templates />",
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,250 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikachannel.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "widgets/pikacolorpanel.h"
#include "widgets/pikaviewabledialog.h"
#include "channel-options-dialog.h"
#include "item-options-dialog.h"
#include "pika-intl.h"
typedef struct _ChannelOptionsDialog ChannelOptionsDialog;
struct _ChannelOptionsDialog
{
PikaChannelOptionsCallback callback;
gpointer user_data;
GtkWidget *color_panel;
GtkWidget *save_sel_toggle;
};
/* local function prototypes */
static void channel_options_dialog_free (ChannelOptionsDialog *private);
static void channel_options_dialog_callback (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data);
static void channel_options_opacity_changed (GtkAdjustment *adjustment,
PikaColorButton *color_button);
static void channel_options_color_changed (PikaColorButton *color_button,
GtkAdjustment *adjustment);
/* public functions */
GtkWidget *
channel_options_dialog_new (PikaImage *image,
PikaChannel *channel,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *color_label,
const gchar *opacity_label,
gboolean show_from_sel,
const gchar *channel_name,
const PikaRGB *channel_color,
gboolean channel_visible,
PikaColorTag channel_color_tag,
gboolean channel_lock_content,
gboolean channel_lock_position,
gboolean channel_lock_visibility,
PikaChannelOptionsCallback callback,
gpointer user_data)
{
ChannelOptionsDialog *private;
GtkWidget *dialog;
GtkAdjustment *opacity_adj;
GtkWidget *scale;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (channel == NULL || PIKA_IS_CHANNEL (channel), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (role != NULL, NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (desc != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (channel_color != NULL, NULL);
g_return_val_if_fail (color_label != NULL, NULL);
g_return_val_if_fail (opacity_label != NULL, NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (ChannelOptionsDialog);
private->callback = callback;
private->user_data = user_data;
dialog = item_options_dialog_new (image, PIKA_ITEM (channel), context,
parent, title, role,
icon_name, desc, help_id,
channel_name ? _("Channel _name:") : NULL,
PIKA_ICON_LOCK_CONTENT,
_("Lock _pixels"),
_("Lock position and _size"),
_("Lock visibility"),
channel_name,
channel_visible,
channel_color_tag,
channel_lock_content,
channel_lock_position,
channel_lock_visibility,
channel_options_dialog_callback,
private);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) channel_options_dialog_free, private);
opacity_adj = gtk_adjustment_new (channel_color->a * 100.0,
0.0, 100.0, 1.0, 10.0, 0);
scale = pika_spin_scale_new (opacity_adj, NULL, 1);
gtk_widget_set_size_request (scale, 200, -1);
item_options_dialog_add_widget (dialog,
opacity_label, scale);
private->color_panel = pika_color_panel_new (color_label,
channel_color,
PIKA_COLOR_AREA_LARGE_CHECKS,
24, 24);
pika_color_panel_set_context (PIKA_COLOR_PANEL (private->color_panel),
context);
g_signal_connect (opacity_adj, "value-changed",
G_CALLBACK (channel_options_opacity_changed),
private->color_panel);
g_signal_connect (private->color_panel, "color-changed",
G_CALLBACK (channel_options_color_changed),
opacity_adj);
item_options_dialog_add_widget (dialog,
NULL, private->color_panel);
if (show_from_sel)
{
private->save_sel_toggle =
gtk_check_button_new_with_mnemonic (_("Initialize from _selection"));
item_options_dialog_add_widget (dialog,
NULL, private->save_sel_toggle);
}
return dialog;
}
/* private functions */
static void
channel_options_dialog_free (ChannelOptionsDialog *private)
{
g_slice_free (ChannelOptionsDialog, private);
}
static void
channel_options_dialog_callback (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data)
{
ChannelOptionsDialog *private = user_data;
PikaRGB color;
gboolean save_selection = FALSE;
pika_color_button_get_color (PIKA_COLOR_BUTTON (private->color_panel),
&color);
if (private->save_sel_toggle)
save_selection =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (private->save_sel_toggle));
private->callback (dialog,
image,
PIKA_CHANNEL (item),
context,
item_name,
&color,
save_selection,
item_visible,
item_color_tag,
item_lock_content,
item_lock_position,
item_lock_visibility,
private->user_data);
}
static void
channel_options_opacity_changed (GtkAdjustment *adjustment,
PikaColorButton *color_button)
{
PikaRGB color;
pika_color_button_get_color (color_button, &color);
pika_rgb_set_alpha (&color, gtk_adjustment_get_value (adjustment) / 100.0);
pika_color_button_set_color (color_button, &color);
}
static void
channel_options_color_changed (PikaColorButton *button,
GtkAdjustment *adjustment)
{
PikaRGB color;
pika_color_button_get_color (button, &color);
gtk_adjustment_set_value (adjustment, color.a * 100.0);
}

View File

@ -0,0 +1,64 @@
/* 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/>.
*/
#ifndef __CHANNEL_OPTIONS_DIALOG_H__
#define __CHANNEL_OPTIONS_DIALOG_H__
typedef void (* PikaChannelOptionsCallback) (GtkWidget *dialog,
PikaImage *image,
PikaChannel *channel,
PikaContext *context,
const gchar *channel_name,
const PikaRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
PikaColorTag channel_color_tag,
gboolean channel_lock_content,
gboolean channel_lock_position,
gboolean channel_lock_visibility,
gpointer user_data);
GtkWidget * channel_options_dialog_new (PikaImage *image,
PikaChannel *channel,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *color_label,
const gchar *opacity_label,
gboolean show_from_sel,
const gchar *channel_name,
const PikaRGB *channel_color,
gboolean channel_visible,
PikaColorTag channel_color_tag,
gboolean channel_lock_content,
gboolean channel_lock_position,
gboolean channel_lock_visibility,
PikaChannelOptionsCallback callback,
gpointer user_data);
#endif /* __CHANNEL_OPTIONS_DIALOG_H__ */

View File

@ -0,0 +1,498 @@
/* 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
*
* color-profile-dialog.h
* Copyright (C) 2015 Michael Natterer <mitch@gimp.org>
*
* Partly based on the lcms plug-in
* Copyright (C) 2006, 2007 Sven Neumann <sven@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-constructors.h"
#include "widgets/pikawidgets-utils.h"
#include "color-profile-dialog.h"
#include "pika-intl.h"
typedef struct
{
ColorProfileDialogType dialog_type;
PikaImage *image;
PikaColorProfile *current_profile;
PikaColorProfile *default_profile;
PikaColorRenderingIntent intent;
gboolean bpc;
PikaColorProfileCallback callback;
gpointer user_data;
PikaColorConfig *config;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *combo;
GtkWidget *dest_view;
} ProfileDialog;
static void color_profile_dialog_free (ProfileDialog *private);
static GtkWidget * color_profile_combo_box_new (ProfileDialog *private);
static void color_profile_dialog_response (GtkWidget *dialog,
gint response_id,
ProfileDialog *private);
static void color_profile_dest_changed (GtkWidget *combo,
ProfileDialog *private);
/* public functions */
GtkWidget *
color_profile_dialog_new (ColorProfileDialogType dialog_type,
PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaColorProfile *current_profile,
PikaColorProfile *default_profile,
PikaColorRenderingIntent intent,
gboolean bpc,
PikaColorProfileCallback callback,
gpointer user_data)
{
ProfileDialog *private;
GtkWidget *dialog;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *expander;
GtkWidget *label;
const gchar *dest_label;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (current_profile == NULL ||
PIKA_IS_COLOR_PROFILE (current_profile), NULL);
g_return_val_if_fail (default_profile == NULL ||
PIKA_IS_COLOR_PROFILE (default_profile), NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (ProfileDialog);
private->dialog_type = dialog_type;
private->image = image;
private->current_profile = current_profile;
private->default_profile = default_profile;
private->intent = intent;
private->bpc = bpc;
private->callback = callback;
private->user_data = user_data;
private->config = image->pika->config->color_management;
switch (dialog_type)
{
case COLOR_PROFILE_DIALOG_ASSIGN_PROFILE:
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Assign ICC Color Profile"),
"pika-image-color-profile-assign",
NULL,
_("Assign a color profile to the image"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_COLOR_PROFILE_ASSIGN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Assign"), GTK_RESPONSE_OK,
NULL);
dest_label = _("Assign");
break;
case COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE:
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Convert to ICC Color Profile"),
"pika-image-color-profile-convert",
NULL,
_("Convert the image to a color profile"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_COLOR_PROFILE_CONVERT,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_onvert"), GTK_RESPONSE_OK,
NULL);
dest_label = _("Convert to");
break;
case COLOR_PROFILE_DIALOG_CONVERT_TO_RGB:
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("RGB Conversion"),
"pika-image-convert-rgb",
PIKA_ICON_CONVERT_RGB,
_("Convert Image to RGB"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_CONVERT_RGB,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_onvert"), GTK_RESPONSE_OK,
NULL);
dest_label = _("Convert to");
break;
case COLOR_PROFILE_DIALOG_CONVERT_TO_GRAY:
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Grayscale Conversion"),
"pika-image-convert-gray",
PIKA_ICON_CONVERT_GRAYSCALE,
_("Convert Image to Grayscale"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_CONVERT_GRAYSCALE,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_onvert"), GTK_RESPONSE_OK,
NULL);
dest_label = _("Convert to");
break;
case COLOR_PROFILE_DIALOG_SELECT_SOFTPROOF_PROFILE:
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Soft-Proof Profile"),
"pika-select-softproof-profile",
PIKA_ICON_DOCUMENT_PRINT,
_("Select Soft-Proof Profile"),
parent,
pika_standard_help_func,
PIKA_HELP_VIEW_COLOR_MANAGEMENT,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Select"), GTK_RESPONSE_OK,
NULL);
dest_label = _("New Color Profile");
break;
default:
g_return_val_if_reached (NULL);
}
private->dialog = dialog;
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) color_profile_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (color_profile_dialog_response),
private);
private->main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (private->main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
private->main_vbox, TRUE, TRUE, 0);
gtk_widget_show (private->main_vbox);
frame = pika_frame_new (_("Current Color Profile"));
gtk_box_pack_start (GTK_BOX (private->main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
label = pika_color_profile_label_new (private->current_profile);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
frame = pika_frame_new (dest_label);
gtk_box_pack_start (GTK_BOX (private->main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
private->combo = color_profile_combo_box_new (private);
gtk_box_pack_start (GTK_BOX (vbox), private->combo, FALSE, FALSE, 0);
gtk_widget_show (private->combo);
expander = gtk_expander_new_with_mnemonic (_("Profile _details"));
gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
gtk_widget_show (expander);
private->dest_view = pika_color_profile_view_new ();
gtk_container_add (GTK_CONTAINER (expander), private->dest_view);
gtk_widget_show (private->dest_view);
g_signal_connect (private->combo, "changed",
G_CALLBACK (color_profile_dest_changed),
private);
color_profile_dest_changed (private->combo, private);
if (dialog_type == COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE)
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *combo;
GtkWidget *toggle;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (private->main_vbox), vbox, FALSE, FALSE, 0);
gtk_widget_show (vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Rendering Intent:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
combo = pika_enum_combo_box_new (PIKA_TYPE_COLOR_RENDERING_INTENT);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->intent,
G_CALLBACK (pika_int_combo_box_get_active),
&private->intent, NULL);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
toggle =
gtk_check_button_new_with_mnemonic (_("_Black Point Compensation"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), private->bpc);
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->bpc);
}
return dialog;
}
/* private functions */
static void
color_profile_dialog_free (ProfileDialog *private)
{
g_slice_free (ProfileDialog, private);
}
static GtkWidget *
color_profile_combo_box_new (ProfileDialog *private)
{
GtkListStore *store;
GtkWidget *combo;
GtkWidget *chooser;
GFile *history;
history = pika_directory_file ("profilerc", NULL);
store = pika_color_profile_store_new (history);
g_object_unref (history);
if (private->default_profile)
{
PikaImageBaseType base_type;
PikaPrecision precision;
GError *error = NULL;
switch (private->dialog_type)
{
case COLOR_PROFILE_DIALOG_ASSIGN_PROFILE:
case COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE:
base_type = pika_image_get_base_type (private->image);
break;
case COLOR_PROFILE_DIALOG_CONVERT_TO_RGB:
base_type = PIKA_RGB;
break;
case COLOR_PROFILE_DIALOG_CONVERT_TO_GRAY:
base_type = PIKA_GRAY;
break;
default:
g_return_val_if_reached (NULL);
}
precision = pika_image_get_precision (private->image);
if (! pika_color_profile_store_add_defaults (PIKA_COLOR_PROFILE_STORE (store),
private->config,
base_type,
precision,
&error))
{
pika_message (private->image->pika, G_OBJECT (private->dialog),
PIKA_MESSAGE_ERROR,
"%s", error->message);
g_clear_error (&error);
}
}
else
{
pika_color_profile_store_add_file (PIKA_COLOR_PROFILE_STORE (store),
NULL, NULL);
}
chooser =
pika_color_profile_chooser_dialog_new (_("Select Destination Profile"),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN);
pika_color_profile_chooser_dialog_connect_path (chooser,
G_OBJECT (private->image->pika->config),
"color-profile-path");
combo = pika_color_profile_combo_box_new_with_model (chooser,
GTK_TREE_MODEL (store));
g_object_unref (store);
pika_color_profile_combo_box_set_active_file (PIKA_COLOR_PROFILE_COMBO_BOX (combo),
NULL, NULL);
return combo;
}
static void
color_profile_dialog_response (GtkWidget *dialog,
gint response_id,
ProfileDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
PikaColorProfile *profile = NULL;
GFile *file;
file = pika_color_profile_combo_box_get_active_file (PIKA_COLOR_PROFILE_COMBO_BOX (private->combo));
if (file)
{
GError *error = NULL;
profile = pika_color_profile_new_from_file (file, &error);
g_object_unref (file);
if (! profile)
{
pika_message (private->image->pika, G_OBJECT (dialog),
PIKA_MESSAGE_ERROR,
"%s", error->message);
g_clear_error (&error);
return;
}
}
else if (private->default_profile)
{
profile = g_object_ref (private->default_profile);
}
private->callback (dialog,
private->image,
profile,
file,
private->intent,
private->bpc,
private->user_data);
if (profile)
g_object_unref (profile);
}
else
{
gtk_widget_destroy (dialog);
}
}
static void
color_profile_dest_changed (GtkWidget *combo,
ProfileDialog *private)
{
PikaColorProfile *dest_profile = NULL;
GFile *file;
file = pika_color_profile_combo_box_get_active_file (PIKA_COLOR_PROFILE_COMBO_BOX (combo));
if (file)
{
GError *error = NULL;
dest_profile = pika_color_profile_new_from_file (file, &error);
g_object_unref (file);
if (! dest_profile)
{
pika_color_profile_view_set_error (PIKA_COLOR_PROFILE_VIEW (private->dest_view),
error->message);
g_clear_error (&error);
}
}
else if (private->default_profile)
{
dest_profile = g_object_ref (private->default_profile);
}
else
{
pika_color_profile_view_set_error (PIKA_COLOR_PROFILE_VIEW (private->dest_view),
C_("profile", "None"));
}
if (dest_profile)
{
pika_color_profile_view_set_profile (PIKA_COLOR_PROFILE_VIEW (private->dest_view),
dest_profile);
g_object_unref (dest_profile);
}
}

View File

@ -0,0 +1,60 @@
/* 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
*
* color-profile-dialog.h
* Copyright (C) 2015 Michael Natterer <mitch@gimp.org>
*
* 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/>.
*/
#ifndef __COLOR_PROFILE_DIALOG_H__
#define __COLOR_PROFILE_DIALOG_H__
typedef enum
{
COLOR_PROFILE_DIALOG_ASSIGN_PROFILE,
COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE,
COLOR_PROFILE_DIALOG_CONVERT_TO_RGB,
COLOR_PROFILE_DIALOG_CONVERT_TO_GRAY,
COLOR_PROFILE_DIALOG_SELECT_SOFTPROOF_PROFILE
} ColorProfileDialogType;
typedef void (* PikaColorProfileCallback) (GtkWidget *dialog,
PikaImage *image,
PikaColorProfile *new_profile,
GFile *new_file,
PikaColorRenderingIntent intent,
gboolean bpc,
gpointer user_data);
GtkWidget * color_profile_dialog_new (ColorProfileDialogType dialog_type,
PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaColorProfile *current_profile,
PikaColorProfile *default_profile,
PikaColorRenderingIntent intent,
gboolean bpc,
PikaColorProfileCallback callback,
gpointer user_data);
#endif /* __COLOR_PROFILE_DIALOG_H__ */

View File

@ -0,0 +1,269 @@
/* 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
*
* color-profile-import-dialog.h
* Copyright (C) 2015 Michael Natterer <mitch@gimp.org>
*
* Partly based on the lcms plug-in
* Copyright (C) 2006, 2007 Sven Neumann <sven@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaimage-color-profile.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-constructors.h"
#include "color-profile-import-dialog.h"
#include "pika-intl.h"
/* public functions */
PikaColorProfilePolicy
color_profile_import_dialog_run (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaColorProfile **dest_profile,
PikaColorRenderingIntent *intent,
gboolean *bpc,
gboolean *dont_ask)
{
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *vbox;
GtkWidget *stack;
GtkWidget *switcher;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *intent_combo;
GtkWidget *bpc_toggle;
GtkWidget *dont_ask_toggle;
PikaColorProfile *src_profile;
PikaColorProfile *pref_profile = NULL;
PikaColorProfilePolicy policy;
const gchar *frame_title;
gchar *text;
g_return_val_if_fail (PIKA_IS_IMAGE (image), PIKA_COLOR_PROFILE_POLICY_KEEP);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), PIKA_COLOR_PROFILE_POLICY_KEEP);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent),
PIKA_COLOR_PROFILE_POLICY_KEEP);
g_return_val_if_fail (dest_profile != NULL, PIKA_COLOR_PROFILE_POLICY_KEEP);
src_profile = pika_image_get_color_profile (image);
*dest_profile = pika_image_get_builtin_color_profile (image);
if (pika_image_get_base_type (image) == PIKA_GRAY)
{
frame_title = _("Convert the image to the built-in grayscale color profile?");
pref_profile = pika_color_config_get_gray_color_profile (image->pika->config->color_management, NULL);
if (pref_profile && pika_color_profile_is_equal (pref_profile, *dest_profile))
g_clear_object (&pref_profile);
}
else
{
frame_title = _("Convert the image to the built-in sRGB color profile?");
pref_profile = pika_color_config_get_rgb_color_profile (image->pika->config->color_management, NULL);
if (pref_profile && pika_color_profile_is_equal (pref_profile, *dest_profile))
g_clear_object (&pref_profile);
}
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Keep the Embedded Working Space?"),
"pika-image-color-profile-import",
"pika-prefs-color-management",
_("Keep the image's color profile"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_COLOR_PROFILE_IMPORT,
_("_Keep"), GTK_RESPONSE_YES,
_("_Convert"), GTK_RESPONSE_NO,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
text = g_strdup_printf (_("The image '%s' has an embedded color profile"),
pika_image_get_display_name (image));
frame = pika_frame_new (text);
g_free (text);
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
label = pika_color_profile_label_new (src_profile);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
switcher = gtk_stack_switcher_new ();
stack = gtk_stack_new ();
gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (stack));
gtk_box_pack_start (GTK_BOX (main_vbox), stack, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (main_vbox), switcher, FALSE, FALSE, 0);
gtk_widget_show (stack);
frame = pika_frame_new (frame_title);
gtk_stack_add_titled (GTK_STACK (stack), frame, "builtin",
_("Built-in Profile"));
gtk_widget_show (frame);
label = pika_color_profile_label_new (*dest_profile);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
if (pref_profile)
{
if (pika_image_get_base_type (image) == PIKA_GRAY)
frame_title = _("Convert the image to the preferred grayscale color profile?");
else
frame_title = _("Convert the image to the preferred RGB color profile?");
frame = pika_frame_new (frame_title);
gtk_stack_add_titled (GTK_STACK (stack), frame, "preferred",
_("Preferred Profile"));
gtk_widget_show (frame);
label = pika_color_profile_label_new (pref_profile);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
gtk_widget_show (switcher);
gtk_stack_set_visible_child_name (GTK_STACK (stack), "preferred");
}
if (intent && bpc)
{
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
gtk_widget_show (vbox);
}
else
{
vbox = main_vbox;
}
if (intent)
{
GtkWidget *hbox;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Rendering Intent:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
intent_combo = pika_enum_combo_box_new (PIKA_TYPE_COLOR_RENDERING_INTENT);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (intent_combo),
*intent);
gtk_box_pack_start (GTK_BOX (hbox), intent_combo, TRUE, TRUE, 0);
gtk_widget_show (intent_combo);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), intent_combo);
}
if (bpc)
{
bpc_toggle =
gtk_check_button_new_with_mnemonic (_("_Black Point Compensation"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bpc_toggle), *bpc);
gtk_box_pack_start (GTK_BOX (vbox), bpc_toggle, FALSE, FALSE, 0);
gtk_widget_show (bpc_toggle);
}
if (dont_ask)
{
dont_ask_toggle =
gtk_check_button_new_with_mnemonic (_("_Don't ask me again"));
gtk_widget_set_tooltip_text (dont_ask_toggle,
_("Your choice can later be edited in Preferences > Color Management"));
gtk_box_pack_end (GTK_BOX (main_vbox), dont_ask_toggle, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dont_ask_toggle), FALSE);
gtk_widget_show (dont_ask_toggle);
}
switch (gtk_dialog_run (GTK_DIALOG (dialog)))
{
case GTK_RESPONSE_NO:
if (g_strcmp0 (gtk_stack_get_visible_child_name (GTK_STACK (stack)),
"builtin") == 0)
{
policy = PIKA_COLOR_PROFILE_POLICY_CONVERT_BUILTIN;
g_object_ref (*dest_profile);
}
else
{
policy = PIKA_COLOR_PROFILE_POLICY_CONVERT_PREFERRED;
*dest_profile = g_object_ref (pref_profile);
}
break;
default:
policy = PIKA_COLOR_PROFILE_POLICY_KEEP;
break;
}
if (intent)
pika_int_combo_box_get_active (PIKA_INT_COMBO_BOX (intent_combo),
(gint *) intent);
if (bpc)
*bpc = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bpc_toggle));
if (dont_ask)
*dont_ask = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dont_ask_toggle));
gtk_widget_destroy (dialog);
g_clear_object (&pref_profile);
return policy;
}

View File

@ -0,0 +1,39 @@
/* 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
*
* color-profile-import-dialog.h
* Copyright (C) 2015 Michael Natterer <mitch@gimp.org>
*
* 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/>.
*/
#ifndef __COLOR_PROFILE_IMPORT_DIALOG_H__
#define __COLOR_PROFILE_IMPORT_DIALOG_H__
PikaColorProfilePolicy
color_profile_import_dialog_run (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaColorProfile **dest_profile,
PikaColorRenderingIntent *intent,
gboolean *bpc,
gboolean *dont_ask);
#endif /* __COLOR_PROFILE_IMPORT_DIALOG_H__ */

View File

@ -0,0 +1,439 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontainer-filter.h"
#include "core/pikacontext.h"
#include "core/pikadatafactory.h"
#include "core/pikaimage.h"
#include "core/pikalist.h"
#include "core/pikapalette.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewablebox.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-utils.h"
#include "convert-indexed-dialog.h"
#include "pika-intl.h"
typedef struct _IndexedDialog IndexedDialog;
struct _IndexedDialog
{
PikaImage *image;
PikaConvertPaletteType palette_type;
gint max_colors;
gboolean remove_duplicates;
PikaConvertDitherType dither_type;
gboolean dither_alpha;
gboolean dither_text_layers;
PikaPalette *custom_palette;
PikaConvertIndexedCallback callback;
gpointer user_data;
GtkWidget *dialog;
PikaContext *context;
PikaContainer *container;
GtkWidget *duplicates_toggle;
};
static void convert_dialog_free (IndexedDialog *private);
static void convert_dialog_response (GtkWidget *widget,
gint response_id,
IndexedDialog *private);
static GtkWidget * convert_dialog_palette_box (IndexedDialog *private);
static gboolean convert_dialog_palette_filter (PikaObject *object,
gpointer user_data);
static void convert_dialog_palette_changed (PikaContext *context,
PikaPalette *palette,
IndexedDialog *private);
static void convert_dialog_type_update (GtkWidget *widget,
IndexedDialog *private);
/* public functions */
GtkWidget *
convert_indexed_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaConvertPaletteType palette_type,
gint max_colors,
gboolean remove_duplicates,
PikaConvertDitherType dither_type,
gboolean dither_alpha,
gboolean dither_text_layers,
PikaPalette *custom_palette,
PikaConvertIndexedCallback callback,
gpointer user_data)
{
IndexedDialog *private;
GtkWidget *dialog;
GtkWidget *button;
GtkWidget *main_vbox;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkAdjustment *adjustment;
GtkWidget *spinbutton;
GtkWidget *frame;
GtkWidget *toggle;
GtkWidget *palette_box;
GtkWidget *combo;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (custom_palette == NULL ||
PIKA_IS_PALETTE (custom_palette), NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (IndexedDialog);
private->image = image;
private->palette_type = palette_type;
private->max_colors = max_colors;
private->remove_duplicates = remove_duplicates;
private->dither_type = dither_type;
private->dither_alpha = dither_alpha;
private->dither_text_layers = dither_text_layers;
private->custom_palette = custom_palette;
private->callback = callback;
private->user_data = user_data;
private->dialog = dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Indexed Color Conversion"),
"pika-image-convert-indexed",
PIKA_ICON_CONVERT_INDEXED,
_("Convert Image to Indexed Colors"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_CONVERT_INDEXED,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_onvert"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) convert_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (convert_dialog_response),
private);
palette_box = convert_dialog_palette_box (private);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
/* palette */
frame =
pika_enum_radio_frame_new_with_range (PIKA_TYPE_CONVERT_PALETTE_TYPE,
PIKA_CONVERT_PALETTE_GENERATE,
(palette_box ?
PIKA_CONVERT_PALETTE_CUSTOM :
PIKA_CONVERT_PALETTE_MONO),
gtk_label_new (_("Colormap")),
G_CALLBACK (convert_dialog_type_update),
private, NULL,
&button);
pika_int_radio_group_set_active (GTK_RADIO_BUTTON (button),
private->palette_type);
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* max n_colors */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
pika_enum_radio_frame_add (GTK_FRAME (frame), hbox,
PIKA_CONVERT_PALETTE_GENERATE, TRUE);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Maximum number of colors:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
if (private->max_colors == 256 && pika_image_has_alpha (image))
private->max_colors = 255;
adjustment = gtk_adjustment_new (private->max_colors, 2, 256, 1, 8, 0);
spinbutton = pika_spin_button_new (adjustment, 1.0, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
gtk_widget_show (spinbutton);
g_signal_connect (adjustment, "value-changed",
G_CALLBACK (pika_int_adjustment_update),
&private->max_colors);
/* custom palette */
if (palette_box)
{
pika_enum_radio_frame_add (GTK_FRAME (frame), palette_box,
PIKA_CONVERT_PALETTE_CUSTOM, TRUE);
gtk_widget_show (palette_box);
}
vbox = gtk_bin_get_child (GTK_BIN (frame));
private->duplicates_toggle = toggle =
gtk_check_button_new_with_mnemonic (_("_Remove unused and duplicate "
"colors from colormap"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
private->remove_duplicates);
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 3);
gtk_widget_show (toggle);
if (private->palette_type == PIKA_CONVERT_PALETTE_GENERATE ||
private->palette_type == PIKA_CONVERT_PALETTE_MONO)
gtk_widget_set_sensitive (toggle, FALSE);
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->remove_duplicates);
/* dithering */
frame = pika_frame_new (_("Dithering"));
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("Color _dithering:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
combo = pika_enum_combo_box_new (PIKA_TYPE_CONVERT_DITHER_TYPE);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->dither_type,
G_CALLBACK (pika_int_combo_box_get_active),
&private->dither_type, NULL);
toggle =
gtk_check_button_new_with_mnemonic (_("Enable dithering of _transparency"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
private->dither_alpha);
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->dither_alpha);
toggle =
gtk_check_button_new_with_mnemonic (_("Enable dithering of text _layers"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
private->dither_text_layers);
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->dither_text_layers);
pika_help_set_help_data (toggle,
_("Dithering text layers will make them uneditable"),
NULL);
return dialog;
}
/* private functions */
static void
convert_dialog_free (IndexedDialog *private)
{
if (private->container)
g_object_unref (private->container);
if (private->context)
g_object_unref (private->context);
g_slice_free (IndexedDialog, private);
}
static void
convert_dialog_response (GtkWidget *dialog,
gint response_id,
IndexedDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
private->callback (dialog,
private->image,
private->palette_type,
private->max_colors,
private->remove_duplicates,
private->dither_type,
private->dither_alpha,
private->dither_text_layers,
private->custom_palette,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
}
static GtkWidget *
convert_dialog_palette_box (IndexedDialog *private)
{
Pika *pika = private->image->pika;
GList *list;
PikaPalette *web_palette = NULL;
gboolean custom_found = FALSE;
/* We can't dither to > 256 colors */
private->container =
pika_container_filter (pika_data_factory_get_container (pika->palette_factory),
convert_dialog_palette_filter,
NULL);
if (pika_container_is_empty (private->container))
{
g_object_unref (private->container);
private->container = NULL;
return NULL;
}
private->context = pika_context_new (pika, "convert-dialog", NULL);
for (list = PIKA_LIST (private->container)->queue->head;
list;
list = g_list_next (list))
{
PikaPalette *palette = list->data;
/* Preferentially, the initial default is 'Web' if available */
if (web_palette == NULL &&
g_ascii_strcasecmp (pika_object_get_name (palette), "Web") == 0)
{
web_palette = palette;
}
if (private->custom_palette == palette)
custom_found = TRUE;
}
if (! custom_found)
{
if (web_palette)
private->custom_palette = web_palette;
else
private->custom_palette = PIKA_LIST (private->container)->queue->head->data;
}
pika_context_set_palette (private->context, private->custom_palette);
g_signal_connect (private->context, "palette-changed",
G_CALLBACK (convert_dialog_palette_changed),
private);
return pika_palette_box_new (private->container, private->context, NULL, 4);
}
static gboolean
convert_dialog_palette_filter (PikaObject *object,
gpointer user_data)
{
PikaPalette *palette = PIKA_PALETTE (object);
return (pika_palette_get_n_colors (palette) > 0 &&
pika_palette_get_n_colors (palette) <= 256);
}
static void
convert_dialog_palette_changed (PikaContext *context,
PikaPalette *palette,
IndexedDialog *private)
{
if (! palette)
return;
if (pika_palette_get_n_colors (palette) > 256)
{
pika_message (private->image->pika, G_OBJECT (private->dialog),
PIKA_MESSAGE_WARNING,
_("Cannot convert to a palette "
"with more than 256 colors."));
}
else
{
private->custom_palette = palette;
}
}
static void
convert_dialog_type_update (GtkWidget *widget,
IndexedDialog *private)
{
pika_radio_button_update (widget, &private->palette_type);
if (private->duplicates_toggle)
gtk_widget_set_sensitive (private->duplicates_toggle,
private->palette_type !=
PIKA_CONVERT_PALETTE_GENERATE &&
private->palette_type !=
PIKA_CONVERT_PALETTE_MONO);
}

View File

@ -0,0 +1,52 @@
/* 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/>.
*/
#ifndef __CONVERT_INDEXED_DIALOG_H__
#define __CONVERT_INDEXED_DIALOG_H__
typedef void (* PikaConvertIndexedCallback) (GtkWidget *dialog,
PikaImage *image,
PikaConvertPaletteType palette_type,
gint max_colors,
gboolean remove_duplicates,
PikaConvertDitherType dither_type,
gboolean dither_alpha,
gboolean dither_text_layers,
PikaPalette *custom_palette,
gpointer user_data);
GtkWidget * convert_indexed_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaConvertPaletteType palette_type,
gint max_colors,
gboolean remove_duplicates,
PikaConvertDitherType dither_type,
gboolean dither_alpha,
gboolean dither_text_layers,
PikaPalette *custom_palette,
PikaConvertIndexedCallback callback,
gpointer user_data);
#endif /* __CONVERT_INDEXED_DIALOG_H__ */

View File

@ -0,0 +1,334 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "gegl/pika-babl.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pika-utils.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-utils.h"
#include "convert-precision-dialog.h"
#include "pika-intl.h"
typedef struct _ConvertDialog ConvertDialog;
struct _ConvertDialog
{
PikaImage *image;
PikaComponentType component_type;
PikaTRCType trc;
GeglDitherMethod layer_dither_method;
GeglDitherMethod text_layer_dither_method;
GeglDitherMethod channel_dither_method;
PikaConvertPrecisionCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void convert_precision_dialog_free (ConvertDialog *private);
static void convert_precision_dialog_response (GtkWidget *widget,
gint response_id,
ConvertDialog *private);
/* public functions */
GtkWidget *
convert_precision_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaComponentType component_type,
GeglDitherMethod layer_dither_method,
GeglDitherMethod text_layer_dither_method,
GeglDitherMethod channel_dither_method,
PikaConvertPrecisionCallback callback,
gpointer user_data)
{
ConvertDialog *private;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *perceptual_radio;
const gchar *enum_desc;
gchar *blurb;
const Babl *old_format;
const Babl *new_format;
gint old_bits;
gint new_bits;
gboolean dither;
PikaTRCType trc;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (callback != NULL, NULL);
/* random formats with the right precision */
old_format = pika_image_get_layer_format (image, FALSE);
new_format = pika_babl_format (PIKA_RGB,
pika_babl_precision (component_type, FALSE),
FALSE,
babl_format_get_space (old_format));
old_bits = (babl_format_get_bytes_per_pixel (old_format) * 8 /
babl_format_get_n_components (old_format));
new_bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
babl_format_get_n_components (new_format));
/* don't dither if we are converting to a higher bit depth,
* or to more than MAX_DITHER_BITS.
*/
dither = (new_bits < old_bits &&
new_bits <= CONVERT_PRECISION_DIALOG_MAX_DITHER_BITS);
trc = pika_babl_format_get_trc (old_format);
trc = pika_suggest_trc_for_component_type (component_type, trc);
private = g_slice_new0 (ConvertDialog);
private->image = image;
private->component_type = component_type;
private->trc = trc;
private->layer_dither_method = layer_dither_method;
private->text_layer_dither_method = text_layer_dither_method;
private->channel_dither_method = channel_dither_method;
private->callback = callback;
private->user_data = user_data;
pika_enum_get_value (PIKA_TYPE_COMPONENT_TYPE, component_type,
NULL, NULL, &enum_desc, NULL);
blurb = g_strdup_printf (_("Convert Image to %s"), enum_desc);
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Encoding Conversion"),
"pika-image-convert-precision",
PIKA_ICON_CONVERT_PRECISION,
blurb,
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_CONVERT_PRECISION,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_onvert"), GTK_RESPONSE_OK,
NULL);
g_free (blurb);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) convert_precision_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (convert_precision_dialog_response),
private);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
/* gamma */
frame = pika_frame_new (_("Gamma"));
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = pika_int_radio_group_new (FALSE, NULL,
G_CALLBACK (pika_radio_button_update),
&private->trc, NULL,
trc,
_("Linear light"),
PIKA_TRC_LINEAR, NULL,
_("Non-Linear"),
PIKA_TRC_NON_LINEAR, NULL,
_("Perceptual (sRGB)"),
PIKA_TRC_PERCEPTUAL, &perceptual_radio,
NULL);
if (private->trc != PIKA_TRC_PERCEPTUAL)
gtk_widget_hide (perceptual_radio);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
/* dithering */
if (dither)
{
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *combo;
GtkSizeGroup *size_group;
frame = pika_frame_new (_("Dithering"));
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* layers */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Layers:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, label);
gtk_widget_show (label);
combo = pika_enum_combo_box_new (GEGL_TYPE_DITHER_METHOD);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->layer_dither_method,
G_CALLBACK (pika_int_combo_box_get_active),
&private->layer_dither_method, NULL);
/* text layers */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Text Layers:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, label);
gtk_widget_show (label);
combo = pika_enum_combo_box_new (GEGL_TYPE_DITHER_METHOD);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->text_layer_dither_method,
G_CALLBACK (pika_int_combo_box_get_active),
&private->text_layer_dither_method, NULL);
pika_help_set_help_data (combo,
_("Dithering text layers will make them "
"uneditable"),
NULL);
/* channels */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Channels and Masks:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, label);
gtk_widget_show (label);
combo = pika_enum_combo_box_new (GEGL_TYPE_DITHER_METHOD);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->channel_dither_method,
G_CALLBACK (pika_int_combo_box_get_active),
&private->channel_dither_method, NULL);
g_object_unref (size_group);
}
return dialog;
}
/* private functions */
static void
convert_precision_dialog_free (ConvertDialog *private)
{
g_slice_free (ConvertDialog, private);
}
static void
convert_precision_dialog_response (GtkWidget *dialog,
gint response_id,
ConvertDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
PikaPrecision precision = pika_babl_precision (private->component_type,
private->trc);
private->callback (dialog,
private->image,
precision,
private->layer_dither_method,
private->text_layer_dither_method,
private->channel_dither_method,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
}

View File

@ -0,0 +1,54 @@
/* 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/>.
*/
#ifndef __CONVERT_PRECISION_DIALOG_H__
#define __CONVERT_PRECISION_DIALOG_H__
/* Don't offer dithering when converting down to more than this
* number of bits per component. Note that gegl:dither would
* do 16 bit, so this is a limitation of the GUI to values that make
* sense. See bug #735895.
*/
#define CONVERT_PRECISION_DIALOG_MAX_DITHER_BITS 8
typedef void (* PikaConvertPrecisionCallback) (GtkWidget *dialog,
PikaImage *image,
PikaPrecision precision,
GeglDitherMethod layer_dither_method,
GeglDitherMethod text_layer_dither_method,
GeglDitherMethod channel_dither_method,
gpointer user_data);
GtkWidget * convert_precision_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaComponentType component_type,
GeglDitherMethod layer_dither_method,
GeglDitherMethod text_layer_dither_method,
GeglDitherMethod channel_dither_method,
PikaConvertPrecisionCallback callback,
gpointer user_data);
#endif /* __CONVERT_PRECISION_DIALOG_H__ */

View File

@ -0,0 +1,164 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikacontext.h"
#include "core/pikadata.h"
#include "core/pikadatafactory.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "data-delete-dialog.h"
#include "pika-intl.h"
typedef struct _DataDeleteDialog DataDeleteDialog;
struct _DataDeleteDialog
{
PikaDataFactory *factory;
PikaData *data;
PikaContext *context;
GtkWidget *parent;
};
/* local function prototypes */
static void data_delete_dialog_response (GtkWidget *dialog,
gint response_id,
DataDeleteDialog *private);
/* public functions */
GtkWidget *
data_delete_dialog_new (PikaDataFactory *factory,
PikaData *data,
PikaContext *context,
GtkWidget *parent)
{
DataDeleteDialog *private;
GtkWidget *dialog;
g_return_val_if_fail (PIKA_IS_DATA_FACTORY (factory), NULL);
g_return_val_if_fail (PIKA_IS_DATA (data), NULL);
g_return_val_if_fail (context == NULL || PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
private = g_slice_new0 (DataDeleteDialog);
private->factory = factory;
private->data = data;
private->context = context;
private->parent = parent;
dialog = pika_message_dialog_new (_("Delete Object"),
PIKA_ICON_EDIT_DELETE,
gtk_widget_get_toplevel (parent), 0,
pika_standard_help_func, NULL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Delete"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect_object (data, "disconnect",
G_CALLBACK (gtk_widget_destroy),
dialog, G_CONNECT_SWAPPED);
g_signal_connect (dialog, "response",
G_CALLBACK (data_delete_dialog_response),
private);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("Delete '%s'?"),
pika_object_get_name (data));
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("Are you sure you want to remove '%s' "
"from the list and delete it on disk?"),
pika_object_get_name (data));
return dialog;
}
/* private functions */
static void
data_delete_dialog_response (GtkWidget *dialog,
gint response_id,
DataDeleteDialog *private)
{
gtk_widget_destroy (dialog);
if (response_id == GTK_RESPONSE_OK)
{
PikaDataFactory *factory = private->factory;
PikaData *data = private->data;
PikaContainer *container;
PikaObject *new_active = NULL;
GError *error = NULL;
container = pika_data_factory_get_container (factory);
if (private->context &&
PIKA_OBJECT (data) ==
pika_context_get_by_type (private->context,
pika_container_get_children_type (container)))
{
new_active = pika_container_get_neighbor_of (container,
PIKA_OBJECT (data));
}
if (! pika_data_factory_data_delete (factory, data, TRUE, &error))
{
pika_message (pika_data_factory_get_pika (factory),
G_OBJECT (private->parent), PIKA_MESSAGE_ERROR,
"%s", error->message);
g_clear_error (&error);
}
if (new_active)
pika_context_set_by_type (private->context,
pika_container_get_children_type (container),
new_active);
}
g_slice_free (DataDeleteDialog, private);
}

View File

@ -0,0 +1,32 @@
/* 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/>.
*/
#ifndef __DATA_DELETE_DIALOG_H__
#define __DATA_DELETE_DIALOG_H__
GtkWidget * data_delete_dialog_new (PikaDataFactory *factory,
PikaData *data,
PikaContext *context,
GtkWidget *parent);
#endif /* __DATA_DELETE_DIALOG_H__ */

View File

@ -0,0 +1,921 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "config/pikaguiconfig.h"
#include "menus/menus.h"
#include "widgets/pikabrusheditor.h"
#include "widgets/pikabrushfactoryview.h"
#include "widgets/pikabufferview.h"
#include "widgets/pikachanneltreeview.h"
#include "widgets/pikacoloreditor.h"
#include "widgets/pikacolormapeditor.h"
#include "widgets/pikacriticaldialog.h"
#include "widgets/pikadashboard.h"
#include "widgets/pikadevicestatus.h"
#include "widgets/pikadialogfactory.h"
#include "widgets/pikadockwindow.h"
#include "widgets/pikadocumentview.h"
#include "widgets/pikadynamicseditor.h"
#include "widgets/pikadynamicsfactoryview.h"
#include "widgets/pikaerrorconsole.h"
#include "widgets/pikaerrordialog.h"
#include "widgets/pikafontfactoryview.h"
#include "widgets/pikagradienteditor.h"
#include "widgets/pikahistogrameditor.h"
#include "widgets/pikaimageview.h"
#include "widgets/pikalayertreeview.h"
#include "widgets/pikamenudock.h"
#include "widgets/pikapaletteeditor.h"
#include "widgets/pikapatternfactoryview.h"
#include "widgets/pikasamplepointeditor.h"
#include "widgets/pikaselectioneditor.h"
#include "widgets/pikasymmetryeditor.h"
#include "widgets/pikatemplateview.h"
#include "widgets/pikatoolbox.h"
#include "widgets/pikatooloptionseditor.h"
#include "widgets/pikatoolpresetfactoryview.h"
#include "widgets/pikatoolpreseteditor.h"
#include "widgets/pikaundoeditor.h"
#include "widgets/pikavectorstreeview.h"
#include "display/pikacursorview.h"
#include "display/pikanavigationeditor.h"
#include "about-dialog.h"
#include "action-search-dialog.h"
#include "dialogs.h"
#include "dialogs-constructors.h"
#include "extensions-dialog.h"
#include "file-open-dialog.h"
#include "file-open-location-dialog.h"
#include "file-save-dialog.h"
#include "image-new-dialog.h"
#include "input-devices-dialog.h"
#include "keyboard-shortcuts-dialog.h"
#include "module-dialog.h"
#include "palette-import-dialog.h"
#include "preferences-dialog.h"
#include "quit-dialog.h"
#include "tips-dialog.h"
#include "welcome-dialog.h"
#include "pika-intl.h"
/**********************/
/* toplevel dialogs */
/**********************/
GtkWidget *
dialogs_image_new_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return image_new_dialog_new (context);
}
GtkWidget *
dialogs_file_open_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return file_open_dialog_new (context->pika);
}
GtkWidget *
dialogs_file_open_location_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return file_open_location_dialog_new (context->pika);
}
GtkWidget *
dialogs_file_save_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return file_save_dialog_new (context->pika, FALSE);
}
GtkWidget *
dialogs_file_export_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return file_save_dialog_new (context->pika, TRUE);
}
GtkWidget *
dialogs_preferences_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return preferences_dialog_create (context->pika);
}
GtkWidget *
dialogs_extensions_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return extensions_dialog_new (context->pika);
}
GtkWidget *
dialogs_keyboard_shortcuts_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return keyboard_shortcuts_dialog_new (context->pika);
}
GtkWidget *
dialogs_input_devices_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return input_devices_dialog_new (context->pika);
}
GtkWidget *
dialogs_module_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return module_dialog_new (context->pika);
}
GtkWidget *
dialogs_palette_import_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return palette_import_dialog_new (context);
}
GtkWidget *
dialogs_tips_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return tips_dialog_create (context->pika);
}
GtkWidget *
dialogs_welcome_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return welcome_dialog_create (context->pika);
}
GtkWidget *
dialogs_about_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return about_dialog_create (context->pika->edit_config);
}
GtkWidget *
dialogs_action_search_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return action_search_dialog_create (context->pika);
}
GtkWidget *
dialogs_error_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_error_dialog_new (_("PIKA Message"));
}
GtkWidget *
dialogs_critical_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_critical_dialog_new (_("PIKA Debug"),
context->pika->config->last_known_release,
context->pika->config->last_release_timestamp);
}
GtkWidget *
dialogs_close_all_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return close_all_dialog_new (context->pika);
}
GtkWidget *
dialogs_quit_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return quit_dialog_new (context->pika);
}
/***********/
/* docks */
/***********/
GtkWidget *
dialogs_toolbox_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_toolbox_new (factory,
context,
ui_manager);
}
GtkWidget *
dialogs_toolbox_dock_window_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
static gint role_serial = 1;
GtkWidget *dock;
gchar *role;
role = g_strdup_printf ("pika-toolbox-%d", role_serial++);
dock = pika_dock_window_new (role,
"<Toolbox>",
TRUE,
factory,
context);
g_free (role);
return dock;
}
GtkWidget *
dialogs_dock_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_menu_dock_new ();
}
GtkWidget *
dialogs_dock_window_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
static gint role_serial = 1;
GtkWidget *dock;
gchar *role;
role = g_strdup_printf ("pika-dock-%d", role_serial++);
dock = pika_dock_window_new (role,
"<Dock>",
FALSE,
factory,
context);
g_free (role);
return dock;
}
/***************/
/* dockables */
/***************/
/***** singleton dialogs *****/
GtkWidget *
dialogs_tool_options_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_tool_options_editor_new (context->pika,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_device_status_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_device_status_new (context->pika);
}
GtkWidget *
dialogs_error_console_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_error_console_new (context->pika,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_cursor_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_cursor_view_new (context->pika,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_dashboard_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_dashboard_new (context->pika,
menus_get_global_menu_factory (context->pika));
}
/***** list views *****/
GtkWidget *
dialogs_image_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_image_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->images,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_brush_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_brush_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->brush_factory,
context,
TRUE,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_dynamics_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_dynamics_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->dynamics_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_mypaint_brush_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_data_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->mybrush_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika),
"<MyPaintBrushes>",
"/mypaint-brushes-popup",
"mypaint-brushes");
}
GtkWidget *
dialogs_pattern_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_pattern_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->pattern_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_gradient_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_data_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->gradient_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika),
"<Gradients>",
"/gradients-popup",
"gradients");
}
GtkWidget *
dialogs_palette_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_data_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->palette_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika),
"<Palettes>",
"/palettes-popup",
"palettes");
}
GtkWidget *
dialogs_font_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_font_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->font_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_buffer_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_buffer_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->named_buffers,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_tool_preset_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_tool_preset_factory_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->tool_preset_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_document_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_document_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->documents,
context,
view_size, 0,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_template_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_template_view_new (PIKA_VIEW_TYPE_LIST,
context->pika->templates,
context,
view_size, 0,
menus_get_global_menu_factory (context->pika));
}
/***** grid views *****/
GtkWidget *
dialogs_image_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_image_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->images,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_brush_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_brush_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->brush_factory,
context,
TRUE,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_dynamics_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_dynamics_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->dynamics_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_mypaint_brush_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_data_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->mybrush_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika),
"<MyPaintBrushes>",
"/mypaint-brushes-popup",
"mypaint-brushes");
}
GtkWidget *
dialogs_pattern_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_pattern_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->pattern_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_gradient_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_data_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->gradient_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika),
"<Gradients>",
"/gradients-popup",
"gradients");
}
GtkWidget *
dialogs_palette_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_data_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->palette_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika),
"<Palettes>",
"/palettes-popup",
"palettes");
}
GtkWidget *
dialogs_font_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_font_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->font_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_buffer_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_buffer_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->named_buffers,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_tool_preset_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_tool_preset_factory_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->tool_preset_factory,
context,
view_size, 1,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_document_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_document_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->documents,
context,
view_size, 0,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_template_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_template_view_new (PIKA_VIEW_TYPE_GRID,
context->pika->templates,
context,
view_size, 0,
menus_get_global_menu_factory (context->pika));
}
/***** image related dialogs *****/
GtkWidget *
dialogs_layer_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
if (view_size < 1)
view_size = context->pika->config->layer_preview_size;
return pika_item_tree_view_new (PIKA_TYPE_LAYER_TREE_VIEW,
view_size, 2, TRUE,
pika_context_get_image (context),
menus_get_global_menu_factory (context->pika),
"<Layers>",
"/layers-popup");
}
GtkWidget *
dialogs_channel_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
if (view_size < 1)
view_size = context->pika->config->layer_preview_size;
return pika_item_tree_view_new (PIKA_TYPE_CHANNEL_TREE_VIEW,
view_size, 1, TRUE,
pika_context_get_image (context),
menus_get_global_menu_factory (context->pika),
"<Channels>",
"/channels-popup");
}
GtkWidget *
dialogs_vectors_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
if (view_size < 1)
view_size = context->pika->config->layer_preview_size;
return pika_item_tree_view_new (PIKA_TYPE_VECTORS_TREE_VIEW,
view_size, 1, TRUE,
pika_context_get_image (context),
menus_get_global_menu_factory (context->pika),
"<Vectors>",
"/vectors-popup");
}
GtkWidget *
dialogs_colormap_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_colormap_editor_new (menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_histogram_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_histogram_editor_new ();
}
GtkWidget *
dialogs_selection_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_selection_editor_new (menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_symmetry_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_symmetry_editor_new (menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_undo_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_undo_editor_new (context->pika->config,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_sample_point_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_sample_point_editor_new (menus_get_global_menu_factory (context->pika));
}
/***** display related dialogs *****/
GtkWidget *
dialogs_navigation_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_navigation_editor_new (menus_get_global_menu_factory (context->pika));
}
/***** misc dockables *****/
GtkWidget *
dialogs_color_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_color_editor_new (context);
}
/*************/
/* editors */
/*************/
GtkWidget *
dialogs_brush_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_brush_editor_new (context,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_dynamics_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_dynamics_editor_new (context,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_gradient_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_gradient_editor_new (context,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_palette_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_palette_editor_new (context,
menus_get_global_menu_factory (context->pika));
}
GtkWidget *
dialogs_tool_preset_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size)
{
return pika_tool_preset_editor_new (context,
menus_get_global_menu_factory (context->pika));
}

View File

@ -0,0 +1,320 @@
/* 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/>.
*/
#ifndef __DIALOGS_CONSTRUCTORS_H__
#define __DIALOGS_CONSTRUCTORS_H__
/* toplevel dialogs */
GtkWidget * dialogs_image_new_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_file_open_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_file_open_location_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_file_save_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_file_export_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_preferences_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_extensions_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_input_devices_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_keyboard_shortcuts_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_module_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_palette_import_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_tips_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_welcome_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_about_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_action_search_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_error_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_critical_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_close_all_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_quit_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
/* docks */
GtkWidget * dialogs_toolbox_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_toolbox_dock_window_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_dock_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_dock_window_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
/* dockables */
GtkWidget * dialogs_tool_options_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_device_status_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_error_console_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_cursor_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_dashboard_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_image_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_brush_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_dynamics_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_mypaint_brush_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_pattern_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_gradient_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_palette_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_font_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_buffer_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_tool_preset_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_document_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_template_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_image_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_brush_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_dynamics_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_mypaint_brush_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_pattern_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_gradient_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_palette_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_font_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_buffer_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_tool_preset_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_document_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_template_grid_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_layer_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_channel_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_vectors_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_path_list_view_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_colormap_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_histogram_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_selection_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_symmetry_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_undo_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_sample_point_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_navigation_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_color_editor_new (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_brush_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_dynamics_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_gradient_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_palette_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
GtkWidget * dialogs_tool_preset_editor_get (PikaDialogFactory *factory,
PikaContext *context,
PikaUIManager *ui_manager,
gint view_size);
#endif /* __DIALOGS_CONSTRUCTORS_H__ */

View File

@ -0,0 +1,41 @@
/* 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/>.
*/
#ifndef __DIALOGS_TYPES_H__
#define __DIALOGS_TYPES_H__
#include "display/display-types.h"
typedef void (* PikaScaleCallback) (GtkWidget *dialog,
PikaViewable *viewable,
gint width,
gint height,
PikaUnit unit,
PikaInterpolationType interpolation,
gdouble xresolution,
gdouble yresolution,
PikaUnit resolution_unit,
gpointer user_data);
#endif /* __DIALOGS_TYPES_H__ */

752
app/dialogs/dialogs.c Normal file
View File

@ -0,0 +1,752 @@
/* 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
*
* dialogs.c
* Copyright (C) 2010 Martin Nordholts <martinn@src.gnome.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikaguiconfig.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikalist.h"
#include "widgets/pikadialogfactory.h"
#include "widgets/pikadockwindow.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamenufactory.h"
#include "widgets/pikasessioninfo.h"
#include "widgets/pikasessioninfo-aux.h"
#include "widgets/pikasessionmanaged.h"
#include "widgets/pikatoolbox.h"
#include "dialogs.h"
#include "dialogs-constructors.h"
#include "pika-log.h"
#include "pika-intl.h"
PikaContainer *global_recent_docks = NULL;
#define FOREIGN(id, singleton, remember_size) \
{ id /* identifier */, \
NULL /* name */, \
NULL /* blurb */, \
NULL /* icon_name */, \
NULL /* help_id */, \
NULL /* new_func */, \
dialogs_restore_dialog /* restore_func */, \
0 /* view_size */, \
singleton /* singleton */, \
TRUE /* session_managed */, \
remember_size /* remember_size */, \
FALSE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
FALSE /* dockable */}
#define IMAGE_WINDOW(id, singleton, remember_size) \
{ id /* identifier */, \
NULL /* name */, \
NULL /* blurb */, \
NULL /* icon_name */, \
NULL /* help_id */, \
NULL /* new_func */, \
dialogs_restore_window /* restore_func */, \
0 /* view_size */, \
singleton /* singleton */, \
TRUE /* session_managed */, \
remember_size /* remember_size */, \
TRUE /* remember_if_open */, \
FALSE /* hideable */, \
TRUE /* image_window */, \
FALSE /* dockable */}
#define TOPLEVEL(id, new_func, singleton, session_managed, remember_size) \
{ id /* identifier */, \
NULL /* name */, \
NULL /* blurb */, \
NULL /* icon_name */, \
NULL /* help_id */, \
new_func /* new_func */, \
dialogs_restore_dialog /* restore_func */, \
0 /* view_size */, \
singleton /* singleton */, \
session_managed /* session_managed */, \
remember_size /* remember_size */, \
FALSE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
FALSE /* dockable */}
#define DOCKABLE(id, name, blurb, icon_name, help_id, new_func, view_size, singleton) \
{ id /* identifier */, \
name /* name */, \
blurb /* blurb */, \
icon_name /* icon_name */, \
help_id /* help_id */, \
new_func /* new_func */, \
NULL /* restore_func */, \
view_size /* view_size */, \
singleton /* singleton */, \
FALSE /* session_managed */, \
FALSE /* remember_size */, \
TRUE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
TRUE /* dockable */}
#define DOCK(id, new_func) \
{ id /* identifier */, \
NULL /* name */, \
NULL /* blurb */, \
NULL /* icon_name */, \
NULL /* help_id */, \
new_func /* new_func */, \
dialogs_restore_dialog /* restore_func */, \
0 /* view_size */, \
FALSE /* singleton */, \
FALSE /* session_managed */, \
FALSE /* remember_size */, \
FALSE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
FALSE /* dockable */}
#define DOCK_WINDOW(id, new_func) \
{ id /* identifier */, \
NULL /* name */, \
NULL /* blurb */, \
NULL /* icon_name */, \
NULL /* help_id */, \
new_func /* new_func */, \
dialogs_restore_dialog /* restore_func */, \
0 /* view_size */, \
FALSE /* singleton */, \
TRUE /* session_managed */, \
TRUE /* remember_size */, \
TRUE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
FALSE /* dockable */}
#define LISTGRID(id, new_func, name, blurb, icon_name, help_id, view_size) \
{ "pika-"#id"-list" /* identifier */, \
name /* name */, \
blurb /* blurb */, \
icon_name /* icon_name */, \
help_id /* help_id */, \
dialogs_##new_func##_list_view_new /* new_func */, \
NULL /* restore_func */, \
view_size /* view_size */, \
FALSE /* singleton */, \
FALSE /* session_managed */, \
FALSE /* remember_size */, \
TRUE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
TRUE /* dockable */}, \
{ "pika-"#id"-grid" /* identifier */, \
name /* name */, \
blurb /* blurb */, \
icon_name /* icon_name */, \
help_id /* help_id */, \
dialogs_##new_func##_grid_view_new /* new_func */, \
NULL /* restore_func */, \
view_size /* view_size */, \
FALSE /* singleton */, \
FALSE /* session_managed */, \
FALSE /* remember_size */, \
TRUE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
TRUE /* dockable */}
#define LIST(id, new_func, name, blurb, icon_name, help_id, view_size) \
{ "pika-"#id"-list" /* identifier */, \
name /* name */, \
blurb /* blurb */, \
icon_name /* icon_name */, \
help_id /* help_id */, \
dialogs_##new_func##_list_view_new /* new_func */, \
NULL /* restore_func */, \
view_size /* view_size */, \
FALSE /* singleton */, \
FALSE /* session_managed */, \
FALSE /* remember_size */, \
TRUE /* remember_if_open */, \
TRUE /* hideable */, \
FALSE /* image_window */, \
TRUE /* dockable */}
static GtkWidget * dialogs_restore_dialog (PikaDialogFactory *factory,
GdkMonitor *monitor,
PikaSessionInfo *info);
static GtkWidget * dialogs_restore_window (PikaDialogFactory *factory,
GdkMonitor *monitor,
PikaSessionInfo *info);
static const PikaDialogFactoryEntry entries[] =
{
/* foreign toplevels without constructor */
FOREIGN ("pika-brightness-contrast-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-color-balance-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-color-picker-tool-dialog", TRUE, TRUE),
FOREIGN ("pika-colorize-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-crop-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-curves-tool-dialog", TRUE, TRUE),
FOREIGN ("pika-desaturate-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-foreground-select-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-gegl-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-gradient-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-hue-saturation-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-levels-tool-dialog", TRUE, TRUE),
FOREIGN ("pika-measure-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-offset-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-operation-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-posterize-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-rotate-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-scale-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-shear-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-text-tool-dialog", TRUE, TRUE),
FOREIGN ("pika-threshold-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-transform-3d-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-perspective-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-unified-transform-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-handle-transform-tool-dialog", TRUE, FALSE),
FOREIGN ("pika-toolbox-color-dialog", TRUE, FALSE),
FOREIGN ("pika-gradient-editor-color-dialog", TRUE, FALSE),
FOREIGN ("pika-palette-editor-color-dialog", TRUE, FALSE),
FOREIGN ("pika-colormap-editor-color-dialog", TRUE, FALSE),
FOREIGN ("pika-colormap-selection-color-dialog", TRUE, FALSE),
FOREIGN ("pika-controller-editor-dialog", FALSE, TRUE),
FOREIGN ("pika-controller-action-dialog", FALSE, TRUE),
/* ordinary toplevels */
TOPLEVEL ("pika-image-new-dialog",
dialogs_image_new_new, FALSE, TRUE, FALSE),
TOPLEVEL ("pika-file-open-dialog",
dialogs_file_open_new, TRUE, TRUE, TRUE),
TOPLEVEL ("pika-file-open-location-dialog",
dialogs_file_open_location_new, FALSE, TRUE, FALSE),
TOPLEVEL ("pika-file-save-dialog",
dialogs_file_save_new, FALSE, TRUE, TRUE),
TOPLEVEL ("pika-file-export-dialog",
dialogs_file_export_new, FALSE, TRUE, TRUE),
/* singleton toplevels */
TOPLEVEL ("pika-preferences-dialog",
dialogs_preferences_get, TRUE, TRUE, TRUE),
TOPLEVEL ("pika-input-devices-dialog",
dialogs_input_devices_get, TRUE, TRUE, FALSE),
TOPLEVEL ("pika-keyboard-shortcuts-dialog",
dialogs_keyboard_shortcuts_get, TRUE, TRUE, TRUE),
TOPLEVEL ("pika-module-dialog",
dialogs_module_get, TRUE, TRUE, TRUE),
TOPLEVEL ("pika-palette-import-dialog",
dialogs_palette_import_get, TRUE, TRUE, TRUE),
TOPLEVEL ("pika-tips-dialog",
dialogs_tips_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-welcome-dialog",
dialogs_welcome_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-about-dialog",
dialogs_about_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-action-search-dialog",
dialogs_action_search_get, TRUE, TRUE, TRUE),
TOPLEVEL ("pika-error-dialog",
dialogs_error_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-critical-dialog",
dialogs_critical_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-close-all-dialog",
dialogs_close_all_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-quit-dialog",
dialogs_quit_get, TRUE, FALSE, FALSE),
TOPLEVEL ("pika-extensions-dialog",
dialogs_extensions_get, TRUE, TRUE, TRUE),
/* docks */
DOCK ("pika-dock",
dialogs_dock_new),
DOCK ("pika-toolbox",
dialogs_toolbox_new),
/* dock windows */
DOCK_WINDOW ("pika-dock-window",
dialogs_dock_window_new),
DOCK_WINDOW ("pika-toolbox-window",
dialogs_toolbox_dock_window_new),
/* singleton dockables */
DOCKABLE ("pika-tool-options",
N_("Tool Options"), NULL, PIKA_ICON_DIALOG_TOOL_OPTIONS,
PIKA_HELP_TOOL_OPTIONS_DIALOG,
dialogs_tool_options_new, 0, TRUE),
DOCKABLE ("pika-device-status",
N_("Devices"), N_("Device Status"), PIKA_ICON_DIALOG_DEVICE_STATUS,
PIKA_HELP_DEVICE_STATUS_DIALOG,
dialogs_device_status_new, 0, TRUE),
DOCKABLE ("pika-error-console",
N_("Errors"), N_("Error Console"), PIKA_ICON_DIALOG_WARNING,
PIKA_HELP_ERRORS_DIALOG,
dialogs_error_console_new, 0, TRUE),
DOCKABLE ("pika-cursor-view",
N_("Pointer"), N_("Pointer Information"), PIKA_ICON_CURSOR,
PIKA_HELP_POINTER_INFO_DIALOG,
dialogs_cursor_view_new, 0, TRUE),
DOCKABLE ("pika-dashboard",
N_("Dashboard"), N_("Dashboard"), PIKA_ICON_DIALOG_DASHBOARD,
PIKA_HELP_DASHBOARD_DIALOG,
dialogs_dashboard_new, 0, TRUE),
/* list & grid views */
LISTGRID (image, image,
N_("Images"), NULL, PIKA_ICON_DIALOG_IMAGES,
PIKA_HELP_IMAGE_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (brush, brush,
N_("Brushes"), NULL, PIKA_ICON_BRUSH,
PIKA_HELP_BRUSH_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (dynamics, dynamics,
N_("Paint Dynamics"), NULL, PIKA_ICON_DYNAMICS,
PIKA_HELP_DYNAMICS_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (mypaint-brush, mypaint_brush,
N_("MyPaint Brushes"), NULL, PIKA_ICON_MYPAINT_BRUSH,
PIKA_HELP_MYPAINT_BRUSH_DIALOG, PIKA_VIEW_SIZE_LARGE),
LISTGRID (pattern, pattern,
N_("Patterns"), NULL, PIKA_ICON_PATTERN,
PIKA_HELP_PATTERN_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (gradient, gradient,
N_("Gradients"), NULL, PIKA_ICON_GRADIENT,
PIKA_HELP_GRADIENT_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (palette, palette,
N_("Palettes"), NULL, PIKA_ICON_PALETTE,
PIKA_HELP_PALETTE_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (font, font,
N_("Fonts"), NULL, PIKA_ICON_FONT,
PIKA_HELP_FONT_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (buffer, buffer,
N_("Buffers"), NULL, PIKA_ICON_BUFFER,
PIKA_HELP_BUFFER_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (tool-preset, tool_preset,
N_("Tool Presets"), NULL, PIKA_ICON_TOOL_PRESET,
PIKA_HELP_TOOL_PRESET_DIALOG, PIKA_VIEW_SIZE_MEDIUM),
LISTGRID (document, document,
N_("History"), N_("Document History"), PIKA_ICON_DOCUMENT_OPEN_RECENT,
PIKA_HELP_DOCUMENT_DIALOG, PIKA_VIEW_SIZE_LARGE),
LISTGRID (template, template,
N_("Templates"), N_("Image Templates"), PIKA_ICON_TEMPLATE,
PIKA_HELP_TEMPLATE_DIALOG, PIKA_VIEW_SIZE_SMALL),
/* image related */
DOCKABLE ("pika-layer-list",
N_("Layers"), NULL, PIKA_ICON_DIALOG_LAYERS,
PIKA_HELP_LAYER_DIALOG,
dialogs_layer_list_view_new, 0, FALSE),
DOCKABLE ("pika-channel-list",
N_("Channels"), NULL, PIKA_ICON_DIALOG_CHANNELS,
PIKA_HELP_CHANNEL_DIALOG,
dialogs_channel_list_view_new, 0, FALSE),
DOCKABLE ("pika-vectors-list",
N_("Paths"), NULL, PIKA_ICON_DIALOG_PATHS,
PIKA_HELP_PATH_DIALOG,
dialogs_vectors_list_view_new, 0, FALSE),
DOCKABLE ("pika-indexed-palette",
N_("Colormap"), NULL, PIKA_ICON_COLORMAP,
PIKA_HELP_INDEXED_PALETTE_DIALOG,
dialogs_colormap_editor_new, 0, FALSE),
DOCKABLE ("pika-histogram-editor",
N_("Histogram"), NULL, PIKA_ICON_HISTOGRAM,
PIKA_HELP_HISTOGRAM_DIALOG,
dialogs_histogram_editor_new, 0, FALSE),
DOCKABLE ("pika-selection-editor",
N_("Selection"), N_("Selection Editor"), PIKA_ICON_SELECTION,
PIKA_HELP_SELECTION_DIALOG,
dialogs_selection_editor_new, 0, FALSE),
DOCKABLE ("pika-symmetry-editor",
N_("Symmetry Painting"), NULL, PIKA_ICON_SYMMETRY,
PIKA_HELP_SYMMETRY_DIALOG,
dialogs_symmetry_editor_new, 0, FALSE),
DOCKABLE ("pika-undo-history",
N_("Undo"), N_("Undo History"), PIKA_ICON_DIALOG_UNDO_HISTORY,
PIKA_HELP_UNDO_DIALOG,
dialogs_undo_editor_new, 0, FALSE),
DOCKABLE ("pika-sample-point-editor",
N_("Sample Points"), N_("Sample Points"), PIKA_ICON_SAMPLE_POINT,
PIKA_HELP_SAMPLE_POINT_DIALOG,
dialogs_sample_point_editor_new, 0, FALSE),
/* display related */
DOCKABLE ("pika-navigation-view",
N_("Navigation"), N_("Display Navigation"), PIKA_ICON_DIALOG_NAVIGATION,
PIKA_HELP_NAVIGATION_DIALOG,
dialogs_navigation_editor_new, 0, FALSE),
/* editors */
DOCKABLE ("pika-color-editor",
N_("FG/BG"), N_("FG/BG Color"), PIKA_ICON_COLORS_DEFAULT,
PIKA_HELP_COLOR_DIALOG,
dialogs_color_editor_new, 0, FALSE),
/* singleton editors */
DOCKABLE ("pika-brush-editor",
N_("Brush Editor"), NULL, PIKA_ICON_BRUSH,
PIKA_HELP_BRUSH_EDITOR_DIALOG,
dialogs_brush_editor_get, 0, TRUE),
DOCKABLE ("pika-dynamics-editor",
N_("Paint Dynamics Editor"), NULL, PIKA_ICON_DYNAMICS,
PIKA_HELP_DYNAMICS_EDITOR_DIALOG,
dialogs_dynamics_editor_get, 0, TRUE),
DOCKABLE ("pika-gradient-editor",
N_("Gradient Editor"), NULL, PIKA_ICON_GRADIENT,
PIKA_HELP_GRADIENT_EDITOR_DIALOG,
dialogs_gradient_editor_get, 0, TRUE),
DOCKABLE ("pika-palette-editor",
N_("Palette Editor"), NULL, PIKA_ICON_PALETTE,
PIKA_HELP_PALETTE_EDITOR_DIALOG,
dialogs_palette_editor_get, 0, TRUE),
DOCKABLE ("pika-tool-preset-editor",
N_("Tool Preset Editor"), NULL, PIKA_ICON_TOOL_PRESET,
PIKA_HELP_TOOL_PRESET_EDITOR_DIALOG,
dialogs_tool_preset_editor_get, 0, TRUE),
/* image windows */
IMAGE_WINDOW ("pika-empty-image-window",
TRUE, TRUE),
IMAGE_WINDOW ("pika-single-image-window",
TRUE, TRUE)
};
/**
* dialogs_restore_dialog:
* @factory:
* @screen:
* @info:
*
* Creates a top level widget based on the given session info object
* in which other widgets later can be be put, typically also restored
* from the same session info object.
*
* Returns:
**/
static GtkWidget *
dialogs_restore_dialog (PikaDialogFactory *factory,
GdkMonitor *monitor,
PikaSessionInfo *info)
{
GtkWidget *dialog;
Pika *pika = pika_dialog_factory_get_context (factory)->pika;
PikaCoreConfig *config = pika->config;
PikaDisplay *display = pika_context_get_display (pika_get_user_context (pika));
PikaDisplayShell *shell = pika_display_get_shell (display);
PIKA_LOG (DIALOG_FACTORY, "restoring toplevel \"%s\" (info %p)",
pika_session_info_get_factory_entry (info)->identifier,
info);
dialog =
pika_dialog_factory_dialog_new (factory, monitor,
NULL /*ui_manager*/,
GTK_WIDGET (pika_display_shell_get_window (shell)),
pika_session_info_get_factory_entry (info)->identifier,
pika_session_info_get_factory_entry (info)->view_size,
! PIKA_GUI_CONFIG (config)->hide_docks);
g_object_set_data (G_OBJECT (dialog), PIKA_DIALOG_VISIBILITY_KEY,
GINT_TO_POINTER (PIKA_GUI_CONFIG (config)->hide_docks ?
PIKA_DIALOG_VISIBILITY_HIDDEN :
PIKA_DIALOG_VISIBILITY_VISIBLE));
return dialog;
}
/**
* dialogs_restore_window:
* @factory:
* @monitor:
* @info:
*
* "restores" the image window. We don't really restore anything since
* the image window is created earlier, so we just look for and return
* the already-created image window.
*
* Returns:
**/
static GtkWidget *
dialogs_restore_window (PikaDialogFactory *factory,
GdkMonitor *monitor,
PikaSessionInfo *info)
{
Pika *pika = pika_dialog_factory_get_context (factory)->pika;
PikaDisplay *display = PIKA_DISPLAY (pika_get_empty_display (pika));
PikaDisplayShell *shell = pika_display_get_shell (display);
GtkWidget *dialog;
dialog = GTK_WIDGET (pika_display_shell_get_window (shell));
return dialog;
}
/* public functions */
void
dialogs_init (Pika *pika)
{
PikaDialogFactory *factory = NULL;
gint i = 0;
g_return_if_fail (PIKA_IS_PIKA (pika));
factory = pika_dialog_factory_new ("toplevel", pika_get_user_context (pika));
pika_dialog_factory_set_singleton (factory);
for (i = 0; i < G_N_ELEMENTS (entries); i++)
pika_dialog_factory_register_entry (factory,
entries[i].identifier,
entries[i].name ? gettext(entries[i].name) : NULL,
entries[i].blurb ? gettext(entries[i].blurb) : NULL,
entries[i].icon_name,
entries[i].help_id,
entries[i].new_func,
entries[i].restore_func,
entries[i].view_size,
entries[i].singleton,
entries[i].session_managed,
entries[i].remember_size,
entries[i].remember_if_open,
entries[i].hideable,
entries[i].image_window,
entries[i].dockable);
global_recent_docks = pika_list_new (PIKA_TYPE_SESSION_INFO, FALSE);
}
void
dialogs_exit (Pika *pika)
{
g_return_if_fail (PIKA_IS_PIKA (pika));
if (pika_dialog_factory_get_singleton ())
{
/* run dispose manually so the factory destroys its dialogs, which
* might in turn directly or indirectly ref the factory
*/
g_object_run_dispose (G_OBJECT (pika_dialog_factory_get_singleton ()));
g_object_unref (pika_dialog_factory_get_singleton ());
pika_dialog_factory_set_singleton (NULL);
}
g_clear_object (&global_recent_docks);
}
static void
dialogs_ensure_factory_entry_on_recent_dock (PikaSessionInfo *info)
{
if (! pika_session_info_get_factory_entry (info))
{
PikaDialogFactoryEntry *entry = NULL;
/* The recent docks container only contains session infos for
* dock windows
*/
entry = pika_dialog_factory_find_entry (pika_dialog_factory_get_singleton (),
"pika-dock-window");
pika_session_info_set_factory_entry (info, entry);
}
}
static GFile *
dialogs_get_dockrc_file (void)
{
const gchar *basename;
basename = g_getenv ("PIKA_TESTING_DOCKRC_NAME");
if (! basename)
basename = "dockrc";
return pika_directory_file (basename, NULL);
}
void
dialogs_load_recent_docks (Pika *pika)
{
GFile *file;
GError *error = NULL;
g_return_if_fail (PIKA_IS_PIKA (pika));
file = dialogs_get_dockrc_file ();
if (pika->be_verbose)
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
if (! pika_config_deserialize_file (PIKA_CONFIG (global_recent_docks),
file,
NULL, &error))
{
if (error->code != PIKA_CONFIG_ERROR_OPEN_ENOENT)
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
g_clear_error (&error);
}
g_object_unref (file);
/* In PIKA 2.6 dockrc did not contain the factory entries for the
* session infos, so set that up manually if needed
*/
pika_container_foreach (global_recent_docks,
(GFunc) dialogs_ensure_factory_entry_on_recent_dock,
NULL);
pika_list_reverse (PIKA_LIST (global_recent_docks));
}
void
dialogs_save_recent_docks (Pika *pika)
{
GFile *file;
GError *error = NULL;
g_return_if_fail (PIKA_IS_PIKA (pika));
file = dialogs_get_dockrc_file ();
if (pika->be_verbose)
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
if (! pika_config_serialize_to_file (PIKA_CONFIG (global_recent_docks),
file,
"recently closed docks",
"end of recently closed docks",
NULL, &error))
{
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
g_clear_error (&error);
}
g_object_unref (file);
}
GtkWidget *
dialogs_get_toolbox (void)
{
GList *list;
g_return_val_if_fail (PIKA_IS_DIALOG_FACTORY (pika_dialog_factory_get_singleton ()), NULL);
for (list = pika_dialog_factory_get_open_dialogs (pika_dialog_factory_get_singleton ());
list;
list = g_list_next (list))
{
if (PIKA_IS_DOCK_WINDOW (list->data) &&
pika_dock_window_has_toolbox (list->data))
return list->data;
}
return NULL;
}
GtkWidget *
dialogs_get_dialog (GObject *attach_object,
const gchar *attach_key)
{
g_return_val_if_fail (G_IS_OBJECT (attach_object), NULL);
g_return_val_if_fail (attach_key != NULL, NULL);
return g_object_get_data (attach_object, attach_key);
}
void
dialogs_attach_dialog (GObject *attach_object,
const gchar *attach_key,
GtkWidget *dialog)
{
g_return_if_fail (G_IS_OBJECT (attach_object));
g_return_if_fail (attach_key != NULL);
g_return_if_fail (GTK_IS_WIDGET (dialog));
g_object_set_data (attach_object, attach_key, dialog);
g_object_set_data (G_OBJECT (dialog), "pika-dialogs-attach-key",
(gpointer) attach_key);
g_signal_connect_object (dialog, "destroy",
G_CALLBACK (dialogs_detach_dialog),
attach_object,
G_CONNECT_SWAPPED);
}
void
dialogs_detach_dialog (GObject *attach_object,
GtkWidget *dialog)
{
const gchar *attach_key;
g_return_if_fail (G_IS_OBJECT (attach_object));
g_return_if_fail (GTK_IS_WIDGET (dialog));
attach_key = g_object_get_data (G_OBJECT (dialog),
"pika-dialogs-attach-key");
g_return_if_fail (attach_key != NULL);
g_object_set_data (attach_object, attach_key, NULL);
g_signal_handlers_disconnect_by_func (dialog,
dialogs_detach_dialog,
attach_object);
}
void
dialogs_destroy_dialog (GObject *attach_object,
const gchar *attach_key)
{
GtkWidget *dialog;
g_return_if_fail (G_IS_OBJECT (attach_object));
g_return_if_fail (attach_key != NULL);
dialog = g_object_get_data (attach_object, attach_key);
if (dialog)
gtk_widget_destroy (dialog);
}

53
app/dialogs/dialogs.h Normal file
View File

@ -0,0 +1,53 @@
/* 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/>.
*/
#ifndef __DIALOGS_H__
#define __DIALOGS_H__
extern PikaDialogFactory *global_dialog_factory;
extern PikaContainer *global_recent_docks;
void dialogs_init (Pika *pika);
void dialogs_exit (Pika *pika);
void dialogs_load_recent_docks (Pika *pika);
void dialogs_save_recent_docks (Pika *pika);
GtkWidget * dialogs_get_toolbox (void);
/* attaching dialogs to arbitrary objects, and detaching them
* automatically upon destruction
*/
GtkWidget * dialogs_get_dialog (GObject *attach_object,
const gchar *attach_key);
void dialogs_attach_dialog (GObject *attach_object,
const gchar *attach_key,
GtkWidget *dialog);
void dialogs_detach_dialog (GObject *attach_object,
GtkWidget *dialog);
void dialogs_destroy_dialog (GObject *attach_object,
const gchar *attach_key);
#endif /* __DIALOGS_H__ */

View File

@ -0,0 +1,273 @@
/* 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-1997 Spencer Kimball and Peter Mattis
*
* extension-dialog.c
* Copyright (C) 2018 Jehan <jehan@gimp.org>
*
* 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 <cairo-gobject.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikaextensionmanager.h"
#include "core/pikaextension.h"
#include "widgets/pikaextensiondetails.h"
#include "widgets/pikaextensionlist.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaprefsbox.h"
#include "extensions-dialog.h"
#include "pika-intl.h"
#define PIKA_EXTENSION_LIST_STACK_CHILD "extension-list"
#define PIKA_EXTENSION_DETAILS_STACK_CHILD "extension-details"
static void extensions_dialog_response (GtkWidget *widget,
gint response_id,
GtkWidget *dialog);
static void extensions_dialog_search_activate (GtkEntry *entry,
gpointer user_data);
static void extensions_dialog_search_icon_pressed (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data);
static void extensions_dialog_extension_activated (PikaExtensionList *list,
PikaExtension *extension,
GtkStack *stack);
static void extensions_dialog_back_button_clicked (GtkButton *button,
GtkStack *stack);
/* public function */
GtkWidget *
extensions_dialog_new (Pika *pika)
{
GtkWidget *dialog;
GtkWidget *stack;
GtkWidget *stacked;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *list;
GtkWidget *widget;
GtkTreeIter top_iter;
dialog = pika_dialog_new (_("Extensions"), "pika-extensions",
NULL, 0, NULL,
PIKA_HELP_EXTENSIONS_DIALOG,
_("_OK"), GTK_RESPONSE_OK,
NULL);
widget = gtk_window_get_titlebar (GTK_WINDOW (dialog));
if (widget)
gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget),
FALSE);
g_signal_connect (dialog, "response",
G_CALLBACK (extensions_dialog_response),
dialog);
stack = gtk_stack_new ();
gtk_stack_set_transition_type (GTK_STACK (stack),
GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
stack, TRUE, TRUE, 0);
gtk_widget_show (stack);
/* The extension lists. */
stacked = pika_prefs_box_new ();
gtk_container_set_border_width (GTK_CONTAINER (stacked), 12);
gtk_stack_add_named (GTK_STACK (stack), stacked,
PIKA_EXTENSION_LIST_STACK_CHILD);
gtk_widget_show (stacked);
vbox = pika_prefs_box_add_page (PIKA_PREFS_BOX (stacked),
"system-software-install",
/*"pika-extensions-installed",*/
_("Installed Extensions"),
_("Installed Extensions"),
PIKA_HELP_EXTENSIONS_INSTALLED,
NULL,
&top_iter);
list = pika_extension_list_new (pika->extension_manager);
g_signal_connect (list, "extension-activated",
G_CALLBACK (extensions_dialog_extension_activated),
stack);
pika_extension_list_show_user (PIKA_EXTENSION_LIST (list));
gtk_box_pack_start (GTK_BOX (vbox), list, TRUE, TRUE, 1);
gtk_widget_show (list);
vbox = pika_prefs_box_add_page (PIKA_PREFS_BOX (stacked),
"system-software-install",
_("System Extensions"),
_("System Extensions"),
PIKA_HELP_EXTENSIONS_SYSTEM,
NULL,
&top_iter);
list = pika_extension_list_new (pika->extension_manager);
g_signal_connect (list, "extension-activated",
G_CALLBACK (extensions_dialog_extension_activated),
stack);
pika_extension_list_show_system (PIKA_EXTENSION_LIST (list));
gtk_box_pack_start (GTK_BOX (vbox), list, TRUE, TRUE, 1);
gtk_widget_show (list);
vbox = pika_prefs_box_add_page (PIKA_PREFS_BOX (stacked),
"system-software-install",
_("Install Extensions"),
_("Install Extensions"),
PIKA_HELP_EXTENSIONS_INSTALL,
NULL,
&top_iter);
list = pika_extension_list_new (pika->extension_manager);
g_signal_connect (list, "extension-activated",
G_CALLBACK (extensions_dialog_extension_activated),
stack);
pika_extension_list_show_search (PIKA_EXTENSION_LIST (list), NULL);
gtk_box_pack_end (GTK_BOX (vbox), list, TRUE, TRUE, 1);
gtk_widget_show (list);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
gtk_widget_show (hbox);
widget = gtk_label_new (_("Search extension:"));
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 1);
gtk_widget_show (widget);
widget = gtk_entry_new ();
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (widget),
GTK_ENTRY_ICON_SECONDARY,
"edit-find");
gtk_entry_set_icon_activatable (GTK_ENTRY (widget),
GTK_ENTRY_ICON_SECONDARY,
TRUE);
gtk_entry_set_icon_sensitive (GTK_ENTRY (widget),
GTK_ENTRY_ICON_SECONDARY,
TRUE);
gtk_entry_set_icon_tooltip_text (GTK_ENTRY (widget),
GTK_ENTRY_ICON_SECONDARY,
_("Search extensions matching these keywords"));
g_signal_connect (widget, "activate",
G_CALLBACK (extensions_dialog_search_activate),
list);
g_signal_connect (widget, "icon-press",
G_CALLBACK (extensions_dialog_search_icon_pressed),
list);
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 1);
gtk_widget_show (widget);
/* The extension details. */
stacked = pika_extension_details_new ();
gtk_stack_add_named (GTK_STACK (stack), stacked,
PIKA_EXTENSION_DETAILS_STACK_CHILD);
gtk_widget_show (stacked);
gtk_stack_set_visible_child_name (GTK_STACK (stack),
PIKA_EXTENSION_LIST_STACK_CHILD);
return dialog;
}
static void
extensions_dialog_response (GtkWidget *widget,
gint response_id,
GtkWidget *dialog)
{
gtk_widget_destroy (dialog);
}
static void
extensions_dialog_search_activate (GtkEntry *entry,
gpointer user_data)
{
PikaExtensionList *list = user_data;
pika_extension_list_show_search (list, gtk_entry_get_text (entry));
}
static void
extensions_dialog_search_icon_pressed (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data)
{
extensions_dialog_search_activate (entry, user_data);
}
static void
extensions_dialog_extension_activated (PikaExtensionList *list,
PikaExtension *extension,
GtkStack *stack)
{
GtkWidget *dialog = gtk_widget_get_toplevel (GTK_WIDGET (stack));
GtkWidget *header_bar;
GtkWidget *widget;
/* Add a back button to the dialogue. */
header_bar = gtk_window_get_titlebar (GTK_WINDOW (dialog));
widget = gtk_button_new_from_icon_name ("go-previous", GTK_ICON_SIZE_SMALL_TOOLBAR);
g_signal_connect (widget, "clicked",
G_CALLBACK (extensions_dialog_back_button_clicked),
stack);
gtk_widget_show (widget);
if (header_bar)
{
gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), widget);
}
else
{
GtkWidget *content_area;
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_add (GTK_CONTAINER (content_area), widget);
}
/* Show the details of the extension. */
widget = gtk_stack_get_child_by_name (stack, PIKA_EXTENSION_DETAILS_STACK_CHILD);
pika_extension_details_set (PIKA_EXTENSION_DETAILS (widget),
extension);
gtk_stack_set_visible_child_name (stack,
PIKA_EXTENSION_DETAILS_STACK_CHILD);
}
static void
extensions_dialog_back_button_clicked (GtkButton *button,
GtkStack *stack)
{
gtk_stack_set_visible_child_name (stack,
PIKA_EXTENSION_LIST_STACK_CHILD);
gtk_widget_destroy (GTK_WIDGET (button));
}

View File

@ -0,0 +1,32 @@
/* 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
*
* extension-dialog.h
* Copyright (C) 2018 Jehan <jehan@gimp.org>
*
* 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/>.
*/
#ifndef __EXTENSIONS_DIALOG_H__
#define __EXTENSIONS_DIALOG_H__
GtkWidget * extensions_dialog_new (Pika *pika);
#endif /* __EXTENSIONS_DIALOG_H__ */

View File

@ -0,0 +1,279 @@
/* 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, 1996, 1997 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Josh MacDonald
*
* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikaimage.h"
#include "core/pikaimage-undo.h"
#include "core/pikalayer.h"
#include "core/pikaprogress.h"
#include "file/file-open.h"
#include "file/pika-file.h"
#include "widgets/pikafiledialog.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaopendialog.h"
#include "widgets/pikawidgets-utils.h"
#include "file-open-dialog.h"
#include "pika-intl.h"
/* local function prototypes */
static void file_open_dialog_response (GtkWidget *dialog,
gint response_id,
Pika *pika);
static PikaImage *file_open_dialog_open_image (GtkWidget *dialog,
Pika *pika,
GFile *file,
PikaPlugInProcedure *load_proc);
static gboolean file_open_dialog_open_layers (GtkWidget *dialog,
PikaImage *image,
GFile *file,
PikaPlugInProcedure *load_proc);
/* public functions */
GtkWidget *
file_open_dialog_new (Pika *pika)
{
GtkWidget *dialog;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
dialog = pika_open_dialog_new (pika);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
pika_file_dialog_load_state (PIKA_FILE_DIALOG (dialog),
"pika-file-open-dialog-state");
g_signal_connect (dialog, "response",
G_CALLBACK (file_open_dialog_response),
pika);
return dialog;
}
/* private functions */
static void
file_open_dialog_response (GtkWidget *dialog,
gint response_id,
Pika *pika)
{
PikaFileDialog *file_dialog = PIKA_FILE_DIALOG (dialog);
PikaOpenDialog *open_dialog = PIKA_OPEN_DIALOG (dialog);
GSList *files;
GSList *list;
gboolean success = FALSE;
pika_file_dialog_save_state (PIKA_FILE_DIALOG (dialog),
"pika-file-open-dialog-state");
if (response_id != GTK_RESPONSE_OK)
{
if (! file_dialog->busy && response_id != GTK_RESPONSE_HELP)
gtk_widget_destroy (dialog);
return;
}
files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (dialog));
if (files)
g_object_set_data_full (G_OBJECT (pika), PIKA_FILE_OPEN_LAST_FILE_KEY,
g_object_ref (files->data),
(GDestroyNotify) g_object_unref);
pika_file_dialog_set_sensitive (file_dialog, FALSE);
/* When we are going to open new image windows, unset the transient
* window. We don't need it since we will use gdk_window_raise() to
* keep the dialog on top. And if we don't do it, then the dialog
* will pull the image window it was invoked from on top of all the
* new opened image windows, and we don't want that to happen.
*/
if (! open_dialog->open_as_layers)
gtk_window_set_transient_for (GTK_WINDOW (dialog), NULL);
if (file_dialog->image)
g_object_ref (file_dialog->image);
for (list = files; list; list = g_slist_next (list))
{
GFile *file = list->data;
if (open_dialog->open_as_layers)
{
if (! file_dialog->image)
{
pika_open_dialog_set_image (
open_dialog,
file_open_dialog_open_image (dialog,
pika,
file,
file_dialog->file_proc),
TRUE);
if (file_dialog->image)
{
g_object_ref (file_dialog->image);
success = TRUE;
}
}
else if (file_open_dialog_open_layers (dialog,
file_dialog->image,
file,
file_dialog->file_proc))
{
success = TRUE;
}
}
else
{
if (file_open_dialog_open_image (dialog,
pika,
file,
file_dialog->file_proc))
{
success = TRUE;
/* Make the dialog stay on top of all images we open if
* we open say 10 at once
*/
gdk_window_raise (gtk_widget_get_window (dialog));
}
}
if (file_dialog->canceled)
break;
}
if (success)
{
if (file_dialog->image)
{
if (open_dialog->open_as_layers)
pika_image_flush (file_dialog->image);
g_object_unref (file_dialog->image);
}
gtk_widget_destroy (dialog);
}
else
{
if (file_dialog->image)
g_object_unref (file_dialog->image);
pika_file_dialog_set_sensitive (file_dialog, TRUE);
}
g_slist_free_full (files, (GDestroyNotify) g_object_unref);
}
static PikaImage *
file_open_dialog_open_image (GtkWidget *dialog,
Pika *pika,
GFile *file,
PikaPlugInProcedure *load_proc)
{
PikaImage *image;
PikaPDBStatusType status;
GError *error = NULL;
image = file_open_with_proc_and_display (pika,
pika_get_user_context (pika),
PIKA_PROGRESS (dialog),
file, FALSE,
load_proc,
G_OBJECT (pika_widget_get_monitor (dialog)),
&status, &error);
if (! image && status != PIKA_PDB_SUCCESS && status != PIKA_PDB_CANCEL)
{
pika_message (pika, G_OBJECT (dialog), PIKA_MESSAGE_ERROR,
_("Opening '%s' failed:\n\n%s"),
pika_file_get_utf8_name (file), error->message);
g_clear_error (&error);
}
return image;
}
static gboolean
file_open_dialog_open_layers (GtkWidget *dialog,
PikaImage *image,
GFile *file,
PikaPlugInProcedure *load_proc)
{
GList *new_layers;
PikaPDBStatusType status;
GError *error = NULL;
new_layers = file_open_layers (image->pika,
pika_get_user_context (image->pika),
PIKA_PROGRESS (dialog),
image, FALSE,
file, PIKA_RUN_INTERACTIVE, load_proc,
&status, &error);
if (new_layers)
{
pika_image_add_layers (image, new_layers,
PIKA_IMAGE_ACTIVE_PARENT, -1,
0, 0,
pika_image_get_width (image),
pika_image_get_height (image),
_("Open layers"));
g_list_free (new_layers);
return TRUE;
}
else if (status != PIKA_PDB_CANCEL)
{
pika_message (image->pika, G_OBJECT (dialog), PIKA_MESSAGE_ERROR,
_("Opening '%s' failed:\n\n%s"),
pika_file_get_utf8_name (file), error->message);
g_clear_error (&error);
}
return FALSE;
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __FILE_OPEN_DIALOG_H__
#define __FILE_OPEN_DIALOG_H__
GtkWidget * file_open_dialog_new (Pika *pika);
#endif /* __FILE_OPEN_DIALOG_H__ */

View File

@ -0,0 +1,283 @@
/* 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, 1996, 1997 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Josh MacDonald
*
* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaprogress.h"
#include "file/file-open.h"
#include "file/file-utils.h"
#include "widgets/pikacontainerentry.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaprogressbox.h"
#include "widgets/pikawidgets-utils.h"
#include "file-open-location-dialog.h"
#include "pika-intl.h"
static void file_open_location_response (GtkDialog *dialog,
gint response_id,
Pika *pika);
static gboolean file_open_location_completion (GtkEntryCompletion *completion,
const gchar *key,
GtkTreeIter *iter,
gpointer data);
/* public functions */
GtkWidget *
file_open_location_dialog_new (Pika *pika)
{
PikaContext *context;
GtkWidget *dialog;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *image;
GtkWidget *label;
GtkWidget *entry;
GtkEntryCompletion *completion;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
dialog = pika_dialog_new (_("Open Location"),
"pika-file-open-location",
NULL, 0,
pika_standard_help_func,
PIKA_HELP_FILE_OPEN_LOCATION,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG(dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (dialog, "response",
G_CALLBACK (file_open_location_response),
pika);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show (vbox);
image = gtk_image_new_from_icon_name (PIKA_ICON_WEB, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
label = gtk_label_new (_("Enter location (URI):"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* we don't want the context to affect the entry, so create
* a scratch one instead of using e.g. the user context
*/
context = pika_context_new (pika, "file-open-location-dialog", NULL);
entry = pika_container_entry_new (pika->documents, context,
PIKA_VIEW_SIZE_SMALL, 0);
g_object_unref (context);
completion = gtk_entry_get_completion (GTK_ENTRY (entry));
gtk_entry_completion_set_match_func (completion,
file_open_location_completion,
NULL, NULL);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
gtk_widget_set_size_request (entry, 400, -1);
gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
g_object_set_data (G_OBJECT (dialog), "location-entry", entry);
return dialog;
}
/* private functions */
static void
file_open_location_response (GtkDialog *dialog,
gint response_id,
Pika *pika)
{
GtkWidget *entry;
GtkWidget *box;
const gchar *text = NULL;
box = g_object_get_data (G_OBJECT (dialog), "progress-box");
if (response_id != GTK_RESPONSE_OK)
{
if (box && PIKA_PROGRESS_BOX (box)->active)
pika_progress_cancel (PIKA_PROGRESS (box));
else
gtk_widget_destroy (GTK_WIDGET (dialog));
return;
}
entry = g_object_get_data (G_OBJECT (dialog), "location-entry");
text = gtk_entry_get_text (GTK_ENTRY (entry));
if (text && strlen (text))
{
PikaImage *image;
gchar *filename;
GFile *file;
PikaPDBStatusType status;
GError *error = NULL;
filename = g_filename_from_uri (text, NULL, NULL);
if (filename)
{
file = g_file_new_for_uri (text);
g_free (filename);
}
else
{
file = file_utils_filename_to_file (pika, text, &error);
}
if (!box)
{
box = pika_progress_box_new ();
gtk_container_set_border_width (GTK_CONTAINER (box), 12);
gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
box, FALSE, FALSE, 0);
g_object_set_data (G_OBJECT (dialog), "progress-box", box);
}
if (file)
{
gtk_widget_show (box);
gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE);
gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, FALSE);
image = file_open_with_proc_and_display (pika,
pika_get_user_context (pika),
PIKA_PROGRESS (box),
file, FALSE, NULL,
G_OBJECT (pika_widget_get_monitor (entry)),
&status, &error);
gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, TRUE);
gtk_editable_set_editable (GTK_EDITABLE (entry), TRUE);
if (image == NULL && status != PIKA_PDB_CANCEL)
{
pika_message (pika, G_OBJECT (box), PIKA_MESSAGE_ERROR,
_("Opening '%s' failed:\n\n%s"),
pika_file_get_utf8_name (file), error->message);
g_clear_error (&error);
}
g_object_unref (file);
if (image != NULL)
{
gtk_widget_destroy (GTK_WIDGET (dialog));
return;
}
}
else
{
pika_message (pika, G_OBJECT (box), PIKA_MESSAGE_ERROR,
_("Opening '%s' failed:\n\n%s"),
text,
/* error should never be NULL, also issue #3093 */
error ? error->message : _("Invalid URI"));
g_clear_error (&error);
}
}
}
static gboolean
file_open_location_completion (GtkEntryCompletion *completion,
const gchar *key,
GtkTreeIter *iter,
gpointer data)
{
GtkTreeModel *model = gtk_entry_completion_get_model (completion);
gchar *name;
gchar *normalized;
gchar *case_normalized;
gboolean match;
gtk_tree_model_get (model, iter,
1, &name,
-1);
if (! name)
return FALSE;
normalized = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
case_normalized = g_utf8_casefold (normalized, -1);
match = (strncmp (key, case_normalized, strlen (key)) == 0);
if (! match)
{
const gchar *colon = strchr (case_normalized, ':');
if (colon && strlen (colon) > 2 && colon[1] == '/' && colon[2] == '/')
match = (strncmp (key, colon + 3, strlen (key)) == 0);
}
g_free (normalized);
g_free (case_normalized);
g_free (name);
return match;
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __FILE_OPEN_LOCATION_DIALOG_H__
#define __FILE_OPEN_LOCATION_DIALOG_H__
GtkWidget * file_open_location_dialog_new (Pika *pika);
#endif /* __FILE_OPEN_LOCATION_DIALOG_H__ */

View File

@ -0,0 +1,864 @@
/* 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, 1996, 1997 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Josh MacDonald
*
* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikaimage.h"
#include "core/pikaprogress.h"
#include "plug-in/pikapluginmanager-file.h"
#include "plug-in/pikapluginprocedure.h"
#include "file/file-save.h"
#include "file/pika-file.h"
#include "widgets/pikaactiongroup.h"
#include "widgets/pikaexportdialog.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "widgets/pikasavedialog.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "file-save-dialog.h"
#include "pika-log.h"
#include "pika-intl.h"
typedef enum
{
CHECK_URI_FAIL,
CHECK_URI_OK,
CHECK_URI_SWITCH_DIALOGS
} CheckUriResult;
/* local function prototypes */
static GtkFileChooserConfirmation
file_save_dialog_confirm_overwrite (GtkWidget *dialog,
Pika *pika);
static void file_save_dialog_response (GtkWidget *dialog,
gint response_id,
Pika *pika);
static CheckUriResult file_save_dialog_check_file (GtkWidget *save_dialog,
Pika *pika,
GFile **ret_file,
gchar **ret_basename,
PikaPlugInProcedure **ret_save_proc);
static gboolean file_save_dialog_no_overwrite_confirmation (PikaFileDialog *dialog,
Pika *pika);
static PikaPlugInProcedure *
file_save_dialog_find_procedure (PikaFileDialog *dialog,
GFile *file);
static gboolean file_save_dialog_switch_dialogs (PikaFileDialog *file_dialog,
Pika *pika,
const gchar *basename);
static gboolean file_save_dialog_use_extension (GtkWidget *save_dialog,
GFile *file);
/* public functions */
GtkWidget *
file_save_dialog_new (Pika *pika,
gboolean export)
{
GtkWidget *dialog;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
if (! export)
{
dialog = pika_save_dialog_new (pika);
pika_file_dialog_load_state (PIKA_FILE_DIALOG (dialog),
"pika-file-save-dialog-state");
}
else
{
dialog = pika_export_dialog_new (pika);
pika_file_dialog_load_state (PIKA_FILE_DIALOG (dialog),
"pika-file-export-dialog-state");
}
g_signal_connect (dialog, "confirm-overwrite",
G_CALLBACK (file_save_dialog_confirm_overwrite),
pika);
g_signal_connect (dialog, "response",
G_CALLBACK (file_save_dialog_response),
pika);
return dialog;
}
/* private functions */
static GtkFileChooserConfirmation
file_save_dialog_confirm_overwrite (GtkWidget *dialog,
Pika *pika)
{
PikaFileDialog *file_dialog = PIKA_FILE_DIALOG (dialog);
if (file_save_dialog_no_overwrite_confirmation (file_dialog, pika))
/* The URI will not be accepted whatever happens, so don't
* bother asking the user about overwriting files
*/
return GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME;
else
return GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
}
static void
file_save_dialog_response (GtkWidget *dialog,
gint response_id,
Pika *pika)
{
PikaFileDialog *file_dialog = PIKA_FILE_DIALOG (dialog);
GFile *file;
gchar *basename;
PikaPlugInProcedure *save_proc;
if (PIKA_IS_SAVE_DIALOG (dialog))
{
pika_file_dialog_save_state (file_dialog, "pika-file-save-dialog-state");
}
else /* PIKA_IS_EXPORT_DIALOG (dialog) */
{
pika_file_dialog_save_state (file_dialog, "pika-file-export-dialog-state");
}
if (response_id != GTK_RESPONSE_OK)
{
if (! file_dialog->busy && response_id != GTK_RESPONSE_HELP)
gtk_widget_destroy (dialog);
return;
}
g_object_ref (file_dialog);
g_object_ref (file_dialog->image);
switch (file_save_dialog_check_file (dialog, pika,
&file, &basename, &save_proc))
{
case CHECK_URI_FAIL:
break;
case CHECK_URI_OK:
{
PikaImage *image = file_dialog->image;
PikaProgress *progress = PIKA_PROGRESS (dialog);
PikaDisplay *display_to_close = NULL;
gboolean xcf_compression = FALSE;
gboolean is_save_dialog = PIKA_IS_SAVE_DIALOG (dialog);
gboolean close_after_saving = FALSE;
gboolean save_a_copy = FALSE;
if (is_save_dialog)
{
close_after_saving = PIKA_SAVE_DIALOG (dialog)->close_after_saving;
display_to_close = PIKA_DISPLAY (PIKA_SAVE_DIALOG (dialog)->display_to_close);
save_a_copy = PIKA_SAVE_DIALOG (dialog)->save_a_copy;
}
pika_file_dialog_set_sensitive (file_dialog, FALSE);
if (PIKA_IS_SAVE_DIALOG (dialog))
{
xcf_compression = PIKA_SAVE_DIALOG (dialog)->compression;
}
/* Hide the file dialog while exporting, avoid dialogs piling
* up, even more as some formats have preview features, so the
* file dialog is just blocking the view.
*/
if (PIKA_IS_EXPORT_DIALOG (dialog))
{
gtk_widget_hide (dialog);
progress = PIKA_PROGRESS (PIKA_EXPORT_DIALOG (dialog)->display);
}
g_signal_connect (dialog, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&dialog);
if (file_save_dialog_save_image (progress,
pika,
image,
file,
save_proc,
PIKA_RUN_INTERACTIVE,
is_save_dialog && ! save_a_copy,
FALSE,
PIKA_IS_EXPORT_DIALOG (dialog),
xcf_compression,
FALSE))
{
/* Save was successful, now store the URI in a couple of
* places that depend on it being the user that made a
* save. Lower-level URI management is handled in
* file_save()
*/
if (is_save_dialog)
{
if (save_a_copy)
pika_image_set_save_a_copy_file (image, file);
g_object_set_data_full (G_OBJECT (image->pika),
PIKA_FILE_SAVE_LAST_FILE_KEY,
g_object_ref (file),
(GDestroyNotify) g_object_unref);
}
else
{
g_object_set_data_full (G_OBJECT (image->pika),
PIKA_FILE_EXPORT_LAST_FILE_KEY,
g_object_ref (file),
(GDestroyNotify) g_object_unref);
}
/* make sure the menus are updated with the keys we've just set */
pika_image_flush (image);
/* Handle close-after-saving */
if (close_after_saving && display_to_close &&
! pika_image_is_dirty (pika_display_get_image (display_to_close)))
{
pika_display_close (display_to_close);
}
if (dialog)
gtk_widget_destroy (dialog);
}
else
{
if (dialog)
{
GFile *parent_dir = g_file_get_parent (file);
/* XXX Not sure why, but after reshowing the file
* chooser dialog, the displayed name is correct, but
* the parent directory is the current working dir.
* Force it to be the expected folder.
*/
gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog),
parent_dir, NULL);
gtk_widget_show (dialog);
g_object_unref (parent_dir);
}
}
g_object_unref (file);
g_free (basename);
if (dialog)
{
pika_file_dialog_set_sensitive (file_dialog, TRUE);
g_signal_handlers_disconnect_by_func (dialog,
G_CALLBACK (gtk_widget_destroyed),
&dialog);
}
}
break;
case CHECK_URI_SWITCH_DIALOGS:
file_dialog->busy = TRUE; /* prevent destruction */
gtk_dialog_response (GTK_DIALOG (dialog), FILE_SAVE_RESPONSE_OTHER_DIALOG);
file_dialog->busy = FALSE;
gtk_widget_destroy (dialog);
break;
}
g_object_unref (file_dialog->image);
g_object_unref (file_dialog);
}
/* IMPORTANT: When changing this function, keep
* file_save_dialog_no_overwrite_confirmation() up to date. It is
* difficult to move logic to a common place due to how the dialog is
* implemented in GTK+ in combination with how we use it.
*/
static CheckUriResult
file_save_dialog_check_file (GtkWidget *dialog,
Pika *pika,
GFile **ret_file,
gchar **ret_basename,
PikaPlugInProcedure **ret_save_proc)
{
PikaFileDialog *file_dialog = PIKA_FILE_DIALOG (dialog);
GFile *file;
gchar *uri;
gchar *basename;
GFile *basename_file;
PikaPlugInProcedure *save_proc;
PikaPlugInProcedure *uri_proc;
PikaPlugInProcedure *basename_proc;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
if (! file)
return CHECK_URI_FAIL;
basename = g_path_get_basename (pika_file_get_utf8_name (file));
basename_file = g_file_new_for_uri (basename);
save_proc = file_dialog->file_proc;
uri_proc = file_save_dialog_find_procedure (file_dialog, file);
basename_proc = file_save_dialog_find_procedure (file_dialog, basename_file);
g_object_unref (basename_file);
uri = g_file_get_uri (file);
PIKA_LOG (SAVE_DIALOG, "URI = %s", uri);
PIKA_LOG (SAVE_DIALOG, "basename = %s", basename);
PIKA_LOG (SAVE_DIALOG, "selected save_proc: %s",
save_proc ?
pika_procedure_get_label (PIKA_PROCEDURE (save_proc)) : "NULL");
PIKA_LOG (SAVE_DIALOG, "URI save_proc: %s",
uri_proc ?
pika_procedure_get_label (PIKA_PROCEDURE (uri_proc)) : "NULL");
PIKA_LOG (SAVE_DIALOG, "basename save_proc: %s",
basename_proc ?
pika_procedure_get_label (PIKA_PROCEDURE (basename_proc)) : "NULL");
g_free (uri);
/* first check if the user entered an extension at all */
if (! basename_proc)
{
PIKA_LOG (SAVE_DIALOG, "basename has no valid extension");
if (! strchr (basename, '.'))
{
const gchar *ext = NULL;
PIKA_LOG (SAVE_DIALOG, "basename has no '.', trying to add extension");
if (! save_proc && PIKA_IS_SAVE_DIALOG (dialog))
{
ext = "xcf";
}
else if (save_proc && save_proc->extensions_list)
{
ext = save_proc->extensions_list->data;
}
if (ext)
{
gchar *ext_basename;
gchar *dirname;
gchar *filename;
gchar *utf8;
PIKA_LOG (SAVE_DIALOG, "appending .%s to basename", ext);
ext_basename = g_strconcat (basename, ".", ext, NULL);
g_free (basename);
basename = ext_basename;
dirname = g_path_get_dirname (pika_file_get_utf8_name (file));
filename = g_build_filename (dirname, basename, NULL);
g_free (dirname);
utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
utf8);
g_free (utf8);
g_free (filename);
PIKA_LOG (SAVE_DIALOG,
"set basename to %s, rerunning response and bailing out",
basename);
/* call the response callback again, so the
* overwrite-confirm logic can check the changed uri
*/
gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
goto fail;
}
else
{
PIKA_LOG (SAVE_DIALOG,
"save_proc has no extensions, continuing without");
/* there may be file formats with no extension at all, use
* the selected proc in this case.
*/
basename_proc = save_proc;
if (! uri_proc)
uri_proc = basename_proc;
}
if (! basename_proc)
{
PIKA_LOG (SAVE_DIALOG,
"unable to figure save_proc, bailing out");
if (file_save_dialog_switch_dialogs (file_dialog, pika, basename))
{
goto switch_dialogs;
}
goto fail;
}
}
else if (save_proc && ! save_proc->extensions_list)
{
PIKA_LOG (SAVE_DIALOG,
"basename has '.', but save_proc has no extensions, "
"accepting random extension");
/* accept any random extension if the file format has
* no extensions at all
*/
basename_proc = save_proc;
if (! uri_proc)
uri_proc = basename_proc;
}
}
/* then check if the selected format matches the entered extension */
if (! save_proc)
{
PIKA_LOG (SAVE_DIALOG, "no save_proc was selected from the list");
if (! basename_proc)
{
PIKA_LOG (SAVE_DIALOG,
"basename has no useful extension, bailing out");
if (file_save_dialog_switch_dialogs (file_dialog, pika, basename))
{
goto switch_dialogs;
}
goto fail;
}
PIKA_LOG (SAVE_DIALOG, "use URI's proc '%s' so indirect saving works",
pika_procedure_get_label (PIKA_PROCEDURE (uri_proc)));
/* use the URI's proc if no save proc was selected */
save_proc = uri_proc;
}
else
{
PIKA_LOG (SAVE_DIALOG, "save_proc '%s' was selected from the list",
pika_procedure_get_label (PIKA_PROCEDURE (save_proc)));
if (save_proc != basename_proc)
{
PIKA_LOG (SAVE_DIALOG, "however the basename's proc is '%s'",
pika_procedure_get_label (PIKA_PROCEDURE (basename_proc)));
if (uri_proc != basename_proc)
{
PIKA_LOG (SAVE_DIALOG,
"that's impossible for remote URIs, bailing out");
/* remote URI */
pika_message (pika, G_OBJECT (dialog), PIKA_MESSAGE_WARNING,
_("Saving remote files needs to determine the "
"file format from the file extension. "
"Please enter a file extension that matches "
"the selected file format or enter no file "
"extension at all."));
goto fail;
}
else
{
PIKA_LOG (SAVE_DIALOG,
"ask the user if she really wants that filename");
/* local URI */
if (! file_save_dialog_use_extension (dialog, file))
{
goto fail;
}
}
}
else if (save_proc != uri_proc)
{
PIKA_LOG (SAVE_DIALOG,
"use URI's proc '%s' so indirect saving works",
pika_procedure_get_label (PIKA_PROCEDURE (uri_proc)));
/* need to use the URI's proc for saving because e.g.
* the GIF plug-in can't save a GIF to sftp://
*/
save_proc = uri_proc;
}
}
if (! save_proc)
{
g_warning ("%s: EEEEEEK", G_STRFUNC);
return CHECK_URI_FAIL;
}
*ret_file = file;
*ret_basename = basename;
*ret_save_proc = save_proc;
return CHECK_URI_OK;
fail:
g_object_unref (file);
g_free (basename);
return CHECK_URI_FAIL;
switch_dialogs:
g_object_unref (file);
g_free (basename);
return CHECK_URI_SWITCH_DIALOGS;
}
/*
* IMPORTANT: Keep this up to date with file_save_dialog_check_uri().
*/
static gboolean
file_save_dialog_no_overwrite_confirmation (PikaFileDialog *file_dialog,
Pika *pika)
{
GFile *file;
gchar *basename;
GFile *basename_file;
PikaPlugInProcedure *basename_proc;
PikaPlugInProcedure *save_proc;
gboolean uri_will_change;
gboolean unknown_ext;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (file_dialog));
if (! file)
return FALSE;
basename = g_path_get_basename (pika_file_get_utf8_name (file));
basename_file = g_file_new_for_uri (basename);
save_proc = file_dialog->file_proc;
basename_proc = file_save_dialog_find_procedure (file_dialog, basename_file);
g_object_unref (basename_file);
uri_will_change = (! basename_proc &&
! strchr (basename, '.') &&
(! save_proc || save_proc->extensions_list));
unknown_ext = (! save_proc &&
! basename_proc);
g_free (basename);
g_object_unref (file);
return uri_will_change || unknown_ext;
}
static PikaPlugInProcedure *
file_save_dialog_find_procedure (PikaFileDialog *file_dialog,
GFile *file)
{
PikaPlugInManager *manager = file_dialog->pika->plug_in_manager;
PikaFileProcedureGroup group;
if (PIKA_IS_SAVE_DIALOG (file_dialog))
group = PIKA_FILE_PROCEDURE_GROUP_SAVE;
else
group = PIKA_FILE_PROCEDURE_GROUP_EXPORT;
return pika_plug_in_manager_file_procedure_find (manager, group, file, NULL);
}
static gboolean
file_save_other_dialog_activated (GtkWidget *label,
const gchar *uri,
GtkDialog *dialog)
{
gtk_dialog_response (dialog, FILE_SAVE_RESPONSE_OTHER_DIALOG);
return TRUE;
}
static gboolean
file_save_dialog_switch_dialogs (PikaFileDialog *file_dialog,
Pika *pika,
const gchar *basename)
{
PikaPlugInProcedure *proc_in_other_group;
PikaFileProcedureGroup other_group;
GFile *file;
gboolean switch_dialogs = FALSE;
file = g_file_new_for_uri (basename);
if (PIKA_IS_EXPORT_DIALOG (file_dialog))
other_group = PIKA_FILE_PROCEDURE_GROUP_SAVE;
else
other_group = PIKA_FILE_PROCEDURE_GROUP_EXPORT;
proc_in_other_group =
pika_plug_in_manager_file_procedure_find (pika->plug_in_manager,
other_group, file, NULL);
g_object_unref (file);
if (proc_in_other_group)
{
GtkWidget *dialog;
const gchar *primary;
const gchar *message;
const gchar *link;
if (PIKA_IS_EXPORT_DIALOG (file_dialog))
{
primary = _("The given filename cannot be used for exporting");
message = _("You can use this dialog to export to various file formats. "
"If you want to save the image to the PIKA XCF format, use "
"File→Save instead.");
link = _("Take me to the Save dialog");
}
else
{
primary = _("The given filename cannot be used for saving");
message = _("You can use this dialog to save to the PIKA XCF "
"format. Use File→Export to export to other file formats.");
link = _("Take me to the Export dialog");
}
dialog = pika_message_dialog_new (_("Extension Mismatch"),
PIKA_ICON_DIALOG_WARNING,
GTK_WIDGET (file_dialog),
GTK_DIALOG_DESTROY_WITH_PARENT,
pika_standard_help_func, NULL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (dialog)->box,
"%s", primary);
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (dialog)->box,
"%s", message);
if (PIKA_IS_EXPORT_DIALOG (file_dialog) ||
(! PIKA_SAVE_DIALOG (file_dialog)->save_a_copy &&
! PIKA_SAVE_DIALOG (file_dialog)->close_after_saving))
{
GtkWidget *label;
gchar *markup;
markup = g_strdup_printf ("<a href=\"other-dialog\">%s</a>", link);
label = gtk_label_new (markup);
g_free (markup);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (PIKA_MESSAGE_DIALOG (dialog)->box), label,
FALSE, FALSE, 0);
gtk_widget_show (label);
g_signal_connect (label, "activate-link",
G_CALLBACK (file_save_other_dialog_activated),
dialog);
}
gtk_dialog_set_response_sensitive (GTK_DIALOG (file_dialog),
GTK_RESPONSE_CANCEL, FALSE);
gtk_dialog_set_response_sensitive (GTK_DIALOG (file_dialog),
GTK_RESPONSE_OK, FALSE);
g_object_ref (dialog);
if (pika_dialog_run (PIKA_DIALOG (dialog)) == FILE_SAVE_RESPONSE_OTHER_DIALOG)
{
switch_dialogs = TRUE;
}
gtk_widget_destroy (dialog);
g_object_unref (dialog);
gtk_dialog_set_response_sensitive (GTK_DIALOG (file_dialog),
GTK_RESPONSE_CANCEL, TRUE);
gtk_dialog_set_response_sensitive (GTK_DIALOG (file_dialog),
GTK_RESPONSE_OK, TRUE);
}
else
{
pika_message (pika, G_OBJECT (file_dialog), PIKA_MESSAGE_WARNING,
_("The given filename does not have any known "
"file extension. Please enter a known file "
"extension or select a file format from the "
"file format list."));
}
return switch_dialogs;
}
static gboolean
file_save_dialog_use_extension (GtkWidget *save_dialog,
GFile *file)
{
GtkWidget *dialog;
gboolean use_name = FALSE;
dialog = pika_message_dialog_new (_("Extension Mismatch"),
PIKA_ICON_DIALOG_QUESTION,
save_dialog, GTK_DIALOG_DESTROY_WITH_PARENT,
pika_standard_help_func, NULL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("The given file extension does "
"not match the chosen file type."));
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("Do you want to save the image using this "
"name anyway?"));
gtk_dialog_set_response_sensitive (GTK_DIALOG (save_dialog),
GTK_RESPONSE_CANCEL, FALSE);
gtk_dialog_set_response_sensitive (GTK_DIALOG (save_dialog),
GTK_RESPONSE_OK, FALSE);
g_object_ref (dialog);
use_name = (pika_dialog_run (PIKA_DIALOG (dialog)) == GTK_RESPONSE_OK);
gtk_widget_destroy (dialog);
g_object_unref (dialog);
gtk_dialog_set_response_sensitive (GTK_DIALOG (save_dialog),
GTK_RESPONSE_CANCEL, TRUE);
gtk_dialog_set_response_sensitive (GTK_DIALOG (save_dialog),
GTK_RESPONSE_OK, TRUE);
return use_name;
}
gboolean
file_save_dialog_save_image (PikaProgress *progress,
Pika *pika,
PikaImage *image,
GFile *file,
PikaPlugInProcedure *save_proc,
PikaRunMode run_mode,
gboolean change_saved_state,
gboolean export_backward,
gboolean export_forward,
gboolean xcf_compression,
gboolean verbose_cancel)
{
PikaPDBStatusType status;
GError *error = NULL;
GList *list;
gboolean success = FALSE;
for (list = pika_action_groups_from_name ("file");
list;
list = g_list_next (list))
{
pika_action_group_set_action_sensitive (list->data, "file-quit", FALSE, NULL);
}
pika_image_set_xcf_compression (image, xcf_compression);
status = file_save (pika, image, progress, file,
save_proc, run_mode,
change_saved_state, export_backward, export_forward,
&error);
switch (status)
{
case PIKA_PDB_SUCCESS:
success = TRUE;
break;
case PIKA_PDB_CANCEL:
if (verbose_cancel)
pika_message_literal (pika,
G_OBJECT (progress), PIKA_MESSAGE_INFO,
_("Saving canceled"));
break;
default:
{
pika_message (pika, G_OBJECT (progress), PIKA_MESSAGE_ERROR,
_("Saving '%s' failed:\n\n%s"),
pika_file_get_utf8_name (file),
error ? error->message : _("Unknown error"));
g_clear_error (&error);
}
break;
}
for (list = pika_action_groups_from_name ("file");
list;
list = g_list_next (list))
{
pika_action_group_set_action_sensitive (list->data, "file-quit", TRUE, NULL);
}
return success;
}

View File

@ -0,0 +1,46 @@
/* 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/>.
*/
#ifndef __FILE_SAVE_DIALOG_H__
#define __FILE_SAVE_DIALOG_H__
#define FILE_SAVE_RESPONSE_OTHER_DIALOG -23
GtkWidget * file_save_dialog_new (Pika *pika,
gboolean export);
gboolean file_save_dialog_save_image (PikaProgress *progress_and_handler,
Pika *pika,
PikaImage *image,
GFile *file,
PikaPlugInProcedure *write_proc,
PikaRunMode run_mode,
gboolean save_a_copy,
gboolean export_backward,
gboolean export_forward,
gboolean xcf_compression,
gboolean verbose_cancel);
#endif /* __FILE_SAVE_DIALOG_H__ */

189
app/dialogs/fill-dialog.c Normal file
View File

@ -0,0 +1,189 @@
/* 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
*
* fill-dialog.c
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikadrawable.h"
#include "core/pikafilloptions.h"
#include "widgets/pikafilleditor.h"
#include "widgets/pikaviewabledialog.h"
#include "fill-dialog.h"
#include "pika-intl.h"
#define RESPONSE_RESET 1
typedef struct _FillDialog FillDialog;
struct _FillDialog
{
GList *items;
GList *drawables;
PikaContext *context;
PikaFillOptions *options;
PikaFillCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void fill_dialog_free (FillDialog *private);
static void fill_dialog_response (GtkWidget *dialog,
gint response_id,
FillDialog *private);
/* public function */
GtkWidget *
fill_dialog_new (GList *items,
GList *drawables,
PikaContext *context,
const gchar *title,
const gchar *icon_name,
const gchar *help_id,
GtkWidget *parent,
PikaFillOptions *options,
PikaFillCallback callback,
gpointer user_data)
{
FillDialog *private;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *fill_editor;
g_return_val_if_fail (items, NULL);
g_return_val_if_fail (drawables, NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (PIKA_IS_FILL_OPTIONS (options), NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (FillDialog);
private->items = g_list_copy (items);
private->drawables = g_list_copy (drawables);
private->context = context;
private->options = pika_fill_options_new (context->pika, context, TRUE);
private->callback = callback;
private->user_data = user_data;
pika_config_sync (G_OBJECT (options),
G_OBJECT (private->options), 0);
dialog = pika_viewable_dialog_new (g_list_copy (items), context,
title, "pika-fill-options",
icon_name,
_("Choose Fill Style"),
parent,
pika_standard_help_func,
help_id,
_("_Reset"), RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Fill"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) fill_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (fill_dialog_response),
private);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
fill_editor = pika_fill_editor_new (private->options, FALSE, FALSE);
gtk_box_pack_start (GTK_BOX (main_vbox), fill_editor, FALSE, FALSE, 0);
gtk_widget_show (fill_editor);
return dialog;
}
/* private functions */
static void
fill_dialog_free (FillDialog *private)
{
g_object_unref (private->options);
g_list_free (private->drawables);
g_list_free (private->items);
g_slice_free (FillDialog, private);
}
static void
fill_dialog_response (GtkWidget *dialog,
gint response_id,
FillDialog *private)
{
switch (response_id)
{
case RESPONSE_RESET:
pika_config_reset (PIKA_CONFIG (private->options));
break;
case GTK_RESPONSE_OK:
private->callback (dialog,
private->items,
private->drawables,
private->context,
private->options,
private->user_data);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}

49
app/dialogs/fill-dialog.h Normal file
View File

@ -0,0 +1,49 @@
/* 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
*
* fill-dialog.h
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
*
* 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/>.
*/
#ifndef __FILL_DIALOG_H__
#define __FILL_DIALOG_H__
typedef void (* PikaFillCallback) (GtkWidget *dialog,
GList *items,
GList *drawables,
PikaContext *context,
PikaFillOptions *options,
gpointer user_data);
GtkWidget * fill_dialog_new (GList *items,
GList *drawables,
PikaContext *context,
const gchar *title,
const gchar *icon_name,
const gchar *help_id,
GtkWidget *parent,
PikaFillOptions *options,
PikaFillCallback callback,
gpointer user_data);
#endif /* __FILL_DIALOG_H__ */

177
app/dialogs/grid-dialog.c Normal file
View File

@ -0,0 +1,177 @@
/* 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
*
* Copyright (C) 2003 Henrik Brix Andersen <brix@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaimage-grid.h"
#include "core/pikaimage-undo.h"
#include "core/pikaimage-undo-push.h"
#include "core/pikagrid.h"
#include "widgets/pikagrideditor.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "grid-dialog.h"
#include "pika-intl.h"
#define GRID_RESPONSE_RESET 1
typedef struct _GridDialog GridDialog;
struct _GridDialog
{
PikaImage *image;
PikaGrid *grid;
PikaGrid *grid_backup;
};
/* local functions */
static void grid_dialog_free (GridDialog *private);
static void grid_dialog_response (GtkWidget *dialog,
gint response_id,
GridDialog *private);
/* public function */
GtkWidget *
grid_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent)
{
GridDialog *private;
GtkWidget *dialog;
GtkWidget *editor;
gdouble xres;
gdouble yres;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
private = g_slice_new0 (GridDialog);
private->image = image;
private->grid = pika_image_get_grid (image);
private->grid_backup = pika_config_duplicate (PIKA_CONFIG (private->grid));
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Configure Grid"), "pika-grid-configure",
PIKA_ICON_GRID, _("Configure Image Grid"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_GRID,
_("_Reset"), GRID_RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GRID_RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) grid_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (grid_dialog_response),
private);
pika_image_get_resolution (image, &xres, &yres);
editor = pika_grid_editor_new (private->grid, context, xres, yres);
gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
editor, TRUE, TRUE, 0);
gtk_widget_show (editor);
return dialog;
}
/* local functions */
static void
grid_dialog_free (GridDialog *private)
{
g_object_unref (private->grid_backup);
g_slice_free (GridDialog, private);
}
static void
grid_dialog_response (GtkWidget *dialog,
gint response_id,
GridDialog *private)
{
switch (response_id)
{
case GRID_RESPONSE_RESET:
pika_config_sync (G_OBJECT (private->image->pika->config->default_grid),
G_OBJECT (private->grid), 0);
break;
case GTK_RESPONSE_OK:
if (! pika_config_is_equal_to (PIKA_CONFIG (private->grid_backup),
PIKA_CONFIG (private->grid)))
{
pika_image_undo_push_image_grid (private->image, _("Grid"),
private->grid_backup);
pika_image_flush (private->image);
}
gtk_widget_destroy (dialog);
break;
default:
pika_image_set_grid (private->image, private->grid_backup, FALSE);
gtk_widget_destroy (dialog);
}
}

33
app/dialogs/grid-dialog.h Normal file
View File

@ -0,0 +1,33 @@
/* 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
*
* Copyright (C) 2003 Henrik Brix Andersen <brix@gimp.org>
*
* 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/>.
*/
#ifndef __GRID_DIALOG_H__
#define __GRID_DIALOG_H__
GtkWidget * grid_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent);
#endif /* __GRID_DIALOG_H__ */

View File

@ -0,0 +1,196 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaitemstack.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "image-merge-layers-dialog.h"
#include "pika-intl.h"
typedef struct _ImageMergeLayersDialog ImageMergeLayersDialog;
struct _ImageMergeLayersDialog
{
PikaImage *image;
PikaContext *context;
PikaMergeType merge_type;
gboolean merge_active_group;
gboolean discard_invisible;
PikaMergeLayersCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void image_merge_layers_dialog_free (ImageMergeLayersDialog *private);
static void image_merge_layers_dialog_response (GtkWidget *dialog,
gint response_id,
ImageMergeLayersDialog *private);
/* public functions */
GtkWidget *
image_merge_layers_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaMergeType merge_type,
gboolean merge_active_group,
gboolean discard_invisible,
PikaMergeLayersCallback callback,
gpointer user_data)
{
ImageMergeLayersDialog *private;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *button;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
private = g_slice_new0 (ImageMergeLayersDialog);
private->image = image;
private->context = context;
private->merge_type = merge_type;
private->merge_active_group = merge_active_group;
private->discard_invisible = discard_invisible;
private->callback = callback;
private->user_data = user_data;
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Merge Layers"), "pika-image-merge-layers",
PIKA_ICON_LAYER_MERGE_DOWN,
_("Layers Merge Options"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_MERGE_LAYERS,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Merge"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) image_merge_layers_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (image_merge_layers_dialog_response),
private);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
frame =
pika_enum_radio_frame_new_with_range (PIKA_TYPE_MERGE_TYPE,
PIKA_EXPAND_AS_NECESSARY,
PIKA_CLIP_TO_BOTTOM_LAYER,
gtk_label_new (_("Final, Merged Layer should be:")),
G_CALLBACK (pika_radio_button_update),
&private->merge_type, NULL,
&button);
pika_int_radio_group_set_active (GTK_RADIO_BUTTON (button),
private->merge_type);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
button = gtk_check_button_new_with_mnemonic (_("Merge within active _groups only"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->merge_active_group);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->merge_active_group);
if (pika_item_stack_is_flat (PIKA_ITEM_STACK (pika_image_get_layers (image))))
gtk_widget_set_sensitive (button, FALSE);
button = gtk_check_button_new_with_mnemonic (_("_Discard invisible layers"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->discard_invisible);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->discard_invisible);
return dialog;
}
/* private functions */
static void
image_merge_layers_dialog_free (ImageMergeLayersDialog *private)
{
g_slice_free (ImageMergeLayersDialog, private);
}
static void
image_merge_layers_dialog_response (GtkWidget *dialog,
gint response_id,
ImageMergeLayersDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
private->callback (dialog,
private->image,
private->context,
private->merge_type,
private->merge_active_group,
private->discard_invisible,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
}

View File

@ -0,0 +1,46 @@
/* 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/>.
*/
#ifndef __IMAGE_MERGE_LAYERS_DIALOG_H__
#define __IMAGE_MERGE_LAYERS_DIALOG_H__
typedef void (* PikaMergeLayersCallback) (GtkWidget *dialog,
PikaImage *image,
PikaContext *context,
PikaMergeType merge_type,
gboolean merge_active_group,
gboolean discard_invisible,
gpointer user_data);
GtkWidget *
image_merge_layers_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaMergeType merge_type,
gboolean merge_active_group,
gboolean discard_invisible,
PikaMergeLayersCallback callback,
gpointer user_data);
#endif /* __IMAGE_MERGE_LAYERS_DIALOG_H__ */

View File

@ -0,0 +1,384 @@
/* 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-1999 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikaguiconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaimage-new.h"
#include "core/pikatemplate.h"
#include "widgets/pikacontainercombobox.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "widgets/pikatemplateeditor.h"
#include "widgets/pikawidgets-utils.h"
#include "image-new-dialog.h"
#include "pika-intl.h"
#define RESPONSE_RESET 1
typedef struct
{
GtkWidget *dialog;
GtkWidget *confirm_dialog;
GtkWidget *combo;
GtkWidget *editor;
PikaContext *context;
PikaTemplate *template;
} ImageNewDialog;
/* local function prototypes */
static void image_new_dialog_free (ImageNewDialog *private);
static void image_new_dialog_response (GtkWidget *widget,
gint response_id,
ImageNewDialog *private);
static void image_new_template_changed (PikaContext *context,
PikaTemplate *template,
ImageNewDialog *private);
static void image_new_confirm_dialog (ImageNewDialog *private);
static void image_new_create_image (ImageNewDialog *private);
/* public functions */
GtkWidget *
image_new_dialog_new (PikaContext *context)
{
ImageNewDialog *private;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *hbox;
GtkWidget *label;
PikaSizeEntry *entry;
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
private = g_slice_new0 (ImageNewDialog);
private->context = pika_context_new (context->pika, "image-new-dialog",
context);
private->template = g_object_new (PIKA_TYPE_TEMPLATE, NULL);
private->dialog = dialog =
pika_dialog_new (_("Create a New Image"),
"pika-image-new",
NULL, 0,
pika_standard_help_func, PIKA_HELP_FILE_NEW,
_("_Reset"), RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_set_data_full (G_OBJECT (dialog),
"pika-image-new-dialog", private,
(GDestroyNotify) image_new_dialog_free);
g_signal_connect (dialog, "response",
G_CALLBACK (image_new_dialog_response),
private);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
/* The template combo */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Template:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
private->combo = g_object_new (PIKA_TYPE_CONTAINER_COMBO_BOX,
"container", context->pika->templates,
"context", private->context,
"view-size", 16,
"view-border-width", 0,
"ellipsize", PANGO_ELLIPSIZE_NONE,
"focus-on-click", FALSE,
NULL);
gtk_box_pack_start (GTK_BOX (hbox), private->combo, TRUE, TRUE, 0);
gtk_widget_show (private->combo);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), private->combo);
g_signal_connect (private->context, "template-changed",
G_CALLBACK (image_new_template_changed),
private);
/* Template editor */
private->editor = pika_template_editor_new (private->template, context->pika,
FALSE);
gtk_box_pack_start (GTK_BOX (main_vbox), private->editor, FALSE, FALSE, 0);
gtk_widget_show (private->editor);
entry = PIKA_SIZE_ENTRY (pika_template_editor_get_size_se (PIKA_TEMPLATE_EDITOR (private->editor)));
pika_size_entry_set_activates_default (entry, TRUE);
pika_size_entry_grab_focus (entry);
image_new_template_changed (private->context,
pika_context_get_template (private->context),
private);
return dialog;
}
void
image_new_dialog_set (GtkWidget *dialog,
PikaImage *image,
PikaTemplate *template)
{
ImageNewDialog *private;
g_return_if_fail (PIKA_IS_DIALOG (dialog));
g_return_if_fail (image == NULL || PIKA_IS_IMAGE (image));
g_return_if_fail (template == NULL || PIKA_IS_TEMPLATE (template));
private = g_object_get_data (G_OBJECT (dialog), "pika-image-new-dialog");
g_return_if_fail (private != NULL);
pika_context_set_template (private->context, template);
if (! template)
{
template = pika_image_new_get_last_template (private->context->pika,
image);
image_new_template_changed (private->context, template, private);
g_object_unref (template);
}
}
/* private functions */
static void
image_new_dialog_free (ImageNewDialog *private)
{
g_object_unref (private->context);
g_object_unref (private->template);
g_slice_free (ImageNewDialog, private);
}
static void
image_new_dialog_response (GtkWidget *dialog,
gint response_id,
ImageNewDialog *private)
{
switch (response_id)
{
case RESPONSE_RESET:
pika_config_sync (G_OBJECT (private->context->pika->config->default_image),
G_OBJECT (private->template), 0);
pika_context_set_template (private->context, NULL);
break;
case GTK_RESPONSE_OK:
if (pika_template_get_initial_size (private->template) >
PIKA_GUI_CONFIG (private->context->pika->config)->max_new_image_size)
image_new_confirm_dialog (private);
else
image_new_create_image (private);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}
static void
image_new_template_changed (PikaContext *context,
PikaTemplate *template,
ImageNewDialog *private)
{
PikaTemplateEditor *editor;
GtkWidget *chain;
gdouble xres, yres;
gchar *comment;
if (! template)
return;
editor = PIKA_TEMPLATE_EDITOR (private->editor);
chain = pika_template_editor_get_resolution_chain (editor);
xres = pika_template_get_resolution_x (template);
yres = pika_template_get_resolution_y (template);
pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain),
ABS (xres - yres) < PIKA_MIN_RESOLUTION);
comment = (gchar *) pika_template_get_comment (template);
if (! comment || ! strlen (comment))
comment = g_strdup (pika_template_get_comment (private->template));
else
comment = NULL;
/* make sure the resolution values are copied first (see bug #546924) */
pika_config_sync (G_OBJECT (template), G_OBJECT (private->template),
PIKA_TEMPLATE_PARAM_COPY_FIRST);
pika_config_sync (G_OBJECT (template), G_OBJECT (private->template), 0);
if (comment)
{
g_object_set (private->template,
"comment", comment,
NULL);
g_free (comment);
}
}
/* the confirm dialog */
static void
image_new_confirm_response (GtkWidget *dialog,
gint response_id,
ImageNewDialog *private)
{
gtk_widget_destroy (dialog);
private->confirm_dialog = NULL;
if (response_id == GTK_RESPONSE_OK)
image_new_create_image (private);
else
gtk_widget_set_sensitive (private->dialog, TRUE);
}
static void
image_new_confirm_dialog (ImageNewDialog *private)
{
PikaGuiConfig *config;
GtkWidget *dialog;
gchar *size;
if (private->confirm_dialog)
{
gtk_window_present (GTK_WINDOW (private->confirm_dialog));
return;
}
private->confirm_dialog =
dialog = pika_message_dialog_new (_("Confirm Image Size"),
PIKA_ICON_DIALOG_WARNING,
private->dialog,
GTK_DIALOG_DESTROY_WITH_PARENT,
pika_standard_help_func, NULL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (private->confirm_dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (dialog, "response",
G_CALLBACK (image_new_confirm_response),
private);
size = g_format_size (pika_template_get_initial_size (private->template));
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("You are trying to create an image "
"with a size of %s."), size);
g_free (size);
config = PIKA_GUI_CONFIG (private->context->pika->config);
size = g_format_size (config->max_new_image_size);
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("An image of the chosen size will use more "
"memory than what is configured as "
"\"Maximum new image size\" in the Preferences "
"dialog (currently %s)."), size);
g_free (size);
gtk_widget_set_sensitive (private->dialog, FALSE);
gtk_widget_show (dialog);
}
static void
image_new_create_image (ImageNewDialog *private)
{
PikaTemplate *template = g_object_ref (private->template);
Pika *pika = private->context->pika;
PikaImage *image;
gtk_widget_hide (private->dialog);
image = pika_image_new_from_template (pika, template,
pika_get_user_context (pika));
pika_create_display (pika, image, pika_template_get_unit (template), 1.0,
G_OBJECT (pika_widget_get_monitor (private->dialog)));
g_object_unref (image);
gtk_widget_destroy (private->dialog);
pika_image_new_set_last_template (pika, template);
g_object_unref (template);
}

View File

@ -0,0 +1,33 @@
/* 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-1999 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/>.
*/
#ifndef __IMAGE_NEW_DIALOG_H__
#define __IMAGE_NEW_DIALOG_H__
GtkWidget * image_new_dialog_new (PikaContext *context);
void image_new_dialog_set (GtkWidget *dialog,
PikaImage *image,
PikaTemplate *template);
#endif /* __IMAGE_NEW_DIALOG_H__ */

View File

@ -0,0 +1,106 @@
/* 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
*
* image-properties-dialog.c
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
*
* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaimagecommenteditor.h"
#include "widgets/pikaimagepropview.h"
#include "widgets/pikaimageprofileview.h"
#include "widgets/pikaviewabledialog.h"
#include "image-properties-dialog.h"
#include "pika-intl.h"
GtkWidget *
image_properties_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent)
{
GtkWidget *dialog;
GtkWidget *notebook;
GtkWidget *view;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Image Properties"),
"pika-image-properties",
"dialog-information",
_("Image Properties"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_PROPERTIES,
_("_Close"), GTK_RESPONSE_CLOSE,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy),
NULL);
notebook = gtk_notebook_new ();
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
notebook, FALSE, FALSE, 0);
gtk_widget_show (notebook);
view = pika_image_prop_view_new (image);
gtk_container_set_border_width (GTK_CONTAINER (view), 12);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
view, gtk_label_new_with_mnemonic (_("_Properties")));
gtk_widget_show (view);
view = pika_image_profile_view_new (image);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
view, gtk_label_new_with_mnemonic (_("C_olor Profile")));
gtk_widget_show (view);
view = pika_image_comment_editor_new (image);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
view, gtk_label_new_with_mnemonic (_("Co_mment")));
gtk_widget_show (view);
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
return dialog;
}

View File

@ -0,0 +1,34 @@
/* 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
*
* image-properties-dialog.h
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
*
* 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/>.
*/
#ifndef __IMAGE_PROPERTIES_DIALOG_H__
#define __IMAGE_PROPERTIES_DIALOG_H__
GtkWidget * image_properties_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent);
#endif /* __IMAGE_PROPERTIES_DIALOG_H__ */

View File

@ -0,0 +1,295 @@
/* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikaguiconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaimage-scale.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "scale-dialog.h"
#include "image-scale-dialog.h"
#include "pika-intl.h"
typedef struct
{
GtkWidget *dialog;
PikaImage *image;
gint width;
gint height;
PikaUnit unit;
PikaInterpolationType interpolation;
gdouble xresolution;
gdouble yresolution;
PikaUnit resolution_unit;
PikaScaleCallback callback;
gpointer user_data;
} ImageScaleDialog;
/* local function prototypes */
static void image_scale_dialog_free (ImageScaleDialog *private);
static void image_scale_callback (GtkWidget *widget,
PikaViewable *viewable,
gint width,
gint height,
PikaUnit unit,
PikaInterpolationType interpolation,
gdouble xresolution,
gdouble yresolution,
PikaUnit resolution_unit,
gpointer data);
static GtkWidget * image_scale_confirm_dialog (ImageScaleDialog *private);
static void image_scale_confirm_large (ImageScaleDialog *private,
gint64 new_memsize,
gint64 max_memsize);
static void image_scale_confirm_small (ImageScaleDialog *private);
static void image_scale_confirm_response (GtkWidget *widget,
gint response_id,
ImageScaleDialog *private);
/* public functions */
GtkWidget *
image_scale_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaUnit unit,
PikaInterpolationType interpolation,
PikaScaleCallback callback,
gpointer user_data)
{
ImageScaleDialog *private;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (ImageScaleDialog);
private->image = image;
private->callback = callback;
private->user_data = user_data;
private->dialog = scale_dialog_new (PIKA_VIEWABLE (image), context,
C_("dialog-title", "Scale Image"),
"pika-image-scale",
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_SCALE,
unit,
interpolation,
image_scale_callback,
private);
g_object_weak_ref (G_OBJECT (private->dialog),
(GWeakNotify) image_scale_dialog_free, private);
return private->dialog;
}
/* private functions */
static void
image_scale_dialog_free (ImageScaleDialog *private)
{
g_slice_free (ImageScaleDialog, private);
}
static void
image_scale_callback (GtkWidget *widget,
PikaViewable *viewable,
gint width,
gint height,
PikaUnit unit,
PikaInterpolationType interpolation,
gdouble xresolution,
gdouble yresolution,
PikaUnit resolution_unit,
gpointer data)
{
ImageScaleDialog *private = data;
PikaImage *image = PIKA_IMAGE (viewable);
PikaImageScaleCheckType scale_check;
gint64 max_memsize;
gint64 new_memsize;
private->width = width;
private->height = height;
private->unit = unit;
private->interpolation = interpolation;
private->xresolution = xresolution;
private->yresolution = yresolution;
private->resolution_unit = resolution_unit;
gtk_widget_set_sensitive (widget, FALSE);
max_memsize = PIKA_GUI_CONFIG (image->pika->config)->max_new_image_size;
scale_check = pika_image_scale_check (image,
width, height, max_memsize,
&new_memsize);
switch (scale_check)
{
case PIKA_IMAGE_SCALE_TOO_BIG:
image_scale_confirm_large (private, new_memsize, max_memsize);
break;
case PIKA_IMAGE_SCALE_TOO_SMALL:
image_scale_confirm_small (private);
break;
case PIKA_IMAGE_SCALE_OK:
private->callback (private->dialog,
PIKA_VIEWABLE (private->image),
private->width,
private->height,
private->unit,
private->interpolation,
private->xresolution,
private->yresolution,
private->resolution_unit,
private->user_data);
break;
}
}
static GtkWidget *
image_scale_confirm_dialog (ImageScaleDialog *private)
{
GtkWidget *widget;
widget = pika_message_dialog_new (_("Confirm Scaling"),
PIKA_ICON_DIALOG_WARNING,
private->dialog,
GTK_DIALOG_DESTROY_WITH_PARENT,
pika_standard_help_func,
PIKA_HELP_IMAGE_SCALE_WARNING,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Scale"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (widget),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (widget, "response",
G_CALLBACK (image_scale_confirm_response),
private);
return widget;
}
static void
image_scale_confirm_large (ImageScaleDialog *private,
gint64 new_memsize,
gint64 max_memsize)
{
GtkWidget *widget = image_scale_confirm_dialog (private);
gchar *size;
size = g_format_size (new_memsize);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (widget)->box,
_("You are trying to create an image "
"with a size of %s."), size);
g_free (size);
size = g_format_size (max_memsize);
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (widget)->box,
_("Scaling the image to the chosen size will "
"make it use more memory than what is "
"configured as \"Maximum Image Size\" in the "
"Preferences dialog (currently %s)."), size);
g_free (size);
gtk_widget_show (widget);
}
static void
image_scale_confirm_small (ImageScaleDialog *private)
{
GtkWidget *widget = image_scale_confirm_dialog (private);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (widget)->box,
_("Scaling the image to the chosen size "
"will shrink some layers completely "
"away."));
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (widget)->box,
_("Is this what you want to do?"));
gtk_widget_show (widget);
}
static void
image_scale_confirm_response (GtkWidget *widget,
gint response_id,
ImageScaleDialog *private)
{
gtk_widget_destroy (widget);
if (response_id == GTK_RESPONSE_OK)
{
private->callback (private->dialog,
PIKA_VIEWABLE (private->image),
private->width,
private->height,
private->unit,
private->interpolation,
private->xresolution,
private->yresolution,
private->resolution_unit,
private->user_data);
}
else
{
gtk_widget_set_sensitive (private->dialog, TRUE);
}
}

View File

@ -0,0 +1,35 @@
/* 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/>.
*/
#ifndef __IMAGE_SCALE_DIALOG_H__
#define __IMAGE_SCALE_DIALOG_H__
GtkWidget * image_scale_dialog_new (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
PikaUnit unit,
PikaInterpolationType interpolation,
PikaScaleCallback callback,
gpointer user_data);
#endif /* __IMAGE_SCALE_DIALOG_H__ */

View File

@ -0,0 +1,154 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "widgets/pikadeviceeditor.h"
#include "widgets/pikadevicemanager.h"
#include "widgets/pikadevices.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "input-devices-dialog.h"
#include "pika-intl.h"
/* local function prototypes */
static void input_devices_dialog_response (GtkWidget *dialog,
guint response_id,
Pika *pika);
/* public functions */
GtkWidget *
input_devices_dialog_new (Pika *pika)
{
GtkWidget *dialog;
GtkWidget *content_area;
GtkWidget *editor;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
dialog = pika_dialog_new (_("Configure Input Devices"),
"pika-input-devices-dialog",
NULL, 0,
pika_standard_help_func,
PIKA_HELP_INPUT_DEVICES,
_("_Reset"), GTK_RESPONSE_REJECT,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_REJECT,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (dialog, "response",
G_CALLBACK (input_devices_dialog_response),
pika);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
editor = pika_device_editor_new (pika);
gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
gtk_box_pack_start (GTK_BOX (content_area), editor, TRUE, TRUE, 0);
gtk_widget_show (editor);
return dialog;
}
/* private functions */
static void
input_devices_dialog_response (GtkWidget *dialog,
guint response_id,
Pika *pika)
{
switch (response_id)
{
case GTK_RESPONSE_OK:
pika_devices_save (pika, TRUE);
break;
case GTK_RESPONSE_DELETE_EVENT:
case GTK_RESPONSE_CANCEL:
pika_devices_restore (pika);
break;
case GTK_RESPONSE_REJECT:
{
GtkWidget *confirm;
confirm = pika_message_dialog_new (_("Reset Input Device Configuration"),
PIKA_ICON_DIALOG_QUESTION,
dialog,
GTK_DIALOG_MODAL |
GTK_DIALOG_DESTROY_WITH_PARENT,
pika_standard_help_func, NULL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Reset"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (confirm),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (confirm)->box,
_("Do you really want to reset all "
"input devices to default configuration?"));
if (pika_dialog_run (PIKA_DIALOG (confirm)) == GTK_RESPONSE_OK)
{
pika_device_manager_reset (pika_devices_get_manager (pika));
pika_devices_save (pika, TRUE);
pika_devices_restore (pika);
}
gtk_widget_destroy (confirm);
}
return;
default:
break;
}
gtk_widget_destroy (dialog);
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __INPUT_DEVICES_DIALOG_H__
#define __INPUT_DEVICES_DIALOG_H__
GtkWidget * input_devices_dialog_new (Pika *pika);
#endif /* __INPUT_DEVICES_DIALOG_H__ */

View File

@ -0,0 +1,492 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaitem.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-utils.h"
#include "item-options-dialog.h"
#include "pika-intl.h"
typedef struct _ItemOptionsDialog ItemOptionsDialog;
struct _ItemOptionsDialog
{
PikaImage *image;
PikaItem *item;
PikaContext *context;
gboolean visible;
PikaColorTag color_tag;
gboolean lock_content;
gboolean lock_position;
gboolean lock_visibility;
PikaItemOptionsCallback callback;
gpointer user_data;
GtkWidget *left_vbox;
GtkWidget *left_grid;
gint grid_row;
GtkWidget *name_entry;
GtkWidget *right_frame;
GtkWidget *right_vbox;
GtkWidget *lock_position_toggle;
};
/* local function prototypes */
static void item_options_dialog_free (ItemOptionsDialog *private);
static void item_options_dialog_response (GtkWidget *dialog,
gint response_id,
ItemOptionsDialog *private);
static GtkWidget * check_button_with_icon_new (const gchar *label,
const gchar *icon_name,
GtkBox *vbox);
/* public functions */
GtkWidget *
item_options_dialog_new (PikaImage *image,
PikaItem *item,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *name_label,
const gchar *lock_content_icon_name,
const gchar *lock_content_label,
const gchar *lock_position_label,
const gchar *lock_visibility_label,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
PikaItemOptionsCallback callback,
gpointer user_data)
{
ItemOptionsDialog *private;
GtkWidget *dialog;
PikaViewable *viewable;
GtkWidget *main_hbox;
GtkWidget *grid;
GtkWidget *button;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (item == NULL || PIKA_IS_ITEM (item), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (role != NULL, NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (desc != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (ItemOptionsDialog);
private->image = image;
private->item = item;
private->context = context;
private->visible = item_visible;
private->color_tag = item_color_tag;
private->lock_content = item_lock_content;
private->lock_position = item_lock_position;
private->lock_visibility = item_lock_visibility;
private->callback = callback;
private->user_data = user_data;
if (item)
viewable = PIKA_VIEWABLE (item);
else
viewable = PIKA_VIEWABLE (image);
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, viewable), context,
title, role, icon_name, desc,
parent,
pika_standard_help_func, help_id,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (dialog, "response",
G_CALLBACK (item_options_dialog_response),
private);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) item_options_dialog_free, private);
g_object_set_data (G_OBJECT (dialog), "item-options-dialog-private", private);
main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_hbox, TRUE, TRUE, 0);
gtk_widget_show (main_hbox);
private->left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start (GTK_BOX (main_hbox), private->left_vbox, TRUE, TRUE, 0);
gtk_widget_show (private->left_vbox);
private->left_grid = grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_box_pack_start (GTK_BOX (private->left_vbox), grid, FALSE, FALSE, 0);
gtk_widget_show (grid);
/* The name label and entry */
if (name_label)
{
GtkWidget *radio;
GtkWidget *radio_box;
GList *children;
GList *list;
private->name_entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (private->name_entry), TRUE);
gtk_entry_set_text (GTK_ENTRY (private->name_entry), item_name);
pika_grid_attach_aligned (GTK_GRID (grid), 0, private->grid_row++,
name_label, 0.0, 0.5,
private->name_entry, 1);
radio_box = pika_enum_radio_box_new (PIKA_TYPE_COLOR_TAG,
G_CALLBACK (pika_radio_button_update),
&private->color_tag, NULL,
&radio);
gtk_widget_set_name (radio_box, "pika-color-tag-box");
gtk_orientable_set_orientation (GTK_ORIENTABLE (radio_box),
GTK_ORIENTATION_HORIZONTAL);
pika_grid_attach_aligned (GTK_GRID (grid), 0, private->grid_row++,
_("Color tag:"), 0.0, 0.5,
radio_box, 1);
pika_int_radio_group_set_active (GTK_RADIO_BUTTON (radio),
private->color_tag);
children = gtk_container_get_children (GTK_CONTAINER (radio_box));
for (list = children;
list;
list = g_list_next (list))
{
PikaColorTag color_tag;
PikaRGB color;
GtkWidget *image;
radio = list->data;
g_object_set (radio, "draw-indicator", FALSE, NULL);
gtk_widget_destroy (gtk_bin_get_child (GTK_BIN (radio)));
color_tag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (radio),
"pika-item-data"));
if (pika_get_color_tag_color (color_tag, &color, FALSE))
{
gint w, h;
image = pika_color_area_new (&color, PIKA_COLOR_AREA_FLAT, 0);
pika_color_area_set_color_config (PIKA_COLOR_AREA (image),
context->pika->config->color_management);
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
gtk_widget_set_size_request (image, w, h);
}
else
{
image = gtk_image_new_from_icon_name (PIKA_ICON_CLOSE,
GTK_ICON_SIZE_MENU);
}
gtk_container_add (GTK_CONTAINER (radio), image);
gtk_widget_show (image);
}
g_list_free (children);
}
/* The switches frame & vbox */
private->right_frame = pika_frame_new (_("Switches"));
gtk_box_pack_start (GTK_BOX (main_hbox), private->right_frame,
FALSE, FALSE, 0);
gtk_widget_show (private->right_frame);
private->right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (private->right_frame), private->right_vbox);
gtk_widget_show (private->right_vbox);
button = check_button_with_icon_new (_("_Visible"),
PIKA_ICON_VISIBLE,
GTK_BOX (private->right_vbox));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->visible);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->visible);
button = check_button_with_icon_new (lock_content_label,
lock_content_icon_name,
GTK_BOX (private->right_vbox));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->lock_content);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->lock_content);
button = check_button_with_icon_new (lock_position_label,
PIKA_ICON_LOCK_POSITION,
GTK_BOX (private->right_vbox));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->lock_position);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->lock_position);
private->lock_position_toggle = button;
button = check_button_with_icon_new (lock_visibility_label,
PIKA_ICON_LOCK_VISIBILITY,
GTK_BOX (private->right_vbox));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->lock_visibility);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->lock_visibility);
return dialog;
}
GtkWidget *
item_options_dialog_get_vbox (GtkWidget *dialog)
{
ItemOptionsDialog *private;
g_return_val_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog), NULL);
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_val_if_fail (private != NULL, NULL);
return private->left_vbox;
}
GtkWidget *
item_options_dialog_get_grid (GtkWidget *dialog,
gint *next_row)
{
ItemOptionsDialog *private;
g_return_val_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog), NULL);
g_return_val_if_fail (next_row != NULL, NULL);
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_val_if_fail (private != NULL, NULL);
*next_row = private->grid_row;
return private->left_grid;
}
GtkWidget *
item_options_dialog_get_name_entry (GtkWidget *dialog)
{
ItemOptionsDialog *private;
g_return_val_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog), NULL);
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_val_if_fail (private != NULL, NULL);
return private->name_entry;
}
GtkWidget *
item_options_dialog_get_lock_position (GtkWidget *dialog)
{
ItemOptionsDialog *private;
g_return_val_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog), NULL);
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_val_if_fail (private != NULL, NULL);
return private->lock_position_toggle;
}
void
item_options_dialog_add_widget (GtkWidget *dialog,
const gchar *label,
GtkWidget *widget)
{
ItemOptionsDialog *private;
g_return_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog));
g_return_if_fail (GTK_IS_WIDGET (widget));
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_if_fail (private != NULL);
pika_grid_attach_aligned (GTK_GRID (private->left_grid),
0, private->grid_row++,
label, 0.0, 0.5,
widget, 1);
}
GtkWidget *
item_options_dialog_add_switch (GtkWidget *dialog,
const gchar *icon_name,
const gchar *label)
{
ItemOptionsDialog *private;
g_return_val_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog), NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (label != NULL, NULL);
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_val_if_fail (private != NULL, NULL);
return check_button_with_icon_new (label, icon_name,
GTK_BOX (private->right_vbox));
}
void
item_options_dialog_set_switches_visible (GtkWidget *dialog,
gboolean visible)
{
ItemOptionsDialog *private;
g_return_if_fail (PIKA_IS_VIEWABLE_DIALOG (dialog));
private = g_object_get_data (G_OBJECT (dialog),
"item-options-dialog-private");
g_return_if_fail (private != NULL);
gtk_widget_set_visible (private->right_frame, visible);
}
/* private functions */
static void
item_options_dialog_free (ItemOptionsDialog *private)
{
g_slice_free (ItemOptionsDialog, private);
}
static void
item_options_dialog_response (GtkWidget *dialog,
gint response_id,
ItemOptionsDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
const gchar *name = NULL;
if (private->name_entry)
name = gtk_entry_get_text (GTK_ENTRY (private->name_entry));
private->callback (dialog,
private->image,
private->item,
private->context,
name,
private->visible,
private->color_tag,
private->lock_content,
private->lock_position,
private->lock_visibility,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
}
static GtkWidget *
check_button_with_icon_new (const gchar *label,
const gchar *icon_name,
GtkBox *vbox)
{
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *image;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (vbox, hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
button = gtk_check_button_new_with_mnemonic (label);
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
gtk_widget_show (button);
return button;
}

View File

@ -0,0 +1,79 @@
/* 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/>.
*/
#ifndef __ITEM_OPTIONS_DIALOG_H__
#define __ITEM_OPTIONS_DIALOG_H__
typedef void (* PikaItemOptionsCallback) (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data);
GtkWidget * item_options_dialog_new (PikaImage *image,
PikaItem *item,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *name_label,
const gchar *lock_content_icon_name,
const gchar *lock_content_label,
const gchar *lock_position_label,
const gchar *lock_visibility_label,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
PikaItemOptionsCallback callback,
gpointer user_data);
GtkWidget * item_options_dialog_get_vbox (GtkWidget *dialog);
GtkWidget * item_options_dialog_get_grid (GtkWidget *dialog,
gint *next_row);
GtkWidget * item_options_dialog_get_name_entry (GtkWidget *dialog);
GtkWidget * item_options_dialog_get_lock_position (GtkWidget *dialog);
void item_options_dialog_add_widget (GtkWidget *dialog,
const gchar *label,
GtkWidget *widget);
GtkWidget * item_options_dialog_add_switch (GtkWidget *dialog,
const gchar *icon_name,
const gchar *label);
void item_options_dialog_set_switches_visible (GtkWidget *dialog,
gboolean visible);
#endif /* __ITEM_OPTIONS_DIALOG_H__ */

View File

@ -0,0 +1,115 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "widgets/pikaactioneditor.h"
#include "widgets/pikahelp-ids.h"
#include "menus/menus.h"
#include "keyboard-shortcuts-dialog.h"
#include "pika-intl.h"
/* local function prototypes */
static void keyboard_shortcuts_dialog_response (GtkWidget *dialog,
gint response,
Pika *pika);
/* public functions */
GtkWidget *
keyboard_shortcuts_dialog_new (Pika *pika)
{
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *editor;
GtkWidget *box;
GtkWidget *button;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
dialog = pika_dialog_new (_("Configure Keyboard Shortcuts"),
"pika-keyboard-shortcuts-dialog",
NULL, 0,
pika_standard_help_func,
PIKA_HELP_KEYBOARD_SHORTCUTS,
_("_OK"), GTK_RESPONSE_OK,
NULL);
g_signal_connect (dialog, "response",
G_CALLBACK (keyboard_shortcuts_dialog_response),
pika);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
editor = pika_action_editor_new (pika, NULL, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), editor, TRUE, TRUE, 0);
gtk_widget_show (editor);
box = pika_hint_box_new (_("To edit a shortcut key, click on the "
"corresponding row and type a new "
"accelerator, or press backspace to "
"clear."));
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
gtk_widget_show (box);
button = pika_prop_check_button_new (G_OBJECT (pika->config), "save-accels",
_("S_ave keyboard shortcuts on exit"));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
return dialog;
}
/* private functions */
static void
keyboard_shortcuts_dialog_response (GtkWidget *dialog,
gint response,
Pika *pika)
{
switch (response)
{
default:
gtk_widget_destroy (dialog);
break;
}
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __KEYBOARD_SHORTCUTS_DIALOG_H__
#define __KEYBOARD_SHORTCUTS_DIALOG_H__
GtkWidget * keyboard_shortcuts_dialog_new (Pika *pika);
#endif /* __KEYBOARD_SHORTCUTS_DIALOG_H__ */

View File

@ -0,0 +1,252 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikachannel.h"
#include "core/pikacontainer.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "widgets/pikacontainercombobox.h"
#include "widgets/pikacontainerview.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-utils.h"
#include "layer-add-mask-dialog.h"
#include "pika-intl.h"
typedef struct _LayerAddMaskDialog LayerAddMaskDialog;
struct _LayerAddMaskDialog
{
GList *layers;
PikaAddMaskType add_mask_type;
PikaChannel *channel;
gboolean invert;
PikaAddMaskCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void layer_add_mask_dialog_free (LayerAddMaskDialog *private);
static void layer_add_mask_dialog_response (GtkWidget *dialog,
gint response_id,
LayerAddMaskDialog *private);
static gboolean layer_add_mask_dialog_channel_selected (PikaContainerView *view,
GList *viewables,
GList *paths,
LayerAddMaskDialog *private);
/* public functions */
GtkWidget *
layer_add_mask_dialog_new (GList *layers,
PikaContext *context,
GtkWidget *parent,
PikaAddMaskType add_mask_type,
gboolean invert,
PikaAddMaskCallback callback,
gpointer user_data)
{
LayerAddMaskDialog *private;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *combo;
GtkWidget *button;
PikaImage *image;
PikaChannel *channel;
GList *channels;
gchar *title;
gchar *desc;
gint n_layers = g_list_length (layers);
g_return_val_if_fail (layers, NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
private = g_slice_new0 (LayerAddMaskDialog);
private->layers = layers;
private->add_mask_type = add_mask_type;
private->invert = invert;
private->callback = callback;
private->user_data = user_data;
title = ngettext ("Add Layer Mask", "Add Layer Masks", n_layers);
title = g_strdup_printf (title, n_layers);
desc = ngettext ("Add a Mask to the Layer", "Add Masks to %d Layers", n_layers);
desc = g_strdup_printf (desc, n_layers);
dialog = pika_viewable_dialog_new (layers, context,
title,
"pika-layer-add-mask",
PIKA_ICON_LAYER_MASK,
desc,
parent,
pika_standard_help_func,
PIKA_HELP_LAYER_MASK_ADD,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Add"), GTK_RESPONSE_OK,
NULL);
g_free (title);
g_free (desc);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) layer_add_mask_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (layer_add_mask_dialog_response),
private);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
frame =
pika_enum_radio_frame_new (PIKA_TYPE_ADD_MASK_TYPE,
gtk_label_new (_("Initialize Layer Mask to:")),
G_CALLBACK (pika_radio_button_update),
&private->add_mask_type, NULL,
&button);
pika_int_radio_group_set_active (GTK_RADIO_BUTTON (button),
private->add_mask_type);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
image = pika_item_get_image (PIKA_ITEM (layers->data));
combo = pika_container_combo_box_new (pika_image_get_channels (image),
context,
PIKA_VIEW_SIZE_SMALL, 1);
pika_enum_radio_frame_add (GTK_FRAME (frame), combo,
PIKA_ADD_MASK_CHANNEL, TRUE);
gtk_widget_show (combo);
g_signal_connect (combo, "select-items",
G_CALLBACK (layer_add_mask_dialog_channel_selected),
private);
channels = pika_image_get_selected_channels (image);
if (channels)
/* Mask dialog only requires one channel. Just take any of the
* selected ones randomly.
*/
channel = channels->data;
else
channel = PIKA_CHANNEL (pika_container_get_first_child (pika_image_get_channels (image)));
pika_container_view_select_item (PIKA_CONTAINER_VIEW (combo),
PIKA_VIEWABLE (channel));
button = gtk_check_button_new_with_mnemonic (_("In_vert mask"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), private->invert);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->invert);
return dialog;
}
/* private functions */
static void
layer_add_mask_dialog_free (LayerAddMaskDialog *private)
{
g_slice_free (LayerAddMaskDialog, private);
}
static void
layer_add_mask_dialog_response (GtkWidget *dialog,
gint response_id,
LayerAddMaskDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
PikaImage *image = pika_item_get_image (PIKA_ITEM (private->layers->data));
if (private->add_mask_type == PIKA_ADD_MASK_CHANNEL &&
! private->channel)
{
pika_message_literal (image->pika,
G_OBJECT (dialog), PIKA_MESSAGE_WARNING,
_("Please select a channel first"));
return;
}
private->callback (dialog,
private->layers,
private->add_mask_type,
private->channel,
private->invert,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
}
static gboolean
layer_add_mask_dialog_channel_selected (PikaContainerView *view,
GList *viewables,
GList *paths,
LayerAddMaskDialog *private)
{
g_return_val_if_fail (g_list_length (viewables) < 2, FALSE);
private->channel = viewables? PIKA_CHANNEL (viewables->data) : NULL;
return TRUE;
}

View File

@ -0,0 +1,43 @@
/* 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/>.
*/
#ifndef __LAYER_ADD_MASK_DIALOG_H__
#define __LAYER_ADD_MASK_DIALOG_H__
typedef void (* PikaAddMaskCallback) (GtkWidget *dialog,
GList *layers,
PikaAddMaskType add_mask_type,
PikaChannel *channel,
gboolean invert,
gpointer user_data);
GtkWidget * layer_add_mask_dialog_new (GList *layers,
PikaContext *context,
GtkWidget *parent,
PikaAddMaskType add_mask_type,
gboolean invert,
PikaAddMaskCallback callback,
gpointer user_data);
#endif /* __LAYER_ADD_MASK_DIALOG_H__ */

View File

@ -0,0 +1,577 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "operations/layer-modes/pika-layer-modes.h"
#include "core/pikacontext.h"
#include "core/pikadrawable-filters.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "text/pikatext.h"
#include "text/pikatextlayer.h"
#include "widgets/pikacontainertreeview.h"
#include "widgets/pikalayermodebox.h"
#include "widgets/pikaviewabledialog.h"
#include "item-options-dialog.h"
#include "layer-options-dialog.h"
#include "pika-intl.h"
typedef struct _LayerOptionsDialog LayerOptionsDialog;
struct _LayerOptionsDialog
{
PikaLayer *layer;
PikaLayerMode mode;
PikaLayerColorSpace blend_space;
PikaLayerColorSpace composite_space;
PikaLayerCompositeMode composite_mode;
gdouble opacity;
PikaFillType fill_type;
gboolean lock_alpha;
gboolean rename_text_layers;
PikaLayerOptionsCallback callback;
gpointer user_data;
GtkWidget *mode_box;
GtkWidget *blend_space_combo;
GtkWidget *composite_space_combo;
GtkWidget *composite_mode_combo;
GtkWidget *size_se;
GtkWidget *offset_se;
};
/* local function prototypes */
static void layer_options_dialog_free (LayerOptionsDialog *private);
static void layer_options_dialog_callback (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data);
static void
layer_options_dialog_update_mode_sensitivity (LayerOptionsDialog *private);
static void layer_options_dialog_mode_notify (GtkWidget *widget,
const GParamSpec *pspec,
LayerOptionsDialog *private);
static void layer_options_dialog_rename_toggled (GtkWidget *widget,
LayerOptionsDialog *private);
/* public functions */
GtkWidget *
layer_options_dialog_new (PikaImage *image,
PikaLayer *layer,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *layer_name,
PikaLayerMode layer_mode,
PikaLayerColorSpace layer_blend_space,
PikaLayerColorSpace layer_composite_space,
PikaLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
PikaFillType layer_fill_type,
gboolean layer_visible,
PikaColorTag layer_color_tag,
gboolean layer_lock_content,
gboolean layer_lock_position,
gboolean layer_lock_visibility,
gboolean layer_lock_alpha,
PikaLayerOptionsCallback callback,
gpointer user_data)
{
LayerOptionsDialog *private;
GtkWidget *dialog;
GtkWidget *grid;
GtkListStore *space_model;
GtkWidget *combo;
GtkWidget *scale;
GtkWidget *label;
GtkAdjustment *adjustment;
GtkWidget *spinbutton;
GtkWidget *button;
PikaLayerModeContext mode_context;
gdouble xres;
gdouble yres;
gint row = 0;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (layer == NULL || PIKA_IS_LAYER (layer), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
private = g_slice_new0 (LayerOptionsDialog);
private->layer = layer;
private->mode = layer_mode;
private->blend_space = layer_blend_space;
private->composite_space = layer_composite_space;
private->composite_mode = layer_composite_mode;
private->opacity = layer_opacity * 100.0;
private->fill_type = layer_fill_type;
private->lock_alpha = layer_lock_alpha;
private->rename_text_layers = FALSE;
private->callback = callback;
private->user_data = user_data;
if (layer && pika_item_is_text_layer (PIKA_ITEM (layer)))
private->rename_text_layers = PIKA_TEXT_LAYER (layer)->auto_rename;
dialog = item_options_dialog_new (image, PIKA_ITEM (layer), context,
parent, title, role,
icon_name, desc, help_id,
_("Layer _name:"),
PIKA_ICON_LOCK_CONTENT,
_("Lock _pixels"),
_("Lock position and _size"),
_("Lock visibility"),
layer_name,
layer_visible,
layer_color_tag,
layer_lock_content,
layer_lock_position,
layer_lock_visibility,
layer_options_dialog_callback,
private);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) layer_options_dialog_free, private);
if (! layer || pika_viewable_get_children (PIKA_VIEWABLE (layer)) == NULL)
mode_context = PIKA_LAYER_MODE_CONTEXT_LAYER;
else
mode_context = PIKA_LAYER_MODE_CONTEXT_GROUP;
private->mode_box = pika_layer_mode_box_new (mode_context);
item_options_dialog_add_widget (dialog, _("_Mode:"), private->mode_box);
pika_layer_mode_box_set_mode (PIKA_LAYER_MODE_BOX (private->mode_box),
private->mode);
g_signal_connect (private->mode_box, "notify::layer-mode",
G_CALLBACK (layer_options_dialog_mode_notify),
private);
space_model =
pika_enum_store_new_with_range (PIKA_TYPE_LAYER_COLOR_SPACE,
PIKA_LAYER_COLOR_SPACE_AUTO,
PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL);
private->blend_space_combo = combo =
pika_enum_combo_box_new_with_model (PIKA_ENUM_STORE (space_model));
item_options_dialog_add_widget (dialog, _("_Blend space:"), combo);
pika_enum_combo_box_set_icon_prefix (PIKA_ENUM_COMBO_BOX (combo),
"pika-layer-color-space");
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->blend_space,
G_CALLBACK (pika_int_combo_box_get_active),
&private->blend_space, NULL);
private->composite_space_combo = combo =
pika_enum_combo_box_new_with_model (PIKA_ENUM_STORE (space_model));
item_options_dialog_add_widget (dialog, _("Compos_ite space:"), combo);
pika_enum_combo_box_set_icon_prefix (PIKA_ENUM_COMBO_BOX (combo),
"pika-layer-color-space");
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->composite_space,
G_CALLBACK (pika_int_combo_box_get_active),
&private->composite_space, NULL);
g_object_unref (space_model);
private->composite_mode_combo = combo =
pika_enum_combo_box_new (PIKA_TYPE_LAYER_COMPOSITE_MODE);
item_options_dialog_add_widget (dialog, _("Composite mo_de:"), combo);
pika_enum_combo_box_set_icon_prefix (PIKA_ENUM_COMBO_BOX (combo),
"pika-layer-composite");
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->composite_mode,
G_CALLBACK (pika_int_combo_box_get_active),
&private->composite_mode, NULL);
/* set the sensitivity of above 3 menus */
layer_options_dialog_update_mode_sensitivity (private);
adjustment = gtk_adjustment_new (private->opacity, 0.0, 100.0,
1.0, 10.0, 0.0);
scale = pika_spin_scale_new (adjustment, NULL, 1);
item_options_dialog_add_widget (dialog, _("_Opacity:"), scale);
g_signal_connect (adjustment, "value-changed",
G_CALLBACK (pika_double_adjustment_update),
&private->opacity);
grid = item_options_dialog_get_grid (dialog, &row);
pika_image_get_resolution (image, &xres, &yres);
if (! layer)
{
/* The size labels */
label = gtk_label_new (_("Width:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
gtk_widget_show (label);
label = gtk_label_new (_("Height:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, row + 1, 1, 1);
gtk_widget_show (label);
/* The size sizeentry */
adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinbutton = pika_spin_button_new (adjustment, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
private->size_se = pika_size_entry_new (1, PIKA_UNIT_PIXEL, "%a",
TRUE, TRUE, FALSE, 10,
PIKA_SIZE_ENTRY_UPDATE_SIZE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (private->size_se),
GTK_SPIN_BUTTON (spinbutton), NULL);
gtk_grid_attach (GTK_GRID (private->size_se), spinbutton, 1, 0, 1, 1);
gtk_widget_show (spinbutton);
gtk_grid_attach (GTK_GRID (grid), private->size_se, 1, row, 1, 2);
gtk_widget_show (private->size_se);
pika_size_entry_set_unit (PIKA_SIZE_ENTRY (private->size_se),
PIKA_UNIT_PIXEL);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (private->size_se), 0,
xres, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (private->size_se), 1,
yres, FALSE);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (private->size_se), 0,
PIKA_MIN_IMAGE_SIZE,
PIKA_MAX_IMAGE_SIZE);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (private->size_se), 1,
PIKA_MIN_IMAGE_SIZE,
PIKA_MAX_IMAGE_SIZE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (private->size_se), 0,
0, pika_image_get_width (image));
pika_size_entry_set_size (PIKA_SIZE_ENTRY (private->size_se), 1,
0, pika_image_get_height (image));
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->size_se), 0,
pika_image_get_width (image));
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->size_se), 1,
pika_image_get_height (image));
row += 2;
}
/* The offset labels */
label = gtk_label_new (_("Offset X:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
gtk_widget_show (label);
label = gtk_label_new (_("Offset Y:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, row + 1, 1, 1);
gtk_widget_show (label);
/* The offset sizeentry */
adjustment = gtk_adjustment_new (0, 1, 1, 1, 10, 0);
spinbutton = pika_spin_button_new (adjustment, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
private->offset_se = pika_size_entry_new (1, PIKA_UNIT_PIXEL, "%a",
TRUE, TRUE, FALSE, 10,
PIKA_SIZE_ENTRY_UPDATE_SIZE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (private->offset_se),
GTK_SPIN_BUTTON (spinbutton), NULL);
gtk_grid_attach (GTK_GRID (private->offset_se), spinbutton, 1, 0, 1, 1);
gtk_widget_show (spinbutton);
gtk_grid_attach (GTK_GRID (grid), private->offset_se, 1, row, 1, 2);
gtk_widget_show (private->offset_se);
pika_size_entry_set_unit (PIKA_SIZE_ENTRY (private->offset_se),
PIKA_UNIT_PIXEL);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (private->offset_se), 0,
xres, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (private->offset_se), 1,
yres, FALSE);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (private->offset_se), 0,
-PIKA_MAX_IMAGE_SIZE,
PIKA_MAX_IMAGE_SIZE);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (private->offset_se), 1,
-PIKA_MAX_IMAGE_SIZE,
PIKA_MAX_IMAGE_SIZE);
pika_size_entry_set_size (PIKA_SIZE_ENTRY (private->offset_se), 0,
0, pika_image_get_width (image));
pika_size_entry_set_size (PIKA_SIZE_ENTRY (private->offset_se), 1,
0, pika_image_get_height (image));
if (layer)
{
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset_se), 0,
pika_item_get_offset_x (PIKA_ITEM (layer)));
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset_se), 1,
pika_item_get_offset_y (PIKA_ITEM (layer)));
}
else
{
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset_se), 0, 0);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset_se), 1, 0);
}
row += 2;
if (! layer)
{
/* The fill type */
combo = pika_enum_combo_box_new (PIKA_TYPE_FILL_TYPE);
pika_grid_attach_aligned (GTK_GRID (grid), 0, row++,
_("_Fill with:"), 0.0, 0.5,
combo, 1);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->fill_type,
G_CALLBACK (pika_int_combo_box_get_active),
&private->fill_type, NULL);
}
if (layer)
{
GtkWidget *left_vbox = item_options_dialog_get_vbox (dialog);
GtkWidget *frame;
PikaContainer *filters;
GtkWidget *view;
frame = pika_frame_new (_("Active Filters"));
gtk_box_pack_start (GTK_BOX (left_vbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
filters = pika_drawable_get_filters (PIKA_DRAWABLE (layer));
view = pika_container_tree_view_new (filters, context,
PIKA_VIEW_SIZE_SMALL, 0);
gtk_container_add (GTK_CONTAINER (frame), view);
gtk_widget_show (view);
}
button = item_options_dialog_get_lock_position (dialog);
if (private->size_se)
g_object_bind_property (G_OBJECT (button), "active",
G_OBJECT (private->size_se), "sensitive",
G_BINDING_SYNC_CREATE |
G_BINDING_INVERT_BOOLEAN);
g_object_bind_property (G_OBJECT (button), "active",
G_OBJECT (private->offset_se), "sensitive",
G_BINDING_SYNC_CREATE |
G_BINDING_INVERT_BOOLEAN);
button = item_options_dialog_add_switch (dialog,
PIKA_ICON_LOCK_ALPHA,
_("Lock _alpha"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->lock_alpha);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->lock_alpha);
/* For text layers add a toggle to control "auto-rename" */
if (layer && pika_item_is_text_layer (PIKA_ITEM (layer)))
{
button = item_options_dialog_add_switch (dialog,
PIKA_ICON_TOOL_TEXT,
_("Set name from _text"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->rename_text_layers);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->rename_text_layers);
g_signal_connect (button, "toggled",
G_CALLBACK (layer_options_dialog_rename_toggled),
private);
}
return dialog;
}
/* private functions */
static void
layer_options_dialog_free (LayerOptionsDialog *private)
{
g_slice_free (LayerOptionsDialog, private);
}
static void
layer_options_dialog_callback (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data)
{
LayerOptionsDialog *private = user_data;
gint width = 0;
gint height = 0;
gint offset_x;
gint offset_y;
if (private->size_se)
{
width =
RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (private->size_se),
0));
height =
RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (private->size_se),
1));
}
offset_x =
RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (private->offset_se),
0));
offset_y =
RINT (pika_size_entry_get_refval (PIKA_SIZE_ENTRY (private->offset_se),
1));
private->callback (dialog,
image,
PIKA_LAYER (item),
context,
item_name,
private->mode,
private->blend_space,
private->composite_space,
private->composite_mode,
private->opacity / 100.0,
private->fill_type,
width,
height,
offset_x,
offset_y,
item_visible,
item_color_tag,
item_lock_content,
item_lock_position,
item_lock_visibility,
private->lock_alpha,
private->rename_text_layers,
private->user_data);
}
static void
layer_options_dialog_update_mode_sensitivity (LayerOptionsDialog *private)
{
gboolean mutable;
mutable = pika_layer_mode_is_blend_space_mutable (private->mode);
gtk_widget_set_sensitive (private->blend_space_combo, mutable);
mutable = pika_layer_mode_is_composite_space_mutable (private->mode);
gtk_widget_set_sensitive (private->composite_space_combo, mutable);
mutable = pika_layer_mode_is_composite_mode_mutable (private->mode);
gtk_widget_set_sensitive (private->composite_mode_combo, mutable);
}
static void
layer_options_dialog_mode_notify (GtkWidget *widget,
const GParamSpec *pspec,
LayerOptionsDialog *private)
{
private->mode = pika_layer_mode_box_get_mode (PIKA_LAYER_MODE_BOX (widget));
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->blend_space_combo),
PIKA_LAYER_COLOR_SPACE_AUTO);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->composite_space_combo),
PIKA_LAYER_COLOR_SPACE_AUTO);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->composite_mode_combo),
PIKA_LAYER_COMPOSITE_AUTO);
layer_options_dialog_update_mode_sensitivity (private);
}
static void
layer_options_dialog_rename_toggled (GtkWidget *widget,
LayerOptionsDialog *private)
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) &&
pika_item_is_text_layer (PIKA_ITEM (private->layer)))
{
PikaTextLayer *text_layer = PIKA_TEXT_LAYER (private->layer);
PikaText *text = pika_text_layer_get_text (text_layer);
if (text && text->text)
{
GtkWidget *dialog;
GtkWidget *name_entry;
gchar *name = pika_utf8_strtrim (text->text, 30);
dialog = gtk_widget_get_toplevel (widget);
name_entry = item_options_dialog_get_name_entry (dialog);
gtk_entry_set_text (GTK_ENTRY (name_entry), name);
g_free (name);
}
}
}

View File

@ -0,0 +1,77 @@
/* 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/>.
*/
#ifndef __LAYER_OPTIONS_DIALOG_H__
#define __LAYER_OPTIONS_DIALOG_H__
typedef void (* PikaLayerOptionsCallback) (GtkWidget *dialog,
PikaImage *image,
PikaLayer *layer,
PikaContext *context,
const gchar *layer_name,
PikaLayerMode layer_mode,
PikaLayerColorSpace layer_blend_space,
PikaLayerColorSpace layer_composite_space,
PikaLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
PikaFillType layer_fill_type,
gint layer_width,
gint layer_height,
gint layer_offset_x,
gint layer_offset_y,
gboolean layer_visible,
PikaColorTag layer_color_tag,
gboolean layer_lock_content,
gboolean layer_lock_position,
gboolean layer_lock_visibility,
gboolean layer_lock_alpha,
gboolean rename_text_layer,
gpointer user_data);
GtkWidget * layer_options_dialog_new (PikaImage *image,
PikaLayer *layer,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *layer_name,
PikaLayerMode layer_mode,
PikaLayerColorSpace layer_blend_space,
PikaLayerColorSpace layer_composite_space,
PikaLayerCompositeMode layer_composite_mode,
gdouble layer_opacity,
PikaFillType layer_fill_type,
gboolean layer_visible,
PikaColorTag layer_color_tag,
gboolean layer_lock_content,
gboolean layer_lock_position,
gboolean layer_lock_visibility,
gboolean layer_lock_alpha,
PikaLayerOptionsCallback callback,
gpointer user_data);
#endif /* __LAYER_OPTIONS_DIALOG_H__ */

878
app/dialogs/lebl-dialog.c Normal file
View File

@ -0,0 +1,878 @@
#include "config.h"
#include <string.h>
#include <math.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "libpikawidgets/pikawidgets.h"
#include "lebl-dialog.h"
#include "pika-intl.h"
/* phish code */
#define PHSHFRAMES 8
#define PHSHORIGWIDTH 288
#define PHSHORIGHEIGHT 22
#define PHSHWIDTH (PHSHORIGWIDTH/PHSHFRAMES)
#define PHSHHEIGHT PHSHORIGHEIGHT
#define PHSHCHECKTIMEOUT (g_random_int()%120*1000)
#define PHSHTIMEOUT 120
#define PHSHHIDETIMEOUT 80
#define PHSHXS 5
#define PHSHYS ((g_random_int() % 2) + 1)
#define PHSHXSHIDEFACTOR 2.5
#define PHSHYSHIDEFACTOR 2.5
#define PHSHPIXELSTOREMOVE(p) (p[3] < 55 || p[2] > 200)
static void
phsh_unsea(GdkPixbuf *gp)
{
guchar *pixels = gdk_pixbuf_get_pixels (gp);
int rs = gdk_pixbuf_get_rowstride (gp);
int w = gdk_pixbuf_get_width (gp);
int h = gdk_pixbuf_get_height (gp);
int x, y;
for (y = 0; y < h; y++, pixels += rs) {
guchar *p = pixels;
for (x = 0; x < w; x++, p+=4) {
if (PHSHPIXELSTOREMOVE(p))
p[3] = 0;
}
}
}
static GdkPixbuf *
get_phsh_frame (GdkPixbuf *pb, int frame)
{
GdkPixbuf *newpb;
newpb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
PHSHWIDTH, PHSHHEIGHT);
gdk_pixbuf_copy_area (pb, frame * PHSHWIDTH, 0,
PHSHWIDTH, PHSHHEIGHT, newpb, 0, 0);
return newpb;
}
typedef struct {
gboolean live;
int x, y;
} InvGoat;
typedef struct {
gboolean good;
int y;
int x;
} InvShot;
static GtkWidget *geginv = NULL;
static GtkWidget *geginv_canvas = NULL;
static GtkWidget *geginv_label = NULL;
static GdkPixbuf *inv_goat1 = NULL;
static GdkPixbuf *inv_goat2 = NULL;
static GdkPixbuf *inv_phsh1 = NULL;
static GdkPixbuf *inv_phsh2 = NULL;
static int inv_phsh_state = 0;
static int inv_goat_state = 0;
static int inv_width = 0;
static int inv_height = 0;
static int inv_goat_width = 0;
static int inv_goat_height = 0;
static int inv_phsh_width = 0;
static int inv_phsh_height = 0;
#define INV_ROWS 3
#define INV_COLS 5
static InvGoat invs[INV_COLS][INV_ROWS] = { { { FALSE, 0, 0 } } };
static int inv_num = INV_ROWS * INV_COLS;
static double inv_factor = 1.0;
static int inv_our_x = 0;
static int inv_x = 0;
static int inv_y = 0;
static int inv_first_col = 0;
static int inv_last_col = INV_COLS-1;
static int inv_level = 0;
static int inv_lives = 0;
static gboolean inv_do_pause = FALSE;
static gboolean inv_reverse = FALSE;
static gboolean inv_game_over = FALSE;
static gboolean inv_left_pressed = FALSE;
static gboolean inv_right_pressed = FALSE;
static gboolean inv_fire_pressed = FALSE;
static gboolean inv_left_released = FALSE;
static gboolean inv_right_released = FALSE;
static gboolean inv_fire_released = FALSE;
static gboolean inv_paused = FALSE;
static GSList *inv_shots = NULL;
static guint inv_draw_idle = 0;
static void
inv_show_status (void)
{
gchar *s, *t, *u, *v, *w;
if (geginv == NULL)
return;
if (inv_game_over) {
t = g_strdup_printf (_("<b>GAME OVER</b> at level %d!"),
inv_level+1);
u = g_strdup_printf ("<big>%s</big>", t);
/* Translators: the first and third strings are similar to a
* title, and the second string is a small information text.
* The spaces are there only to separate all the strings, so
try to keep them as is. */
s = g_strdup_printf (_("%1$s %2$s %3$s"),
u, _("Press 'q' to quit"), u);
g_free (t);
g_free (u);
} else if (inv_paused) {
t = g_strdup_printf("<big><b>%s</b></big>", _("Paused"));
/* Translators: the first string is a title and the second
* string is a small information text. */
s = g_strdup_printf (_("%1$s\t%2$s"),
t, _("Press 'p' to unpause"));
g_free (t);
} else {
t = g_strdup_printf ("<b>%d</b>", inv_level+1);
u = g_strdup_printf ("<b>%d</b>", inv_lives);
v = g_strdup_printf (_("Level: %s, Lives: %s"), t, u);
w = g_strdup_printf ("<big>%s</big>", v);
/* Translators: the first string is a title and the second
* string is a small information text. */
s = g_strdup_printf (_("%1$s\t%2$s"), w,
_("Left/Right to move, Space to fire, 'p' to pause, 'q' to quit"));
g_free (t);
g_free (u);
g_free (v);
g_free (w);
}
gtk_label_set_markup (GTK_LABEL (geginv_label), s);
g_free (s);
}
static gboolean
inv_queue_draw_idle (gpointer data)
{
inv_draw_idle = 0;
if (geginv)
gtk_widget_queue_draw (data);
return FALSE;
}
static void
inv_queue_draw (GtkWidget *window)
{
if (inv_draw_idle == 0)
inv_draw_idle = g_idle_add (inv_queue_draw_idle, window);
}
static void
inv_draw_explosion (int x, int y)
{
GdkDrawingContext *context;
cairo_rectangle_int_t rect;
cairo_region_t *region;
cairo_t *cr;
int i;
if ( ! gtk_widget_is_drawable (geginv_canvas))
return;
rect.x = x - 100;
rect.y = y - 100;
rect.width = 200;
rect.height = 200;
region = cairo_region_create_rectangle (&rect);
context = gdk_window_begin_draw_frame (gtk_widget_get_window (geginv_canvas),
region);
cairo_region_destroy (region);
cr = gdk_drawing_context_get_cairo_context (context);
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
for (i = 5; i < 100; i += 5) {
cairo_arc (cr, x, y, i, 0, 2 * G_PI);
cairo_fill (cr);
gdk_display_flush (gtk_widget_get_display (geginv_canvas));
g_usleep (50000);
}
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
for (i = 5; i < 100; i += 5) {
cairo_arc (cr, x, y, i, 0, 2 * G_PI);
cairo_fill (cr);
gdk_display_flush (gtk_widget_get_display (geginv_canvas));
g_usleep (50000);
}
gdk_window_end_draw_frame (gtk_widget_get_window (geginv_canvas),
context);
inv_queue_draw (geginv);
}
static void
inv_do_game_over (void)
{
GSList *li;
inv_game_over = TRUE;
for (li = inv_shots; li != NULL; li = li->next) {
InvShot *shot = li->data;
shot->good = FALSE;
}
inv_queue_draw (geginv);
inv_show_status ();
}
static GdkPixbuf *
pb_scale (GdkPixbuf *pb, double scale)
{
int w, h;
if (scale == 1.0)
return (GdkPixbuf *)g_object_ref ((GObject *)pb);
w = gdk_pixbuf_get_width (pb) * scale;
h = gdk_pixbuf_get_height (pb) * scale;
return gdk_pixbuf_scale_simple (pb, w, h,
GDK_INTERP_BILINEAR);
}
static void
refind_first_and_last (void)
{
int i, j;
for (i = 0; i < INV_COLS; i++) {
gboolean all_null = TRUE;
for (j = 0; j < INV_ROWS; j++) {
if (invs[i][j].live) {
all_null = FALSE;
break;
}
}
if ( ! all_null) {
inv_first_col = i;
break;
}
}
for (i = INV_COLS-1; i >= 0; i--) {
gboolean all_null = TRUE;
for (j = 0; j < INV_ROWS; j++) {
if (invs[i][j].live) {
all_null = FALSE;
break;
}
}
if ( ! all_null) {
inv_last_col = i;
break;
}
}
}
static void
whack_gegl (int i, int j)
{
if ( ! invs[i][j].live)
return;
invs[i][j].live = FALSE;
inv_num --;
if (inv_num > 0) {
refind_first_and_last ();
} else {
inv_x = 70;
inv_y = 70;
inv_first_col = 0;
inv_last_col = INV_COLS-1;
inv_reverse = FALSE;
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
g_slist_free (inv_shots);
inv_shots = NULL;
for (i = 0; i < INV_COLS; i++) {
for (j = 0; j < INV_ROWS; j++) {
invs[i][j].live = TRUE;
invs[i][j].x = 70 + i * 100;
invs[i][j].y = 70 + j * 80;
}
}
inv_num = INV_ROWS * INV_COLS;
inv_level ++;
inv_show_status ();
}
inv_queue_draw (geginv);
}
static gboolean
geginv_timeout (gpointer data)
{
int i, j;
int limitx1;
int limitx2;
int speed;
int shots;
int max_shots;
if (inv_paused)
return TRUE;
if (geginv != data ||
inv_num <= 0 ||
inv_y > 700)
return FALSE;
limitx1 = 70 - (inv_first_col * 100);
limitx2 = 800 - 70 - (inv_last_col * 100);
if (inv_game_over) {
inv_y += 30;
} else {
if (inv_num < (INV_COLS*INV_ROWS)/3)
speed = 45+2*inv_level;
else if (inv_num < (2*INV_COLS*INV_ROWS)/3)
speed = 30+2*inv_level;
else
speed = 15+2*inv_level;
if (inv_reverse) {
inv_x -= speed;
if (inv_x < limitx1) {
inv_reverse = FALSE;
inv_x = (limitx1 + (limitx1 - inv_x));
inv_y += 30+inv_level;
}
} else {
inv_x += speed;
if (inv_x > limitx2) {
inv_reverse = TRUE;
inv_x = (limitx2 - (inv_x - limitx2));
inv_y += 30+inv_level;
}
}
}
for (i = 0; i < INV_COLS; i++) {
for (j = 0; j < INV_ROWS; j++) {
if (invs[i][j].live) {
invs[i][j].x = inv_x + i * 100;
invs[i][j].y = inv_y + j * 80;
if ( ! inv_game_over &&
invs[i][j].y >= 570) {
inv_do_game_over ();
} else if ( ! inv_game_over &&
invs[i][j].y >= 530 &&
invs[i][j].x + 40 > inv_our_x - 25 &&
invs[i][j].x - 40 < inv_our_x + 25) {
whack_gegl (i,j);
inv_lives --;
inv_draw_explosion (inv_our_x, 550);
if (inv_lives <= 0) {
inv_do_game_over ();
} else {
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
g_slist_free (inv_shots);
inv_shots = NULL;
inv_our_x = 400;
inv_do_pause = TRUE;
inv_show_status ();
}
}
}
}
}
shots = 0;
max_shots = (g_random_int () >> 3) % (2+inv_level);
while ( ! inv_game_over && shots < MIN (max_shots, inv_num)) {
int i = (g_random_int () >> 3) % INV_COLS;
for (j = INV_ROWS-1; j >= 0; j--) {
if (invs[i][j].live) {
InvShot *shot = g_new0 (InvShot, 1);
shot->good = FALSE;
shot->x = invs[i][j].x + (g_random_int () % 6) - 3;
shot->y = invs[i][j].y + inv_goat_height/2 + (g_random_int () % 3);
inv_shots = g_slist_prepend (inv_shots, shot);
shots++;
break;
}
}
}
inv_goat_state = (inv_goat_state+1) % 2;
inv_queue_draw (geginv);
g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv);
return FALSE;
}
static gboolean
find_gegls (int x, int y)
{
int i, j;
/* FIXME: this is stupid, we can do better */
for (i = 0; i < INV_COLS; i++) {
for (j = 0; j < INV_ROWS; j++) {
int ix = invs[i][j].x;
int iy = invs[i][j].y;
if ( ! invs[i][j].live)
continue;
if (y >= iy - 30 &&
y <= iy + 30 &&
x >= ix - 40 &&
x <= ix + 40) {
whack_gegl (i, j);
return TRUE;
}
}
}
return FALSE;
}
static gboolean
geginv_move_timeout (gpointer data)
{
GSList *li;
static int shot_inhibit = 0;
if (inv_paused)
return TRUE;
if (geginv != data ||
inv_num <= 0 ||
inv_y > 700)
return FALSE;
inv_phsh_state = (inv_phsh_state+1)%10;
/* we will be drawing something */
if (inv_shots != NULL)
inv_queue_draw (geginv);
li = inv_shots;
while (li != NULL) {
InvShot *shot = li->data;
if (shot->good) {
shot->y -= 30;
if (find_gegls (shot->x, shot->y) ||
shot->y <= 0) {
GSList *list = li;
/* we were restarted */
if (inv_shots == NULL)
return TRUE;
li = li->next;
g_free (shot);
inv_shots = g_slist_delete_link (inv_shots, list);
continue;
}
} else /* bad */ {
shot->y += 30;
if ( ! inv_game_over &&
shot->y >= 535 &&
shot->y <= 565 &&
shot->x >= inv_our_x - 25 &&
shot->x <= inv_our_x + 25) {
inv_lives --;
inv_draw_explosion (inv_our_x, 550);
if (inv_lives <= 0) {
inv_do_game_over ();
} else {
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
g_slist_free (inv_shots);
inv_shots = NULL;
inv_our_x = 400;
inv_do_pause = TRUE;
inv_show_status ();
return TRUE;
}
}
if (shot->y >= 600) {
GSList *list = li;
li = li->next;
g_free (shot);
inv_shots = g_slist_delete_link (inv_shots, list);
continue;
}
}
li = li->next;
}
if ( ! inv_game_over) {
if (inv_left_pressed && inv_our_x > 100) {
inv_our_x -= 20;
inv_queue_draw (geginv);
} else if (inv_right_pressed && inv_our_x < 700) {
inv_our_x += 20;
inv_queue_draw (geginv);
}
}
if (shot_inhibit > 0)
shot_inhibit--;
if ( ! inv_game_over && inv_fire_pressed && shot_inhibit == 0) {
InvShot *shot = g_new0 (InvShot, 1);
shot->good = TRUE;
shot->x = inv_our_x;
shot->y = 540;
inv_shots = g_slist_prepend (inv_shots, shot);
shot_inhibit = 5;
inv_queue_draw (geginv);
}
if (inv_left_released)
inv_left_pressed = FALSE;
if (inv_right_released)
inv_right_pressed = FALSE;
if (inv_fire_released)
inv_fire_pressed = FALSE;
return TRUE;
}
static gboolean
inv_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
{
switch (event->keyval) {
case GDK_KEY_Left:
case GDK_KEY_KP_Left:
case GDK_KEY_Pointer_Left:
inv_left_pressed = TRUE;
inv_left_released = FALSE;
return TRUE;
case GDK_KEY_Right:
case GDK_KEY_KP_Right:
case GDK_KEY_Pointer_Right:
inv_right_pressed = TRUE;
inv_right_released = FALSE;
return TRUE;
case GDK_KEY_space:
case GDK_KEY_KP_Space:
inv_fire_pressed = TRUE;
inv_fire_released = FALSE;
return TRUE;
default:
break;
}
return FALSE;
}
static gboolean
inv_key_release (GtkWidget *widget, GdkEventKey *event, gpointer data)
{
switch (event->keyval) {
case GDK_KEY_Left:
case GDK_KEY_KP_Left:
case GDK_KEY_Pointer_Left:
inv_left_released = TRUE;
return TRUE;
case GDK_KEY_Right:
case GDK_KEY_KP_Right:
case GDK_KEY_Pointer_Right:
inv_right_released = TRUE;
return TRUE;
case GDK_KEY_space:
case GDK_KEY_KP_Space:
inv_fire_released = TRUE;
return TRUE;
case GDK_KEY_q:
case GDK_KEY_Q:
gtk_widget_destroy (widget);
return TRUE;
case GDK_KEY_p:
case GDK_KEY_P:
inv_paused = ! inv_paused;
inv_show_status ();
return TRUE;
default:
break;
}
return FALSE;
}
static gboolean
ensure_creatures (void)
{
GdkPixbuf *pb, *pb1;
if (inv_goat1 != NULL)
return TRUE;
pb = gdk_pixbuf_new_from_resource ("/technology.heckin/lebl-dialog/wanda.png",
NULL);
if (pb == NULL)
return FALSE;
pb1 = get_phsh_frame (pb, 1);
inv_phsh1 = pb_scale (pb1, inv_factor);
g_object_unref (G_OBJECT (pb1));
phsh_unsea (inv_phsh1);
pb1 = get_phsh_frame (pb, 2);
inv_phsh2 = pb_scale (pb1, inv_factor);
g_object_unref (G_OBJECT (pb1));
phsh_unsea (inv_phsh2);
g_object_unref (G_OBJECT (pb));
pb = gdk_pixbuf_new_from_resource ("/technology.heckin/lebl-dialog/gegl-1.png",
NULL);
if (pb == NULL) {
g_object_unref (G_OBJECT (inv_phsh1));
g_object_unref (G_OBJECT (inv_phsh2));
return FALSE;
}
inv_goat1 = pb_scale (pb, inv_factor * 0.66);
g_object_unref (pb);
pb = gdk_pixbuf_new_from_resource ("/technology.heckin/lebl-dialog/gegl-2.png",
NULL);
if (pb == NULL) {
g_object_unref (G_OBJECT (inv_goat1));
g_object_unref (G_OBJECT (inv_phsh1));
g_object_unref (G_OBJECT (inv_phsh2));
return FALSE;
}
inv_goat2 = pb_scale (pb, inv_factor * 0.66);
g_object_unref (pb);
inv_goat_width = gdk_pixbuf_get_width (inv_goat1);
inv_goat_height = gdk_pixbuf_get_height (inv_goat1);
inv_phsh_width = gdk_pixbuf_get_width (inv_phsh1);
inv_phsh_height = gdk_pixbuf_get_height (inv_phsh1);
return TRUE;
}
static void
geginv_destroyed (GtkWidget *w, gpointer data)
{
geginv = NULL;
}
static gboolean
inv_draw (GtkWidget *widget, cairo_t *cr)
{
GdkPixbuf *goat;
GSList *li;
int i, j;
if (geginv == NULL) {
inv_draw_idle = 0;
return TRUE;
}
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_paint (cr);
if (inv_goat_state == 0)
goat = inv_goat1;
else
goat = inv_goat2;
for (i = 0; i < INV_COLS; i++) {
for (j = 0; j < INV_ROWS; j++) {
int x, y;
if ( ! invs[i][j].live)
continue;
x = invs[i][j].x*inv_factor - inv_goat_width/2,
y = invs[i][j].y*inv_factor - inv_goat_height/2,
gdk_cairo_set_source_pixbuf (cr, goat, x, y);
cairo_rectangle (cr,
x, y,
inv_goat_width,
inv_goat_height);
cairo_fill (cr);
}
}
for (li = inv_shots; li != NULL; li = li->next) {
InvShot *shot = li->data;
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_rectangle (cr,
(shot->x-1)*inv_factor,
(shot->y-4)*inv_factor,
3, 8);
cairo_fill (cr);
}
if ( ! inv_game_over) {
GdkPixbuf *phsh;
if (inv_phsh_state < 5) {
phsh = inv_phsh1;
} else {
phsh = inv_phsh2;
}
gdk_cairo_set_source_pixbuf (cr, phsh,
inv_our_x*inv_factor - inv_phsh_width/2,
550*inv_factor - inv_phsh_height/2);
cairo_rectangle (cr,
inv_our_x*inv_factor - inv_phsh_width/2,
550*inv_factor - inv_phsh_height/2,
inv_phsh_width,
inv_phsh_height);
cairo_fill (cr);
}
if (inv_do_pause) {
g_usleep (G_USEC_PER_SEC);
inv_do_pause = FALSE;
}
inv_draw_idle = 0;
return TRUE;
}
gboolean pika_lebl_dialog (void);
gboolean
pika_lebl_dialog (void)
{
GdkMonitor *monitor;
GdkRectangle workarea;
GtkWidget *vbox;
int i, j;
if (geginv != NULL) {
gtk_window_present (GTK_WINDOW (geginv));
return FALSE;
}
inv_width = 800;
inv_height = 600;
monitor = pika_get_monitor_at_pointer ();
gdk_monitor_get_workarea (monitor, &workarea);
if (inv_width > workarea.width * 0.9) {
inv_width = workarea.width * 0.9;
inv_height = inv_width * (600.0/800.0);
}
if (inv_height > workarea.height * 0.9) {
inv_height = workarea.height * 0.9;
inv_width = inv_height * (800.0/600.0);
}
inv_factor = (double)inv_width / 800.0;
if ( ! ensure_creatures ())
return FALSE;
geginv = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position (GTK_WINDOW (geginv), GTK_WIN_POS_CENTER);
gtk_window_set_title (GTK_WINDOW (geginv), _("Killer GEGLs from Outer Space"));
g_object_set (G_OBJECT (geginv), "resizable", FALSE, NULL);
g_signal_connect (G_OBJECT (geginv), "destroy",
G_CALLBACK (geginv_destroyed),
NULL);
geginv_canvas = gtk_drawing_area_new ();
gtk_widget_set_size_request (geginv_canvas, inv_width, inv_height);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (geginv), vbox);
gtk_box_pack_start (GTK_BOX (vbox), geginv_canvas, TRUE, TRUE, 0);
geginv_label = gtk_label_new ("");
gtk_box_pack_start (GTK_BOX (vbox), geginv_label, FALSE, FALSE, 0);
inv_our_x = 400;
inv_x = 70;
inv_y = 70;
inv_first_col = 0;
inv_level = 0;
inv_lives = 3;
inv_last_col = INV_COLS-1;
inv_reverse = FALSE;
inv_game_over = FALSE;
inv_left_pressed = FALSE;
inv_right_pressed = FALSE;
inv_fire_pressed = FALSE;
inv_left_released = FALSE;
inv_right_released = FALSE;
inv_fire_released = FALSE;
inv_paused = FALSE;
gtk_widget_add_events (geginv, GDK_KEY_RELEASE_MASK);
g_signal_connect (G_OBJECT (geginv), "key_press_event",
G_CALLBACK (inv_key_press), NULL);
g_signal_connect (G_OBJECT (geginv), "key_release_event",
G_CALLBACK (inv_key_release), NULL);
g_signal_connect (G_OBJECT (geginv_canvas), "draw",
G_CALLBACK (inv_draw), NULL);
g_slist_foreach (inv_shots, (GFunc)g_free, NULL);
g_slist_free (inv_shots);
inv_shots = NULL;
for (i = 0; i < INV_COLS; i++) {
for (j = 0; j < INV_ROWS; j++) {
invs[i][j].live = TRUE;
invs[i][j].x = 70 + i * 100;
invs[i][j].y = 70 + j * 80;
}
}
inv_num = INV_ROWS * INV_COLS;
g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv);
g_timeout_add (90, geginv_move_timeout, geginv);
inv_show_status ();
gtk_widget_show_all (geginv);
return FALSE;
}

15397
app/dialogs/lebl-dialog.h Normal file

File diff suppressed because it is too large Load Diff

84
app/dialogs/meson.build Normal file
View File

@ -0,0 +1,84 @@
welcome_dialog_data_h = custom_target('welcome-dialog-data-h',
input : [meson.project_source_root() / 'tools/generate-welcome-dialog-data.py',
meson.project_source_root() / 'desktop/technology.heckin.PIKA.appdata.xml.in.in'],
output : ['welcome-dialog-data.h'],
command : [python, '@INPUT0@', pika_version, '--header'],
capture: true)
welcome_dialog_data_c = custom_target('welcome-dialog-data-c',
input : [meson.project_source_root() / 'tools/generate-welcome-dialog-data.py',
meson.project_source_root() / 'desktop/technology.heckin.PIKA.appdata.xml.in.in'],
output : ['welcome-dialog-data.c'],
command : [python, '@INPUT0@', pika_version],
capture: true)
libappdialogs_sources = [
'about-dialog.c',
'action-search-dialog.c',
'channel-options-dialog.c',
'color-profile-dialog.c',
'color-profile-import-dialog.c',
'convert-indexed-dialog.c',
'convert-precision-dialog.c',
'data-delete-dialog.c',
'dialogs-constructors.c',
'dialogs.c',
'extensions-dialog.c',
'file-open-dialog.c',
'file-open-location-dialog.c',
'file-save-dialog.c',
'fill-dialog.c',
'grid-dialog.c',
'image-merge-layers-dialog.c',
'image-new-dialog.c',
'image-properties-dialog.c',
'image-scale-dialog.c',
'input-devices-dialog.c',
'item-options-dialog.c',
'keyboard-shortcuts-dialog.c',
'layer-add-mask-dialog.c',
'layer-options-dialog.c',
'lebl-dialog.c',
'metadata-rotation-import-dialog.c',
'module-dialog.c',
'palette-import-dialog.c',
'preferences-dialog-utils.c',
'preferences-dialog.c',
'print-size-dialog.c',
'quit-dialog.c',
'resize-dialog.c',
'resolution-calibrate-dialog.c',
'scale-dialog.c',
'stroke-dialog.c',
'template-options-dialog.c',
'tips-dialog.c',
'tips-parser.c',
'user-install-dialog.c',
'vectors-export-dialog.c',
'vectors-import-dialog.c',
'vectors-options-dialog.c',
'welcome-dialog.c',
gitversion_h,
welcome_dialog_data_c,
welcome_dialog_data_h,
]
# Auto-generated sources
libappdialogs_sources += [
custom_target('authors.h',
input : [ 'authors.xsl', meson.project_source_root() / 'authors.xml' ],
output: [ 'authors.h' ],
command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT0@', '@INPUT1@' ],
)
]
libappdialogs = static_library('appdialogs',
libappdialogs_sources,
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Pika-Dialogs"',
dependencies: [
appstream_glib,
gegl,
gexiv2,
gtk3,
],
)

View File

@ -0,0 +1,296 @@
/* 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
*
* metadata-rotation-import-dialog.h
* Copyright (C) 2020 Jehan
*
* 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 <gegl.h>
#include <gexiv2/gexiv2.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaimage-metadata.h"
#include "core/pikapickable.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "metadata-rotation-import-dialog.h"
#include "pika-intl.h"
static PikaMetadataRotationPolicy pika_image_metadata_rotate_dialog (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
GExiv2Orientation orientation,
gboolean *dont_ask);
static GdkPixbuf * pika_image_metadata_rotate_pixbuf (GdkPixbuf *pixbuf,
GExiv2Orientation orientation);
/* public functions */
PikaMetadataRotationPolicy
metadata_rotation_import_dialog_run (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
gboolean *dont_ask)
{
PikaMetadata *metadata;
GExiv2Orientation orientation;
metadata = pika_image_get_metadata (image);
orientation = gexiv2_metadata_try_get_orientation (GEXIV2_METADATA (metadata), NULL);
if (orientation <= GEXIV2_ORIENTATION_NORMAL ||
orientation > GEXIV2_ORIENTATION_MAX)
return PIKA_METADATA_ROTATION_POLICY_KEEP;
return pika_image_metadata_rotate_dialog (image, context, parent,
orientation, dont_ask);
}
static PikaMetadataRotationPolicy
pika_image_metadata_rotate_dialog (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
GExiv2Orientation orientation,
gboolean *dont_ask)
{
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *vbox;
GtkWidget *label;
GtkWidget *toggle;
gchar *text;
GdkPixbuf *pixbuf;
gint width;
gint scale_factor;
gint height;
gint response;
dialog =
pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
_("Rotate Image?"),
"pika-metadata-rotate-dialog",
PIKA_ICON_OBJECT_ROTATE_180,
_("Apply metadata rotation"),
parent,
pika_standard_help_func,
PIKA_HELP_IMAGE_METADATA_ROTATION_IMPORT,
_("_Keep Original"), GTK_RESPONSE_CANCEL,
_("_Rotate"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, FALSE, FALSE, 0);
gtk_widget_show (main_vbox);
text = g_strdup_printf (_("The image '%s' contains Exif orientation "
"metadata"),
pika_image_get_display_name (image));
label = g_object_new (GTK_TYPE_LABEL,
"label", text,
"wrap", TRUE,
"justify", GTK_JUSTIFY_LEFT,
"xalign", 0.0,
"yalign", 0.5,
NULL);
g_free (text);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
scale_factor = gtk_widget_get_scale_factor (main_vbox);
width = pika_image_get_width (image);
height = pika_image_get_height (image);
#define MAX_THUMBNAIL_SIZE (128 * scale_factor)
if (width > MAX_THUMBNAIL_SIZE || height > MAX_THUMBNAIL_SIZE)
{
/* Adjust the width/height ratio to a maximum size (relative to
* current display scale factor.
*/
if (width > height)
{
height = MAX_THUMBNAIL_SIZE * height / width;
width = MAX_THUMBNAIL_SIZE;
}
else
{
width = MAX_THUMBNAIL_SIZE * width / height;
height = MAX_THUMBNAIL_SIZE;
}
}
pika_pickable_flush (PIKA_PICKABLE (image));
pixbuf = pika_viewable_get_pixbuf (PIKA_VIEWABLE (image), context,
width, height);
if (pixbuf)
{
GdkPixbuf *rotated;
GtkWidget *hbox;
GtkWidget *image;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
label = gtk_label_new (_("Original"));
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_end (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
image = gtk_image_new_from_pixbuf (pixbuf);
gtk_box_pack_end (GTK_BOX (vbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
label = gtk_label_new (_("Rotated"));
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_end (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
rotated = pika_image_metadata_rotate_pixbuf (pixbuf, orientation);
image = gtk_image_new_from_pixbuf (rotated);
g_object_unref (rotated);
gtk_box_pack_end (GTK_BOX (vbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
}
label = g_object_new (GTK_TYPE_LABEL,
"label", _("Would you like to rotate the image?"),
"wrap", TRUE,
"justify", GTK_JUSTIFY_LEFT,
"xalign", 0.0,
"yalign", 0.5,
NULL);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
toggle = gtk_check_button_new_with_mnemonic (_("_Don't ask me again"));
gtk_box_pack_end (GTK_BOX (main_vbox), toggle, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE);
gtk_widget_show (toggle);
response = pika_dialog_run (PIKA_DIALOG (dialog));
*dont_ask = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)));
gtk_widget_destroy (dialog);
return (response == GTK_RESPONSE_OK) ?
PIKA_METADATA_ROTATION_POLICY_ROTATE : PIKA_COLOR_PROFILE_POLICY_KEEP;
}
static GdkPixbuf *
pika_image_metadata_rotate_pixbuf (GdkPixbuf *pixbuf,
GExiv2Orientation orientation)
{
GdkPixbuf *rotated = NULL;
GdkPixbuf *temp;
switch (orientation)
{
case GEXIV2_ORIENTATION_UNSPECIFIED:
case GEXIV2_ORIENTATION_NORMAL: /* standard orientation, do nothing */
rotated = g_object_ref (pixbuf);
break;
case GEXIV2_ORIENTATION_HFLIP:
rotated = gdk_pixbuf_flip (pixbuf, TRUE);
break;
case GEXIV2_ORIENTATION_ROT_180:
rotated = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
break;
case GEXIV2_ORIENTATION_VFLIP:
rotated = gdk_pixbuf_flip (pixbuf, FALSE);
break;
case GEXIV2_ORIENTATION_ROT_90_HFLIP: /* flipped diagonally around '\' */
temp = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
rotated = gdk_pixbuf_flip (temp, TRUE);
g_object_unref (temp);
break;
case GEXIV2_ORIENTATION_ROT_90: /* 90 CW */
rotated = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
break;
case GEXIV2_ORIENTATION_ROT_90_VFLIP: /* flipped diagonally around '/' */
temp = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
rotated = gdk_pixbuf_flip (temp, FALSE);
g_object_unref (temp);
break;
case GEXIV2_ORIENTATION_ROT_270: /* 90 CCW */
rotated = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
break;
default: /* shouldn't happen */
break;
}
return rotated;
}

View File

@ -0,0 +1,36 @@
/* 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
*
* metadata-rotation-import-dialog.h
* Copyright (C) 2020 Jehan
*
* 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/>.
*/
#ifndef __METADATA_ROTATION_IMPORT_DIALOG_H__
#define __METADATA_ROTATION_IMPORT_DIALOG_H__
PikaMetadataRotationPolicy
metadata_rotation_import_dialog_run (PikaImage *image,
PikaContext *context,
GtkWidget *parent,
gboolean *dont_ask);
#endif /* __METADATA_ROTATION_IMPORT_DIALOG_H__*/

352
app/dialogs/module-dialog.c Normal file
View File

@ -0,0 +1,352 @@
/* 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
*
* module-dialog.c
* (C) 1999 Austin Donnelly <austin@gimp.org>
* (C) 2008 Sven Neumann <sven@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikamodule/pikamodule.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pika-modules.h"
#include "widgets/pikahelp-ids.h"
#include "module-dialog.h"
#include "pika-intl.h"
#define RESPONSE_REFRESH 1
enum
{
INFO_AUTHOR,
INFO_VERSION,
INFO_DATE,
INFO_COPYRIGHT,
INFO_LOCATION,
N_INFOS
};
typedef struct _ModuleDialog ModuleDialog;
struct _ModuleDialog
{
Pika *pika;
PikaModule *selected;
GtkListStore *list;
GtkWidget *listbox;
GtkWidget *hint;
GtkWidget *grid;
GtkWidget *label[N_INFOS];
GtkWidget *error_box;
GtkWidget *error_label;
};
/* local function prototypes */
static GtkWidget * create_widget_for_module (gpointer item,
gpointer user_data);
static void dialog_response (GtkWidget *widget,
gint response_id,
ModuleDialog *private);
static void dialog_destroy_callback (GtkWidget *widget,
ModuleDialog *private);
static void dialog_select_callback (GtkListBox *listbox,
GtkListBoxRow *row,
ModuleDialog *private);
static void dialog_enabled_toggled (GtkToggleButton *checkbox,
ModuleDialog *private);
static void dialog_info_init (ModuleDialog *private,
GtkWidget *grid);
/* public functions */
GtkWidget *
module_dialog_new (Pika *pika)
{
ModuleDialog *private;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *sw;
GtkWidget *image;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
private = g_slice_new0 (ModuleDialog);
private->pika = pika;
dialog = pika_dialog_new (_("Module Manager"),
"pika-modules", NULL, 0,
pika_standard_help_func, PIKA_HELP_MODULE_DIALOG,
_("_Refresh"), RESPONSE_REFRESH,
_("_Close"), GTK_RESPONSE_CLOSE,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_CLOSE,
RESPONSE_REFRESH,
-1);
g_signal_connect (dialog, "response",
G_CALLBACK (dialog_response),
private);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
private->hint = pika_hint_box_new (_("You will have to restart PIKA "
"for the changes to take effect."));
gtk_box_pack_start (GTK_BOX (vbox), private->hint, FALSE, FALSE, 0);
if (pika->write_modulerc)
gtk_widget_show (private->hint);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_widget_set_size_request (sw, 124, 100);
gtk_widget_show (sw);
private->listbox = gtk_list_box_new ();
gtk_list_box_set_selection_mode (GTK_LIST_BOX (private->listbox),
GTK_SELECTION_BROWSE);
gtk_list_box_bind_model (GTK_LIST_BOX (private->listbox),
G_LIST_MODEL (pika->module_db),
create_widget_for_module,
private,
NULL);
g_signal_connect (private->listbox, "row-selected",
G_CALLBACK (dialog_select_callback),
private);
gtk_container_add (GTK_CONTAINER (sw), private->listbox);
gtk_widget_show (private->listbox);
private->grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (private->grid), 6);
gtk_box_pack_start (GTK_BOX (vbox), private->grid, FALSE, FALSE, 0);
gtk_widget_show (private->grid);
private->error_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), private->error_box, FALSE, FALSE, 0);
image = gtk_image_new_from_icon_name (PIKA_ICON_DIALOG_WARNING,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (private->error_box), image, FALSE, FALSE, 0);
gtk_widget_show (image);
private->error_label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (private->error_label), 0.0);
gtk_box_pack_start (GTK_BOX (private->error_box),
private->error_label, TRUE, TRUE, 0);
gtk_widget_show (private->error_label);
dialog_info_init (private, private->grid);
g_signal_connect (dialog, "destroy",
G_CALLBACK (dialog_destroy_callback),
private);
return dialog;
}
/* private functions */
static GtkWidget *
create_widget_for_module (gpointer item,
gpointer user_data)
{
PikaModule *module = PIKA_MODULE (item);
ModuleDialog *private = user_data;
const PikaModuleInfo *info = pika_module_get_info (module);
GFile *file = pika_module_get_file (module);
GtkWidget *row;
GtkWidget *grid;
GtkWidget *label;
GtkWidget *checkbox;
row = gtk_list_box_row_new ();
g_object_set_data (G_OBJECT (row), "module", module);
gtk_widget_show (row);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
g_object_set (grid, "margin", 3, NULL);
gtk_container_add (GTK_CONTAINER (row), grid);
gtk_widget_show (grid);
checkbox = gtk_check_button_new ();
g_object_bind_property (module, "auto-load", checkbox, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
g_signal_connect (checkbox, "toggled",
G_CALLBACK (dialog_enabled_toggled),
private);
gtk_widget_show (checkbox);
gtk_grid_attach (GTK_GRID (grid), checkbox, 0, 0, 1, 1);
label = gtk_label_new (info ? gettext (info->purpose) :
pika_file_get_utf8_name (file));
gtk_widget_show (label);
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
return row;
}
static void
dialog_response (GtkWidget *widget,
gint response_id,
ModuleDialog *private)
{
if (response_id == RESPONSE_REFRESH)
pika_modules_refresh (private->pika);
else
gtk_widget_destroy (widget);
}
static void
dialog_destroy_callback (GtkWidget *widget,
ModuleDialog *private)
{
g_slice_free (ModuleDialog, private);
}
static void
dialog_select_callback (GtkListBox *listbox,
GtkListBoxRow *row,
ModuleDialog *private)
{
guint i;
PikaModule *module;
const PikaModuleInfo *info;
const gchar *location = NULL;
const gchar *text[N_INFOS] = { NULL, };
gboolean show_error;
if (row == NULL)
{
for (i = 0; i < N_INFOS; i++)
gtk_label_set_text (GTK_LABEL (private->label[i]), NULL);
gtk_label_set_text (GTK_LABEL (private->error_label), NULL);
gtk_widget_hide (private->error_box);
return;
}
module = g_object_get_data (G_OBJECT (row), "module");
if (private->selected == module)
return;
private->selected = module;
if (pika_module_is_on_disk (module))
location = pika_file_get_utf8_name (pika_module_get_file (module));
info = pika_module_get_info (module);
if (info)
{
text[INFO_AUTHOR] = info->author;
text[INFO_VERSION] = info->version;
text[INFO_DATE] = info->date;
text[INFO_COPYRIGHT] = info->copyright;
text[INFO_LOCATION] = location ? location : _("Only in memory");
}
else
{
text[INFO_LOCATION] = location ? location : _("No longer available");
}
for (i = 0; i < N_INFOS; i++)
gtk_label_set_text (GTK_LABEL (private->label[i]),
text[i] ? text[i] : "--");
/* Show errors */
show_error = (pika_module_get_state (module) == PIKA_MODULE_STATE_ERROR &&
pika_module_get_last_error (module));
gtk_label_set_text (GTK_LABEL (private->error_label),
show_error ? pika_module_get_last_error (module) : NULL);
gtk_widget_set_visible (private->error_box, show_error);
}
static void
dialog_enabled_toggled (GtkToggleButton *checkbox,
ModuleDialog *private)
{
private->pika->write_modulerc = TRUE;
gtk_widget_show (private->hint);
}
static void
dialog_info_init (ModuleDialog *private,
GtkWidget *grid)
{
GtkWidget *label;
gint i;
const gchar * const text[] =
{
N_("Author:"),
N_("Version:"),
N_("Date:"),
N_("Copyright:"),
N_("Location:")
};
for (i = 0; i < G_N_ELEMENTS (text); i++)
{
label = gtk_label_new (gettext (text[i]));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (GTK_GRID (grid), label, 0, i, 1, 1);
gtk_widget_show (label);
private->label[i] = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (private->label[i]), 0.0);
gtk_label_set_ellipsize (GTK_LABEL (private->label[i]),
PANGO_ELLIPSIZE_END);
gtk_grid_attach (GTK_GRID (grid), private->label[i], 1, i, 1, 1);
gtk_widget_show (private->label[i]);
}
}

View File

@ -0,0 +1,31 @@
/* 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
*
* module-dialog.h
* (C) 1999 Austin Donnelly <austin@gimp.org>
*
* 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/>.
*/
#ifndef __MODULE_DIALOG_H__
GtkWidget * module_dialog_new (Pika *pika);
#endif /* __MODULE_DIALOG_H__ */

View File

@ -0,0 +1,887 @@
/* 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 <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikacontext.h"
#include "core/pikadatafactory.h"
#include "core/pikadrawable.h"
#include "core/pikagradient.h"
#include "core/pikaimage.h"
#include "core/pikapalette.h"
#include "core/pikapalette-import.h"
#include "widgets/pikacontainercombobox.h"
#include "widgets/pikadnd.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaview.h"
#include "widgets/pikawidgets-utils.h"
#include "palette-import-dialog.h"
#include "pika-intl.h"
typedef enum
{
GRADIENT_IMPORT,
IMAGE_IMPORT,
FILE_IMPORT
} ImportType;
typedef struct _ImportDialog ImportDialog;
struct _ImportDialog
{
GtkWidget *dialog;
ImportType import_type;
PikaContext *context;
PikaImage *image;
PikaPalette *palette;
GtkWidget *gradient_radio;
GtkWidget *image_radio;
GtkWidget *file_radio;
GtkWidget *gradient_combo;
GtkWidget *image_combo;
GtkWidget *file_chooser;
GtkWidget *sample_merged_toggle;
GtkWidget *selection_only_toggle;
GtkWidget *entry;
GtkWidget *num_colors;
GtkWidget *columns;
GtkWidget *threshold;
GtkWidget *preview;
GtkWidget *no_colors_label;
};
static void palette_import_free (ImportDialog *private);
static void palette_import_response (GtkWidget *dialog,
gint response_id,
ImportDialog *private);
static void palette_import_gradient_changed (PikaContext *context,
PikaGradient *gradient,
ImportDialog *private);
static void palette_import_image_changed (PikaContext *context,
PikaImage *image,
ImportDialog *private);
static void palette_import_layer_changed (PikaImage *image,
ImportDialog *private);
static void palette_import_mask_changed (PikaImage *image,
ImportDialog *private);
static void palette_import_filename_changed (GtkFileChooser *button,
ImportDialog *private);
static void import_dialog_drop_callback (GtkWidget *widget,
gint x,
gint y,
PikaViewable *viewable,
gpointer data);
static void palette_import_grad_callback (GtkWidget *widget,
ImportDialog *private);
static void palette_import_image_callback (GtkWidget *widget,
ImportDialog *private);
static void palette_import_file_callback (GtkWidget *widget,
ImportDialog *private);
static void palette_import_columns_changed (PikaLabelSpin *columns,
ImportDialog *private);
static void palette_import_image_add (PikaContainer *container,
PikaImage *image,
ImportDialog *private);
static void palette_import_image_remove (PikaContainer *container,
PikaImage *image,
ImportDialog *private);
static void palette_import_make_palette (ImportDialog *private);
/* public functions */
GtkWidget *
palette_import_dialog_new (PikaContext *context)
{
ImportDialog *private;
PikaGradient *gradient;
GtkWidget *dialog;
GtkWidget *main_hbox;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *grid;
GtkSizeGroup *size_group;
GSList *group = NULL;
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
gradient = pika_context_get_gradient (context);
private = g_slice_new0 (ImportDialog);
private->import_type = GRADIENT_IMPORT;
private->context = pika_context_new (context->pika, "Palette Import",
context);
dialog = private->dialog =
pika_dialog_new (_("Import a New Palette"),
"pika-palette-import", NULL, 0,
pika_standard_help_func,
PIKA_HELP_PALETTE_IMPORT,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Import"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) palette_import_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (palette_import_response),
private);
pika_dnd_viewable_dest_add (dialog,
PIKA_TYPE_GRADIENT,
import_dialog_drop_callback,
private);
pika_dnd_viewable_dest_add (dialog,
PIKA_TYPE_IMAGE,
import_dialog_drop_callback,
private);
main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_hbox, TRUE, TRUE, 0);
gtk_widget_show (main_hbox);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start (GTK_BOX (main_hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
/* The "Source" frame */
frame = pika_frame_new (_("Select Source"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_container_add (GTK_CONTAINER (frame), grid);
gtk_widget_show (grid);
private->gradient_radio =
gtk_radio_button_new_with_mnemonic (group, _("_Gradient"));
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (private->gradient_radio));
gtk_grid_attach (GTK_GRID (grid), private->gradient_radio, 0, 0, 1, 1);
gtk_widget_show (private->gradient_radio);
g_signal_connect (private->gradient_radio, "toggled",
G_CALLBACK (palette_import_grad_callback),
private);
private->image_radio =
gtk_radio_button_new_with_mnemonic (group, _("I_mage"));
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (private->image_radio));
gtk_grid_attach (GTK_GRID (grid), private->image_radio, 0, 1, 1, 1);
gtk_widget_show (private->image_radio);
g_signal_connect (private->image_radio, "toggled",
G_CALLBACK (palette_import_image_callback),
private);
gtk_widget_set_sensitive (private->image_radio,
! pika_container_is_empty (context->pika->images));
private->sample_merged_toggle =
gtk_check_button_new_with_mnemonic (_("Sample _Merged"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->sample_merged_toggle),
TRUE);
gtk_grid_attach (GTK_GRID (grid), private->sample_merged_toggle, 1, 2, 1, 1);
gtk_widget_show (private->sample_merged_toggle);
g_signal_connect_swapped (private->sample_merged_toggle, "toggled",
G_CALLBACK (palette_import_make_palette),
private);
private->selection_only_toggle =
gtk_check_button_new_with_mnemonic (_("_Selected Pixels only"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->selection_only_toggle),
FALSE);
gtk_grid_attach (GTK_GRID (grid), private->selection_only_toggle, 1, 3, 1, 1);
gtk_widget_show (private->selection_only_toggle);
g_signal_connect_swapped (private->selection_only_toggle, "toggled",
G_CALLBACK (palette_import_make_palette),
private);
private->file_radio =
gtk_radio_button_new_with_mnemonic (group, _("Palette _file"));
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (private->image_radio));
gtk_grid_attach (GTK_GRID (grid), private->file_radio, 0, 4, 1, 1);
gtk_widget_show (private->file_radio);
g_signal_connect (private->file_radio, "toggled",
G_CALLBACK (palette_import_file_callback),
private);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
/* The gradient menu */
private->gradient_combo =
pika_container_combo_box_new (pika_data_factory_get_container (context->pika->gradient_factory),
private->context, 24, 1);
pika_grid_attach_aligned (GTK_GRID (grid), 0, 0,
NULL, 0.0, 0.5, private->gradient_combo, 1);
gtk_size_group_add_widget (size_group, private->gradient_combo);
/* The image menu */
private->image_combo =
pika_container_combo_box_new (context->pika->images, private->context,
24, 1);
pika_grid_attach_aligned (GTK_GRID (grid), 0, 1,
NULL, 0.0, 0.5, private->image_combo, 1);
gtk_size_group_add_widget (size_group, private->image_combo);
/* Palette file name entry */
private->file_chooser = gtk_file_chooser_button_new (_("Select Palette File"),
GTK_FILE_CHOOSER_ACTION_OPEN);
pika_grid_attach_aligned (GTK_GRID (grid), 0, 4,
NULL, 0.0, 0.5, private->file_chooser, 1);
gtk_size_group_add_widget (size_group, private->file_chooser);
g_object_unref (size_group);
/* The "Import" frame */
frame = pika_frame_new (_("Import Options"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_container_add (GTK_CONTAINER (frame), grid);
gtk_widget_show (grid);
/* The source's name */
private->entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (private->entry),
gradient ?
pika_object_get_name (gradient) : _("New import"));
pika_grid_attach_aligned (GTK_GRID (grid), 0, 0,
_("Palette _name:"), 0.0, 0.5,
private->entry, 2);
/* The # of colors */
private->num_colors = pika_scale_entry_new (_("N_umber of colors:"),
256, 2, 10000, 0);
pika_grid_attach_aligned (GTK_GRID (grid), -1, 1,
NULL, 0.0, 0.5,
private->num_colors, 3);
pika_scale_entry_set_logarithmic (PIKA_SCALE_ENTRY (private->num_colors), TRUE);
g_signal_connect_swapped (private->num_colors,
"value-changed",
G_CALLBACK (palette_import_make_palette),
private);
/* The columns */
private->columns = pika_scale_entry_new (_("C_olumns:"), 16, 0, 64, 0);
pika_grid_attach_aligned (GTK_GRID (grid), -1, 2,
NULL, 0.0, 0.5,
private->columns, 3);
g_signal_connect (private->columns, "value-changed",
G_CALLBACK (palette_import_columns_changed),
private);
/* The interval */
private->threshold = pika_scale_entry_new (_("I_nterval:"), 1, 1, 128, 0);
pika_grid_attach_aligned (GTK_GRID (grid), -1, 3,
NULL, 0.0, 0.5,
private->threshold, 3);
g_signal_connect_swapped (private->threshold, "value-changed",
G_CALLBACK (palette_import_make_palette),
private);
/* The "Preview" frame */
frame = pika_frame_new (_("Preview"));
gtk_box_pack_start (GTK_BOX (main_hbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
private->preview = pika_view_new_full_by_types (private->context,
PIKA_TYPE_VIEW,
PIKA_TYPE_PALETTE,
192, 192, 1,
TRUE, FALSE, FALSE);
gtk_widget_set_halign (private->preview, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), private->preview, FALSE, FALSE, 0);
gtk_widget_show (private->preview);
private->no_colors_label =
gtk_label_new (_("The selected source contains no colors."));
gtk_widget_set_size_request (private->no_colors_label, 194, -1);
gtk_label_set_line_wrap (GTK_LABEL (private->no_colors_label), TRUE);
pika_label_set_attributes (GTK_LABEL (private->no_colors_label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_start (GTK_BOX (vbox), private->no_colors_label, FALSE, FALSE, 0);
gtk_widget_show (private->no_colors_label);
/* keep the dialog up-to-date */
g_signal_connect (context->pika->images, "add",
G_CALLBACK (palette_import_image_add),
private);
g_signal_connect (context->pika->images, "remove",
G_CALLBACK (palette_import_image_remove),
private);
g_signal_connect (private->context, "gradient-changed",
G_CALLBACK (palette_import_gradient_changed),
private);
g_signal_connect (private->context, "image-changed",
G_CALLBACK (palette_import_image_changed),
private);
g_signal_connect (private->file_chooser, "selection-changed",
G_CALLBACK (palette_import_filename_changed),
private);
palette_import_grad_callback (private->gradient_radio, private);
return dialog;
}
/* private functions */
static void
palette_import_free (ImportDialog *private)
{
Pika *pika = private->context->pika;
g_signal_handlers_disconnect_by_func (pika->images,
palette_import_image_add,
private);
g_signal_handlers_disconnect_by_func (pika->images,
palette_import_image_remove,
private);
if (private->palette)
g_object_unref (private->palette);
g_object_unref (private->context);
g_slice_free (ImportDialog, private);
}
/* the palette import response callback ************************************/
static void
palette_import_response (GtkWidget *dialog,
gint response_id,
ImportDialog *private)
{
palette_import_image_changed (private->context, NULL, private);
if (response_id == GTK_RESPONSE_OK)
{
Pika *pika = private->context->pika;
if (private->palette &&
pika_palette_get_n_colors (private->palette) > 0)
{
const gchar *name = gtk_entry_get_text (GTK_ENTRY (private->entry));
if (name && *name)
pika_object_set_name (PIKA_OBJECT (private->palette), name);
pika_container_add (pika_data_factory_get_container (pika->palette_factory),
PIKA_OBJECT (private->palette));
}
else
{
pika_message_literal (pika, G_OBJECT (dialog), PIKA_MESSAGE_ERROR,
_("There is no palette to import."));
return;
}
}
gtk_widget_destroy (dialog);
}
/* functions to create & update the import dialog's gradient selection *****/
static void
palette_import_gradient_changed (PikaContext *context,
PikaGradient *gradient,
ImportDialog *private)
{
if (gradient && private->import_type == GRADIENT_IMPORT)
{
gtk_entry_set_text (GTK_ENTRY (private->entry),
pika_object_get_name (gradient));
palette_import_make_palette (private);
}
}
static void
palette_import_image_changed (PikaContext *context,
PikaImage *image,
ImportDialog *private)
{
if (private->image)
{
g_signal_handlers_disconnect_by_func (private->image,
palette_import_layer_changed,
private);
g_signal_handlers_disconnect_by_func (private->image,
palette_import_mask_changed,
private);
}
private->image = image;
if (private->import_type == IMAGE_IMPORT)
{
gboolean sensitive = FALSE;
if (image)
{
gchar *label;
label = g_strdup_printf ("%s-%d",
pika_image_get_display_name (image),
pika_image_get_id (image));
gtk_entry_set_text (GTK_ENTRY (private->entry), label);
g_free (label);
palette_import_make_palette (private);
if (pika_image_get_base_type (image) != PIKA_INDEXED)
sensitive = TRUE;
}
gtk_widget_set_sensitive (private->sample_merged_toggle, sensitive);
gtk_widget_set_sensitive (private->selection_only_toggle, sensitive);
gtk_widget_set_sensitive (private->threshold, sensitive);
gtk_widget_set_sensitive (private->num_colors, sensitive);
}
if (private->image)
{
g_signal_connect (private->image, "selected-layers-changed",
G_CALLBACK (palette_import_layer_changed),
private);
g_signal_connect (private->image, "mask-changed",
G_CALLBACK (palette_import_mask_changed),
private);
}
}
static void
palette_import_layer_changed (PikaImage *image,
ImportDialog *private)
{
if (private->import_type == IMAGE_IMPORT &&
! gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (private->sample_merged_toggle)))
{
palette_import_make_palette (private);
}
}
static void
palette_import_mask_changed (PikaImage *image,
ImportDialog *private)
{
if (private->import_type == IMAGE_IMPORT &&
gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (private->selection_only_toggle)))
{
palette_import_make_palette (private);
}
}
static void
palette_import_filename_changed (GtkFileChooser *button,
ImportDialog *private)
{
gchar *filename;
if (private->import_type != FILE_IMPORT)
return;
filename = gtk_file_chooser_get_filename (button);
if (filename)
{
gchar *basename = g_filename_display_basename (filename);
/* TODO: strip filename extension */
gtk_entry_set_text (GTK_ENTRY (private->entry), basename);
g_free (basename);
}
else
{
gtk_entry_set_text (GTK_ENTRY (private->entry), "");
}
g_free (filename);
palette_import_make_palette (private);
}
static void
import_dialog_drop_callback (GtkWidget *widget,
gint x,
gint y,
PikaViewable *viewable,
gpointer data)
{
ImportDialog *private = data;
pika_context_set_by_type (private->context,
G_TYPE_FROM_INSTANCE (viewable),
PIKA_OBJECT (viewable));
if (PIKA_IS_GRADIENT (viewable) &&
private->import_type != GRADIENT_IMPORT)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->gradient_radio),
TRUE);
}
else if (PIKA_IS_IMAGE (viewable) &&
private->import_type != IMAGE_IMPORT)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->image_radio),
TRUE);
}
}
/* the import source menu item callbacks ***********************************/
static void
palette_import_set_sensitive (ImportDialog *private)
{
gboolean gradient = (private->import_type == GRADIENT_IMPORT);
gboolean image = (private->import_type == IMAGE_IMPORT);
gboolean file = (private->import_type == FILE_IMPORT);
gtk_widget_set_sensitive (private->gradient_combo, gradient);
gtk_widget_set_sensitive (private->image_combo, image);
gtk_widget_set_sensitive (private->sample_merged_toggle, image);
gtk_widget_set_sensitive (private->selection_only_toggle, image);
gtk_widget_set_sensitive (private->file_chooser, file);
gtk_widget_set_sensitive (private->num_colors, ! file);
gtk_widget_set_sensitive (private->columns, ! file);
gtk_widget_set_sensitive (private->threshold, image);
}
static void
palette_import_grad_callback (GtkWidget *widget,
ImportDialog *private)
{
PikaGradient *gradient;
if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
return;
private->import_type = GRADIENT_IMPORT;
gradient = pika_context_get_gradient (private->context);
gtk_entry_set_text (GTK_ENTRY (private->entry),
pika_object_get_name (gradient));
palette_import_set_sensitive (private);
palette_import_make_palette (private);
}
static void
palette_import_image_callback (GtkWidget *widget,
ImportDialog *private)
{
PikaImage *image;
if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
return;
private->import_type = IMAGE_IMPORT;
image = pika_context_get_image (private->context);
if (! image)
{
PikaContainer *images = private->context->pika->images;
image = PIKA_IMAGE (pika_container_get_first_child (images));
}
palette_import_set_sensitive (private);
palette_import_image_changed (private->context, image, private);
}
static void
palette_import_file_callback (GtkWidget *widget,
ImportDialog *private)
{
gchar *filename;
if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
return;
private->import_type = FILE_IMPORT;
filename =
gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (private->file_chooser));
if (filename)
{
gchar *basename = g_filename_display_basename (filename);
/* TODO: strip filename extension */
gtk_entry_set_text (GTK_ENTRY (private->entry), basename);
g_free (basename);
g_free (filename);
}
else
{
gtk_entry_set_text (GTK_ENTRY (private->entry), "");
}
palette_import_set_sensitive (private);
}
static void
palette_import_columns_changed (PikaLabelSpin *columns,
ImportDialog *private)
{
if (private->palette)
pika_palette_set_columns (private->palette,
ROUND (pika_label_spin_get_value (columns)));
}
/* functions & callbacks to keep the import dialog uptodate ****************/
static void
palette_import_image_add (PikaContainer *container,
PikaImage *image,
ImportDialog *private)
{
if (! gtk_widget_is_sensitive (private->image_radio))
{
gtk_widget_set_sensitive (private->image_radio, TRUE);
pika_context_set_image (private->context, image);
}
}
static void
palette_import_image_remove (PikaContainer *container,
PikaImage *image,
ImportDialog *private)
{
if (! pika_container_get_n_children (private->context->pika->images))
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (private->image_radio)))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->gradient_radio),
TRUE);
gtk_widget_set_sensitive (private->image_radio, FALSE);
}
}
static void
palette_import_make_palette (ImportDialog *private)
{
PikaPalette *palette = NULL;
const gchar *palette_name;
gint n_colors;
gint n_columns;
gint threshold;
palette_name = gtk_entry_get_text (GTK_ENTRY (private->entry));
if (! palette_name || ! strlen (palette_name))
palette_name = _("Untitled");
n_colors = ROUND (pika_label_spin_get_value (PIKA_LABEL_SPIN (private->num_colors)));
n_columns = ROUND (pika_label_spin_get_value (PIKA_LABEL_SPIN (private->columns)));
threshold = ROUND (pika_label_spin_get_value (PIKA_LABEL_SPIN (private->threshold)));
switch (private->import_type)
{
case GRADIENT_IMPORT:
{
PikaGradient *gradient;
gradient = pika_context_get_gradient (private->context);
palette = pika_palette_import_from_gradient (gradient,
private->context,
FALSE,
PIKA_GRADIENT_BLEND_RGB_PERCEPTUAL,
palette_name,
n_colors);
}
break;
case IMAGE_IMPORT:
{
PikaImage *image = pika_context_get_image (private->context);
gboolean sample_merged;
gboolean selection_only;
sample_merged =
gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (private->sample_merged_toggle));
selection_only =
gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (private->selection_only_toggle));
if (pika_image_get_base_type (image) == PIKA_INDEXED)
{
palette = pika_palette_import_from_indexed_image (image,
private->context,
palette_name);
}
else if (sample_merged)
{
palette = pika_palette_import_from_image (image,
private->context,
palette_name,
n_colors,
threshold,
selection_only);
}
else
{
GList *drawables;
drawables = pika_image_get_selected_layers (image);
if (drawables)
palette = pika_palette_import_from_drawables (drawables,
private->context,
palette_name,
n_colors,
threshold,
selection_only);
}
}
break;
case FILE_IMPORT:
{
GFile *file;
GError *error = NULL;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (private->file_chooser));
palette = pika_palette_import_from_file (private->context,
file,
palette_name, &error);
g_object_unref (file);
if (! palette)
{
pika_message_literal (private->context->pika,
G_OBJECT (private->dialog), PIKA_MESSAGE_ERROR,
error->message);
g_error_free (error);
}
else
{
gint columns = pika_palette_get_columns (palette);
if (columns > 0)
{
n_columns = columns;
pika_label_spin_set_value (PIKA_LABEL_SPIN (private->columns),
n_columns);
}
}
}
break;
}
if (private->palette)
g_object_unref (private->palette);
private->palette = palette;
if (palette)
{
pika_palette_set_columns (palette, n_columns);
pika_view_set_viewable (PIKA_VIEW (private->preview),
PIKA_VIEWABLE (palette));
}
gtk_widget_set_visible (private->no_colors_label,
! (palette &&
pika_palette_get_n_colors (palette) > 0));
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __PALETTE_IMPORT_DIALOG_H__
#define __PALETTE_IMPORT_DIALOG_H__
GtkWidget * palette_import_dialog_new (PikaContext *context);
#endif /* __PALETTE_IMPORT_DIALOG_H__ */

View File

@ -0,0 +1,429 @@
/* 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-1997 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "widgets/pikacolorpanel.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-constructors.h"
#include "preferences-dialog-utils.h"
GtkWidget *
prefs_frame_new (const gchar *label,
GtkContainer *parent,
gboolean expand)
{
GtkWidget *frame;
GtkWidget *vbox;
frame = pika_frame_new (label);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
if (GTK_IS_BOX (parent))
gtk_box_pack_start (GTK_BOX (parent), frame, expand, expand, 0);
else
gtk_container_add (parent, frame);
gtk_widget_show (frame);
return vbox;
}
GtkWidget *
prefs_grid_new (GtkContainer *parent)
{
GtkWidget *grid;
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
if (GTK_IS_BOX (parent))
gtk_box_pack_start (GTK_BOX (parent), grid, FALSE, FALSE, 0);
else
gtk_container_add (parent, grid);
gtk_widget_show (grid);
return grid;
}
GtkWidget *
prefs_hint_box_new (const gchar *icon_name,
const gchar *text)
{
GtkWidget *hbox;
GtkWidget *image;
GtkWidget *label;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
label = gtk_label_new (text);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
gtk_widget_show (hbox);
return hbox;
}
GtkWidget *
prefs_button_add (const gchar *icon_name,
const gchar *label,
GtkBox *box)
{
GtkWidget *button;
button = pika_icon_button_new (icon_name, label);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
gtk_widget_show (button);
return button;
}
GtkWidget *
prefs_check_button_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkBox *vbox)
{
GtkWidget *button;
button = pika_prop_check_button_new (config, property_name, label);
if (button)
gtk_box_pack_start (vbox, button, FALSE, FALSE, 0);
return button;
}
GtkWidget *
prefs_switch_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkBox *vbox,
GtkSizeGroup *group)
{
GtkWidget *box;
GtkWidget *plabel;
box = pika_prop_switch_new (config, property_name, label, &plabel, NULL);
if (!box)
return NULL;
gtk_box_pack_start (vbox, box, FALSE, FALSE, 0);
gtk_label_set_xalign (GTK_LABEL (plabel), 0.0);
if (group)
gtk_size_group_add_widget (group, plabel);
return box;
}
GtkWidget *
prefs_check_button_add_with_icon (GObject *config,
const gchar *property_name,
const gchar *label,
const gchar *icon_name,
GtkBox *vbox,
GtkSizeGroup *group)
{
GtkWidget *button;
GtkWidget *hbox;
GtkWidget *image;
button = pika_prop_check_button_new (config, property_name, label);
if (! button)
return NULL;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (vbox, hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
g_object_set (image,
"margin-start", 2,
"margin-end", 2,
"margin-top", 2,
"margin-bottom", 2,
NULL);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
if (group)
gtk_size_group_add_widget (group, image);
return button;
}
GtkWidget *
prefs_widget_add_aligned (GtkWidget *widget,
const gchar *text,
GtkGrid *grid,
gint grid_top,
gboolean left_align,
GtkSizeGroup *group)
{
GtkWidget *label = pika_grid_attach_aligned (grid, 0, grid_top,
text, 0.0, 0.5,
widget, 1);
if (group)
gtk_size_group_add_widget (group, label);
if (left_align == TRUE)
gtk_widget_set_halign (widget, GTK_ALIGN_START);
return label;
}
GtkWidget *
prefs_color_button_add (GObject *config,
const gchar *property_name,
const gchar *label,
const gchar *title,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group,
PikaContext *context)
{
GtkWidget *button;
GParamSpec *pspec;
gboolean has_alpha;
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
property_name);
has_alpha = pika_param_spec_rgb_has_alpha (pspec);
button = pika_prop_color_button_new (config, property_name,
title,
PREFS_COLOR_BUTTON_WIDTH,
PREFS_COLOR_BUTTON_HEIGHT,
has_alpha ?
PIKA_COLOR_AREA_SMALL_CHECKS :
PIKA_COLOR_AREA_FLAT);
if (button)
{
if (context)
pika_color_panel_set_context (PIKA_COLOR_PANEL (button), context);
prefs_widget_add_aligned (button, label, grid, grid_top, TRUE, group);
}
return button;
}
GtkWidget *
prefs_entry_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *entry = pika_prop_entry_new (config, property_name, -1);
if (entry)
prefs_widget_add_aligned (entry, label, grid, grid_top, FALSE, group);
return entry;
}
GtkWidget *
prefs_spin_button_add (GObject *config,
const gchar *property_name,
gdouble step_increment,
gdouble page_increment,
gint digits,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *button = pika_prop_spin_button_new (config, property_name,
step_increment,
page_increment,
digits);
if (button)
prefs_widget_add_aligned (button, label, grid, grid_top, TRUE, group);
return button;
}
GtkWidget *
prefs_memsize_entry_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *entry = pika_prop_memsize_entry_new (config, property_name);
if (entry)
prefs_widget_add_aligned (entry, label, grid, grid_top, TRUE, group);
return entry;
}
GtkWidget *
prefs_file_chooser_button_add (GObject *config,
const gchar *property_name,
const gchar *label,
const gchar *dialog_title,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *button;
button = pika_prop_file_chooser_button_new (config, property_name,
dialog_title,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
if (button)
prefs_widget_add_aligned (button, label, grid, grid_top, FALSE, group);
return button;
}
GtkWidget *
prefs_enum_combo_box_add (GObject *config,
const gchar *property_name,
gint minimum,
gint maximum,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *combo = pika_prop_enum_combo_box_new (config, property_name,
minimum, maximum);
if (combo)
prefs_widget_add_aligned (combo, label, grid, grid_top, FALSE, group);
return combo;
}
GtkWidget *
prefs_boolean_combo_box_add (GObject *config,
const gchar *property_name,
const gchar *true_text,
const gchar *false_text,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *combo = pika_prop_boolean_combo_box_new (config, property_name,
true_text, false_text);
if (combo)
prefs_widget_add_aligned (combo, label, grid, grid_top, FALSE, group);
return combo;
}
#ifdef HAVE_ISO_CODES
GtkWidget *
prefs_language_combo_box_add (GObject *config,
const gchar *property_name,
GtkBox *vbox)
{
GtkWidget *combo = pika_prop_language_combo_box_new (config, property_name);
if (combo)
gtk_box_pack_start (vbox, combo, FALSE, FALSE, 0);
return combo;
}
#endif
GtkWidget *
prefs_profile_combo_box_add (GObject *config,
const gchar *property_name,
GtkListStore *profile_store,
const gchar *dialog_title,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group,
GObject *profile_path_config,
const gchar *profile_path_property_name)
{
GtkWidget *combo = pika_prop_profile_combo_box_new (config,
property_name,
profile_store,
dialog_title,
profile_path_config,
profile_path_property_name);
if (combo)
prefs_widget_add_aligned (combo, label, grid, grid_top, FALSE, group);
return combo;
}
GtkWidget *
prefs_compression_combo_box_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group)
{
GtkWidget *combo = pika_prop_compression_combo_box_new (config,
property_name);
if (combo)
prefs_widget_add_aligned (combo, label, grid, grid_top, FALSE, group);
return combo;
}

View File

@ -0,0 +1,142 @@
/* 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-1997 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/>.
*/
#ifndef __PREFERENCES_DIALOG_UTILS_H__
#define __PREFERENCES_DIALOG_UTILS_H__
#define PREFS_COLOR_BUTTON_WIDTH 40
#define PREFS_COLOR_BUTTON_HEIGHT 24
GtkWidget * prefs_frame_new (const gchar *label,
GtkContainer *parent,
gboolean expand);
GtkWidget * prefs_grid_new (GtkContainer *parent);
GtkWidget * prefs_hint_box_new (const gchar *icon_name,
const gchar *text);
GtkWidget * prefs_button_add (const gchar *icon_name,
const gchar *label,
GtkBox *box);
GtkWidget * prefs_switch_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkBox *vbox,
GtkSizeGroup *group);
GtkWidget * prefs_check_button_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkBox *box);
GtkWidget * prefs_check_button_add_with_icon (GObject *config,
const gchar *property_name,
const gchar *label,
const gchar *icon_name,
GtkBox *box,
GtkSizeGroup *group);
GtkWidget * prefs_widget_add_aligned (GtkWidget *widget,
const gchar *text,
GtkGrid *grid,
gint grid_top,
gboolean left_align,
GtkSizeGroup *group);
GtkWidget * prefs_color_button_add (GObject *config,
const gchar *property_name,
const gchar *label,
const gchar *title,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group,
PikaContext *context);
GtkWidget * prefs_entry_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
GtkWidget * prefs_spin_button_add (GObject *config,
const gchar *property_name,
gdouble step_increment,
gdouble page_increment,
gint digits,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
GtkWidget * prefs_memsize_entry_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
GtkWidget * prefs_file_chooser_button_add (GObject *config,
const gchar *property_name,
const gchar *label,
const gchar *dialog_title,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
GtkWidget * prefs_enum_combo_box_add (GObject *config,
const gchar *property_name,
gint minimum,
gint maximum,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
GtkWidget * prefs_boolean_combo_box_add (GObject *config,
const gchar *property_name,
const gchar *true_text,
const gchar *false_text,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
#ifdef HAVE_ISO_CODES
GtkWidget * prefs_language_combo_box_add (GObject *config,
const gchar *property_name,
GtkBox *vbox);
#endif
GtkWidget * prefs_profile_combo_box_add (GObject *config,
const gchar *property_name,
GtkListStore *profile_store,
const gchar *dialog_title,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group,
GObject *profile_path_config,
const gchar *profile_path_property_name);
GtkWidget * prefs_compression_combo_box_add (GObject *config,
const gchar *property_name,
const gchar *label,
GtkGrid *grid,
gint grid_top,
GtkSizeGroup *group);
#endif /* __PREFERENCES_DIALOG_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __PREFERENCES_DIALOG_H__
#define __PREFERENCES_DIALOG_H__
GtkWidget * preferences_dialog_create (Pika *pika);
#endif /* __PREFERENCES_DIALOG_H__ */

View File

@ -0,0 +1,435 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pika-utils.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikaviewabledialog.h"
#include "print-size-dialog.h"
#include "pika-intl.h"
#define RESPONSE_RESET 1
#define SB_WIDTH 8
typedef struct _PrintSizeDialog PrintSizeDialog;
struct _PrintSizeDialog
{
PikaImage *image;
PikaSizeEntry *size_entry;
PikaSizeEntry *resolution_entry;
PikaChainButton *chain;
gdouble xres;
gdouble yres;
PikaResolutionCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void print_size_dialog_free (PrintSizeDialog *private);
static void print_size_dialog_response (GtkWidget *dialog,
gint response_id,
PrintSizeDialog *private);
static void print_size_dialog_reset (PrintSizeDialog *private);
static void print_size_dialog_size_changed (GtkWidget *widget,
PrintSizeDialog *private);
static void print_size_dialog_resolution_changed (GtkWidget *widget,
PrintSizeDialog *private);
static void print_size_dialog_set_size (PrintSizeDialog *private,
gdouble width,
gdouble height);
static void print_size_dialog_set_resolution (PrintSizeDialog *private,
gdouble xres,
gdouble yres);
/* public functions */
GtkWidget *
print_size_dialog_new (PikaImage *image,
PikaContext *context,
const gchar *title,
const gchar *role,
GtkWidget *parent,
PikaHelpFunc help_func,
const gchar *help_id,
PikaResolutionCallback callback,
gpointer user_data)
{
PrintSizeDialog *private;
GtkWidget *dialog;
GtkWidget *frame;
GtkWidget *grid;
GtkWidget *entry;
GtkWidget *label;
GtkWidget *width;
GtkWidget *height;
GtkWidget *hbox;
GtkWidget *chain;
GtkAdjustment *adj;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (PrintSizeDialog);
private->image = image;
private->callback = callback;
private->user_data = user_data;
pika_image_get_resolution (image, &private->xres, &private->yres);
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, image), context,
title, role,
PIKA_ICON_DOCUMENT_PRINT_RESOLUTION, title,
parent,
help_func, help_id,
_("_Reset"), RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) print_size_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (print_size_dialog_response),
private);
frame = pika_frame_new (_("Print Size"));
gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
gtk_container_add (GTK_CONTAINER (frame), grid);
gtk_widget_show (grid);
/* the print size entry */
adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
width = pika_spin_button_new (adj, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (width), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (width), SB_WIDTH);
adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
height = pika_spin_button_new (adj, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (height), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (height), SB_WIDTH);
entry = pika_size_entry_new (0, pika_get_default_unit (), "%p",
FALSE, FALSE, FALSE, SB_WIDTH,
PIKA_SIZE_ENTRY_UPDATE_SIZE);
private->size_entry = PIKA_SIZE_ENTRY (entry);
label = gtk_label_new_with_mnemonic (_("_Width:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), width);
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
gtk_widget_show (label);
label = gtk_label_new_with_mnemonic (_("H_eight:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), height);
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
gtk_widget_show (label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_grid_attach (GTK_GRID (grid), hbox, 1, 0, 1, 2);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (height), NULL);
gtk_grid_attach (GTK_GRID (entry), height, 0, 1, 1, 1);
gtk_widget_show (height);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (width), NULL);
gtk_grid_attach (GTK_GRID (entry), width, 0, 0, 1, 1);
gtk_widget_show (width);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0,
private->xres, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 1,
private->yres, FALSE);
pika_size_entry_set_refval_boundaries
(PIKA_SIZE_ENTRY (entry), 0, PIKA_MIN_IMAGE_SIZE, PIKA_MAX_IMAGE_SIZE);
pika_size_entry_set_refval_boundaries
(PIKA_SIZE_ENTRY (entry), 1, PIKA_MIN_IMAGE_SIZE, PIKA_MAX_IMAGE_SIZE);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 0,
pika_image_get_width (image));
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 1,
pika_image_get_height (image));
/* the resolution entry */
adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
width = pika_spin_button_new (adj, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (width), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (width), SB_WIDTH);
adj = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
height = pika_spin_button_new (adj, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (height), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (height), SB_WIDTH);
label = gtk_label_new_with_mnemonic (_("_X resolution:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), width);
gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
gtk_widget_show (label);
label = gtk_label_new_with_mnemonic (_("_Y resolution:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), height);
gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
gtk_widget_show (label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_grid_attach (GTK_GRID (grid), hbox, 1, 2, 1, 2);
gtk_widget_show (hbox);
entry = pika_size_entry_new (0, pika_image_get_unit (image), _("pixels/%a"),
FALSE, FALSE, FALSE, SB_WIDTH,
PIKA_SIZE_ENTRY_UPDATE_RESOLUTION);
private->resolution_entry = PIKA_SIZE_ENTRY (entry);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (height), NULL);
gtk_grid_attach (GTK_GRID (entry), height, 0, 1, 1, 1);
gtk_widget_show (height);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (width), NULL);
gtk_grid_attach (GTK_GRID (entry), width, 0, 0, 1, 1);
gtk_widget_show (width);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (entry), 0,
PIKA_MIN_RESOLUTION,
PIKA_MAX_RESOLUTION);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (entry), 1,
PIKA_MIN_RESOLUTION,
PIKA_MAX_RESOLUTION);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 0, private->xres);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 1, private->yres);
chain = pika_chain_button_new (PIKA_CHAIN_RIGHT);
if (ABS (private->xres - private->yres) < PIKA_MIN_RESOLUTION)
pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain), TRUE);
gtk_grid_attach (GTK_GRID (entry), chain, 1, 0, 1, 2);
gtk_widget_show (chain);
private->chain = PIKA_CHAIN_BUTTON (chain);
g_signal_connect (private->size_entry, "value-changed",
G_CALLBACK (print_size_dialog_size_changed),
private);
g_signal_connect (private->resolution_entry, "value-changed",
G_CALLBACK (print_size_dialog_resolution_changed),
private);
return dialog;
}
/* private functions */
static void
print_size_dialog_free (PrintSizeDialog *private)
{
g_slice_free (PrintSizeDialog, private);
}
static void
print_size_dialog_response (GtkWidget *dialog,
gint response_id,
PrintSizeDialog *private)
{
PikaSizeEntry *entry = private->resolution_entry;
switch (response_id)
{
case RESPONSE_RESET:
print_size_dialog_reset (private);
break;
case GTK_RESPONSE_OK:
private->callback (dialog,
private->image,
pika_size_entry_get_refval (entry, 0),
pika_size_entry_get_refval (entry, 1),
pika_size_entry_get_unit (entry),
private->user_data);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}
static void
print_size_dialog_reset (PrintSizeDialog *private)
{
gdouble xres, yres;
pika_size_entry_set_unit (private->resolution_entry,
pika_get_default_unit ());
pika_image_get_resolution (private->image, &xres, &yres);
print_size_dialog_set_resolution (private, xres, yres);
}
static void
print_size_dialog_size_changed (GtkWidget *widget,
PrintSizeDialog *private)
{
PikaImage *image = private->image;
gdouble width;
gdouble height;
gdouble xres;
gdouble yres;
gdouble scale;
scale = pika_unit_get_factor (pika_size_entry_get_unit (private->size_entry));
width = pika_size_entry_get_value (private->size_entry, 0);
height = pika_size_entry_get_value (private->size_entry, 1);
xres = scale * pika_image_get_width (image) / MAX (0.001, width);
yres = scale * pika_image_get_height (image) / MAX (0.001, height);
xres = CLAMP (xres, PIKA_MIN_RESOLUTION, PIKA_MAX_RESOLUTION);
yres = CLAMP (yres, PIKA_MIN_RESOLUTION, PIKA_MAX_RESOLUTION);
print_size_dialog_set_resolution (private, xres, yres);
print_size_dialog_set_size (private,
pika_image_get_width (image),
pika_image_get_height (image));
}
static void
print_size_dialog_resolution_changed (GtkWidget *widget,
PrintSizeDialog *private)
{
PikaSizeEntry *entry = private->resolution_entry;
gdouble xres = pika_size_entry_get_refval (entry, 0);
gdouble yres = pika_size_entry_get_refval (entry, 1);
print_size_dialog_set_resolution (private, xres, yres);
}
static void
print_size_dialog_set_size (PrintSizeDialog *private,
gdouble width,
gdouble height)
{
g_signal_handlers_block_by_func (private->size_entry,
print_size_dialog_size_changed,
private);
pika_size_entry_set_refval (private->size_entry, 0, width);
pika_size_entry_set_refval (private->size_entry, 1, height);
g_signal_handlers_unblock_by_func (private->size_entry,
print_size_dialog_size_changed,
private);
}
static void
print_size_dialog_set_resolution (PrintSizeDialog *private,
gdouble xres,
gdouble yres)
{
if (private->chain && pika_chain_button_get_active (private->chain))
{
if (xres != private->xres)
yres = xres;
else
xres = yres;
}
private->xres = xres;
private->yres = yres;
g_signal_handlers_block_by_func (private->resolution_entry,
print_size_dialog_resolution_changed,
private);
pika_size_entry_set_refval (private->resolution_entry, 0, xres);
pika_size_entry_set_refval (private->resolution_entry, 1, yres);
g_signal_handlers_unblock_by_func (private->resolution_entry,
print_size_dialog_resolution_changed,
private);
g_signal_handlers_block_by_func (private->size_entry,
print_size_dialog_size_changed,
private);
pika_size_entry_set_resolution (private->size_entry, 0, xres, TRUE);
pika_size_entry_set_resolution (private->size_entry, 1, yres, TRUE);
g_signal_handlers_unblock_by_func (private->size_entry,
print_size_dialog_size_changed,
private);
}

View File

@ -0,0 +1,45 @@
/* 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/>.
*/
#ifndef __PRINT_SIZE_DIALOG_H__
#define __PRINT_SIZE_DIALOG_H__
typedef void (* PikaResolutionCallback) (GtkWidget *dialog,
PikaImage *image,
gdouble xresolution,
gdouble yresolution,
PikaUnit resolution_unit,
gpointer user_data);
GtkWidget * print_size_dialog_new (PikaImage *image,
PikaContext *context,
const gchar *title,
const gchar *role,
GtkWidget *parent,
PikaHelpFunc help_func,
const gchar *help_id,
PikaResolutionCallback callback,
gpointer user_data);
#endif /* __PRINT_SIZE_DIALOG_H__ */

627
app/dialogs/quit-dialog.c Normal file
View File

@ -0,0 +1,627 @@
/* 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
*
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "display/pikadisplay.h"
#include "display/pikadisplay-foreach.h"
#include "display/pikadisplayshell.h"
#include "display/pikaimagewindow.h"
#include "widgets/pikaaction.h"
#include "widgets/pikacellrendererbutton.h"
#include "widgets/pikacontainertreestore.h"
#include "widgets/pikacontainertreeview.h"
#include "widgets/pikacontainerview.h"
#include "widgets/pikadnd.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "widgets/pikaviewrenderer.h"
#include "widgets/pikawidgets-utils.h"
#include "quit-dialog.h"
#include "pika-intl.h"
typedef struct _QuitDialog QuitDialog;
struct _QuitDialog
{
Pika *pika;
PikaContainer *images;
PikaContext *context;
gboolean do_quit;
GtkWidget *dialog;
PikaContainerTreeView *tree_view;
GtkTreeViewColumn *save_column;
GtkWidget *ok_button;
PikaMessageBox *box;
GtkWidget *lost_label;
GtkWidget *hint_label;
guint accel_key;
GdkModifierType accel_mods;
};
static GtkWidget * quit_close_all_dialog_new (Pika *pika,
gboolean do_quit);
static void quit_close_all_dialog_free (QuitDialog *private);
static void quit_close_all_dialog_response (GtkWidget *dialog,
gint response_id,
QuitDialog *private);
static void quit_close_all_dialog_accel_marshal (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
static void quit_close_all_dialog_container_changed (PikaContainer *images,
PikaObject *image,
QuitDialog *private);
static gboolean quit_close_all_dialog_images_selected (PikaContainerView *view,
GList *images,
GList *paths,
QuitDialog *private);
static void quit_close_all_dialog_name_cell_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data);
static void quit_close_all_dialog_save_clicked (GtkCellRenderer *cell,
const gchar *path,
GdkModifierType state,
QuitDialog *private);
static gboolean quit_close_all_dialog_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
QuitDialog *private);
static gboolean quit_close_all_idle (QuitDialog *private);
/* public functions */
GtkWidget *
quit_dialog_new (Pika *pika)
{
return quit_close_all_dialog_new (pika, TRUE);
}
GtkWidget *
close_all_dialog_new (Pika *pika)
{
return quit_close_all_dialog_new (pika, FALSE);
}
/* private functions */
static GtkWidget *
quit_close_all_dialog_new (Pika *pika,
gboolean do_quit)
{
QuitDialog *private;
GtkWidget *view;
PikaContainerTreeView *tree_view;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkWidget *dnd_widget;
GtkAccelGroup *accel_group;
GClosure *closure;
gint rows;
gint view_size;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
private = g_slice_new0 (QuitDialog);
private->pika = pika;
private->do_quit = do_quit;
private->images = pika_displays_get_dirty_images (pika);
private->context = pika_context_new (pika, "close-all-dialog",
pika_get_user_context (pika));
g_return_val_if_fail (private->images != NULL, NULL);
private->dialog =
pika_message_dialog_new (do_quit ? _("Quit PIKA") : _("Close All Images"),
PIKA_ICON_DIALOG_WARNING,
NULL, 0,
pika_standard_help_func,
do_quit ?
PIKA_HELP_FILE_QUIT : PIKA_HELP_FILE_CLOSE_ALL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
NULL);
private->ok_button = gtk_dialog_add_button (GTK_DIALOG (private->dialog),
"", GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (private->dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_object_weak_ref (G_OBJECT (private->dialog),
(GWeakNotify) quit_close_all_dialog_free, private);
g_signal_connect (private->dialog, "response",
G_CALLBACK (quit_close_all_dialog_response),
private);
/* connect <Primary>D to the quit/close button */
accel_group = gtk_accel_group_new ();
gtk_window_add_accel_group (GTK_WINDOW (private->dialog), accel_group);
g_object_unref (accel_group);
closure = g_closure_new_object (sizeof (GClosure), G_OBJECT (private->dialog));
g_closure_set_marshal (closure, quit_close_all_dialog_accel_marshal);
gtk_accelerator_parse ("<Primary>D",
&private->accel_key, &private->accel_mods);
gtk_accel_group_connect (accel_group,
private->accel_key, private->accel_mods,
0, closure);
private->box = PIKA_MESSAGE_DIALOG (private->dialog)->box;
view_size = pika->config->layer_preview_size;
rows = CLAMP (pika_container_get_n_children (private->images), 3, 6);
view = pika_container_tree_view_new (private->images, private->context,
view_size, 1);
pika_container_box_set_size_request (PIKA_CONTAINER_BOX (view),
-1,
rows * (view_size + 2));
private->tree_view = tree_view = PIKA_CONTAINER_TREE_VIEW (view);
gtk_tree_view_column_set_expand (tree_view->main_column, TRUE);
renderer = pika_container_tree_view_get_name_cell (tree_view);
gtk_tree_view_column_set_cell_data_func (tree_view->main_column,
renderer,
quit_close_all_dialog_name_cell_func,
NULL, NULL);
private->save_column = column = gtk_tree_view_column_new ();
renderer = pika_cell_renderer_button_new ();
g_object_set (renderer,
"icon-name", "document-save",
NULL);
gtk_tree_view_column_pack_end (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer, NULL);
gtk_tree_view_append_column (tree_view->view, column);
pika_container_tree_view_add_toggle_cell (tree_view, renderer);
g_signal_connect (renderer, "clicked",
G_CALLBACK (quit_close_all_dialog_save_clicked),
private);
gtk_box_pack_start (GTK_BOX (private->box), view, TRUE, TRUE, 0);
gtk_widget_show (view);
g_signal_connect (view, "select-items",
G_CALLBACK (quit_close_all_dialog_images_selected),
private);
dnd_widget = pika_container_view_get_dnd_widget (PIKA_CONTAINER_VIEW (view));
pika_dnd_xds_source_add (dnd_widget,
(PikaDndDragViewableFunc) pika_dnd_get_drag_viewable,
NULL);
g_signal_connect (tree_view->view, "query-tooltip",
G_CALLBACK (quit_close_all_dialog_query_tooltip),
private);
if (do_quit)
private->lost_label = gtk_label_new (_("If you quit PIKA now, "
"these changes will be lost."));
else
private->lost_label = gtk_label_new (_("If you close these images now, "
"changes will be lost."));
gtk_label_set_xalign (GTK_LABEL (private->lost_label), 0.0);
gtk_label_set_line_wrap (GTK_LABEL (private->lost_label), TRUE);
gtk_box_pack_start (GTK_BOX (private->box), private->lost_label,
FALSE, FALSE, 0);
gtk_widget_show (private->lost_label);
private->hint_label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (private->hint_label), 0.0);
gtk_label_set_line_wrap (GTK_LABEL (private->hint_label), TRUE);
gtk_box_pack_start (GTK_BOX (private->box), private->hint_label,
FALSE, FALSE, 0);
gtk_widget_show (private->hint_label);
closure = g_cclosure_new (G_CALLBACK (quit_close_all_dialog_container_changed),
private, NULL);
g_object_watch_closure (G_OBJECT (private->dialog), closure);
g_signal_connect_closure (private->images, "add", closure, FALSE);
g_signal_connect_closure (private->images, "remove", closure, FALSE);
quit_close_all_dialog_container_changed (private->images, NULL,
private);
return private->dialog;
}
static void
quit_close_all_dialog_free (QuitDialog *private)
{
g_idle_remove_by_data (private);
g_object_unref (private->images);
g_object_unref (private->context);
g_slice_free (QuitDialog, private);
}
static void
quit_close_all_dialog_response (GtkWidget *dialog,
gint response_id,
QuitDialog *private)
{
Pika *pika = private->pika;
gboolean do_quit = private->do_quit;
gtk_widget_destroy (dialog);
if (response_id == GTK_RESPONSE_OK)
{
if (do_quit)
pika_exit (pika, TRUE);
else
pika_displays_close (pika);
}
}
static void
quit_close_all_dialog_accel_marshal (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
gtk_dialog_response (GTK_DIALOG (closure->data), GTK_RESPONSE_OK);
/* we handled the accelerator */
g_value_set_boolean (return_value, TRUE);
}
static void
quit_close_all_dialog_container_changed (PikaContainer *images,
PikaObject *image,
QuitDialog *private)
{
gint num_images = pika_container_get_n_children (images);
gchar *accel_string;
gchar *hint;
gchar *markup;
accel_string = gtk_accelerator_get_label (private->accel_key,
private->accel_mods);
pika_message_box_set_primary_text (private->box,
/* TRANSLATORS: unless your language
msgstr[0] applies to 1 only (as
in English), replace "one" with %d. */
ngettext ("There is one image with "
"unsaved changes:",
"There are %d images with "
"unsaved changes:",
num_images), num_images);
if (num_images == 0)
{
gtk_widget_hide (private->lost_label);
if (private->do_quit)
hint = g_strdup_printf (_("Press %s to quit."),
accel_string);
else
hint = g_strdup_printf (_("Press %s to close all images."),
accel_string);
g_object_set (private->ok_button,
"label", private->do_quit ? _("_Quit") : _("Cl_ose"),
"use-stock", TRUE,
"image", NULL,
NULL);
gtk_widget_grab_default (private->ok_button);
/* When no image requires saving anymore, there is no harm in
* assuming completing the original quit or close-all action is
* the expected end-result.
* I don't immediately exit though because of some unfinished
* actions provoking warnings. Let's just close as soon as
* possible with an idle source.
* Also the idle source has another benefit: allowing to change
* one's mind and not exit after the last save, for instance by
* hitting Esc quickly while the last save is in progress.
*/
g_idle_add ((GSourceFunc) quit_close_all_idle, private);
}
else
{
GtkWidget *icon;
if (private->do_quit)
hint = g_strdup_printf (_("Press %s to discard all changes and quit."),
accel_string);
else
hint = g_strdup_printf (_("Press %s to discard all changes and close all images."),
accel_string);
gtk_widget_show (private->lost_label);
icon = gtk_image_new_from_icon_name (PIKA_ICON_EDIT_DELETE,
GTK_ICON_SIZE_BUTTON);
g_object_set (private->ok_button,
"label", _("_Discard Changes"),
"use-stock", FALSE,
"image", icon,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (private->dialog),
GTK_RESPONSE_CANCEL);
}
markup = g_strdup_printf ("<i><small>%s</small></i>", hint);
gtk_label_set_markup (GTK_LABEL (private->hint_label), markup);
g_free (markup);
g_free (hint);
g_free (accel_string);
}
static gboolean
quit_close_all_dialog_images_selected (PikaContainerView *view,
GList *images,
GList *paths,
QuitDialog *private)
{
/* The signal allows for multiple selection cases, but this specific
* dialog only allows one image selected at a time.
*/
g_return_val_if_fail (g_list_length (images) <= 1, FALSE);
if (images)
{
PikaImage *image = images->data;
GList *list;
for (list = pika_get_display_iter (private->pika);
list;
list = g_list_next (list))
{
PikaDisplay *display = list->data;
if (pika_display_get_image (display) == image)
{
pika_display_shell_present (pika_display_get_shell (display));
/* We only want to update the active shell. Give back keyboard
* focus to the quit dialog after this.
*/
gtk_window_present (GTK_WINDOW (private->dialog));
}
}
}
return TRUE;
}
static void
quit_close_all_dialog_name_cell_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
PikaViewRenderer *renderer;
PikaImage *image;
gchar *name;
gtk_tree_model_get (tree_model, iter,
PIKA_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
PIKA_CONTAINER_TREE_STORE_COLUMN_NAME, &name,
-1);
image = PIKA_IMAGE (renderer->viewable);
if (pika_image_is_export_dirty (image))
{
g_object_set (cell,
"markup", NULL,
"text", name,
NULL);
}
else
{
GFile *file;
const gchar *filename;
gchar *escaped_name;
gchar *escaped_filename;
gchar *exported;
gchar *markup;
file = pika_image_get_exported_file (image);
if (! file)
file = pika_image_get_imported_file (image);
filename = pika_file_get_utf8_name (file);
escaped_name = g_markup_escape_text (name, -1);
escaped_filename = g_markup_escape_text (filename, -1);
exported = g_strdup_printf (_("Exported to %s"), escaped_filename);
markup = g_strdup_printf ("%s\n<i>%s</i>", escaped_name, exported);
g_free (exported);
g_free (escaped_name);
g_free (escaped_filename);
g_object_set (cell,
"text", NULL,
"markup", markup,
NULL);
g_free (markup);
}
g_object_unref (renderer);
g_free (name);
}
static void
quit_close_all_dialog_save_clicked (GtkCellRenderer *cell,
const gchar *path_str,
GdkModifierType state,
QuitDialog *private)
{
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
GtkTreeIter iter;
if (gtk_tree_model_get_iter (private->tree_view->model, &iter, path))
{
PikaViewRenderer *renderer;
PikaImage *image;
GList *list;
gtk_tree_model_get (private->tree_view->model, &iter,
PIKA_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
-1);
image = PIKA_IMAGE (renderer->viewable);
g_object_unref (renderer);
for (list = pika_get_display_iter (private->pika);
list;
list = g_list_next (list))
{
PikaDisplay *display = list->data;
if (pika_display_get_image (display) == image)
{
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImageWindow *window = pika_display_shell_get_window (shell);
if (window)
{
GAction *action;
pika_display_shell_present (shell);
/* Make sure the quit dialog kept keyboard focus when
* the save dialog will exit. */
gtk_window_present (GTK_WINDOW (private->dialog));
if (state & GDK_SHIFT_MASK)
action = g_action_map_lookup_action (G_ACTION_MAP (private->pika->app),
"file-save-as");
else
action = g_action_map_lookup_action (G_ACTION_MAP (private->pika->app),
"file-save");
g_return_if_fail (PIKA_IS_ACTION (action));
pika_action_activate (PIKA_ACTION (action));
}
break;
}
}
}
gtk_tree_path_free (path);
}
static gboolean
quit_close_all_dialog_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
QuitDialog *private)
{
GtkTreePath *path;
gboolean show_tip = FALSE;
if (gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y,
keyboard_tip,
NULL, &path, NULL))
{
GtkTreeViewColumn *column = NULL;
gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y,
NULL, &column, NULL, NULL);
if (column == private->save_column)
{
gchar *tip = g_strconcat (_("Save this image"), "\n<b>",
pika_get_mod_string (GDK_SHIFT_MASK),
"</b> ", _("Save as"),
NULL);
gtk_tooltip_set_markup (tooltip, tip);
gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (widget), tooltip, path);
g_free (tip);
show_tip = TRUE;
}
gtk_tree_path_free (path);
}
return show_tip;
}
static gboolean
quit_close_all_idle (QuitDialog *private)
{
gtk_dialog_response (GTK_DIALOG (private->dialog), GTK_RESPONSE_OK);
return FALSE;
}

32
app/dialogs/quit-dialog.h Normal file
View File

@ -0,0 +1,32 @@
/* 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
*
* Copyright (C) 2004 Sven Neumann
*
* 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/>.
*/
#ifndef __QUIT_DIALOG_H__
#define __QUIT_DIALOG_H__
GtkWidget * quit_dialog_new (Pika *pika);
GtkWidget * close_all_dialog_new (Pika *pika);
#endif /* __QUIT_DIALOG_H__ */

851
app/dialogs/resize-dialog.c Normal file
View File

@ -0,0 +1,851 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikatemplate.h"
#include "widgets/pikacontainercombobox.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikasizebox.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikawidgets-constructors.h"
#include "resize-dialog.h"
#include "pika-intl.h"
#define RESPONSE_RESET 1
#define SB_WIDTH 8
typedef struct _ResizeDialog ResizeDialog;
struct _ResizeDialog
{
PikaViewable *viewable;
PikaContext *context;
PikaContext *parent_context;
PikaFillType fill_type;
PikaItemSet layer_set;
gboolean resize_text_layers;
PikaResizeCallback callback;
gpointer user_data;
gdouble old_xres;
gdouble old_yres;
PikaUnit old_res_unit;
gint old_width;
gint old_height;
PikaUnit old_unit;
PikaFillType old_fill_type;
PikaItemSet old_layer_set;
gboolean old_resize_text_layers;
GtkWidget *box;
GtkWidget *offset;
GtkWidget *area;
GtkWidget *layer_set_combo;
GtkWidget *fill_type_combo;
GtkWidget *text_layers_button;
GtkWidget *ppi_box;
GtkWidget *ppi_image;
GtkWidget *ppi_template;
PikaTemplate *template;
};
/* local function prototypes */
static void resize_dialog_free (ResizeDialog *private);
static void resize_dialog_response (GtkWidget *dialog,
gint response_id,
ResizeDialog *private);
static void resize_dialog_reset (ResizeDialog *private);
static void size_notify (PikaSizeBox *box,
GParamSpec *pspec,
ResizeDialog *private);
static void offset_update (GtkWidget *widget,
ResizeDialog *private);
static void offsets_changed (GtkWidget *area,
gint off_x,
gint off_y,
ResizeDialog *private);
static void offset_center_clicked (GtkWidget *widget,
ResizeDialog *private);
static void template_changed (PikaContext *context,
PikaTemplate *template,
ResizeDialog *private);
static void reset_template_clicked (GtkWidget *button,
ResizeDialog *private);
static void ppi_select_toggled (GtkWidget *radio,
ResizeDialog *private);
/* public function */
GtkWidget *
resize_dialog_new (PikaViewable *viewable,
PikaContext *context,
const gchar *title,
const gchar *role,
GtkWidget *parent,
PikaHelpFunc help_func,
const gchar *help_id,
PikaUnit unit,
PikaFillType fill_type,
PikaItemSet layer_set,
gboolean resize_text_layers,
PikaResizeCallback callback,
gpointer user_data)
{
ResizeDialog *private;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *vbox;
GtkWidget *center_hbox;
GtkWidget *center_left_vbox;
GtkWidget *center_right_vbox;
GtkWidget *frame;
GtkWidget *button;
GtkWidget *spinbutton;
GtkWidget *entry;
GtkWidget *hbox;
GtkWidget *combo;
GtkWidget *label;
GtkWidget *template_selector;
GtkWidget *ppi_image;
GtkWidget *ppi_template;
GtkAdjustment *adjustment;
GdkPixbuf *pixbuf;
GtkSizeGroup *size_group = NULL;
PikaImage *image = NULL;
const gchar *size_title = NULL;
const gchar *layers_title = NULL;
gint width, height;
gdouble xres, yres;
g_return_val_if_fail (PIKA_IS_VIEWABLE (viewable), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (callback != NULL, NULL);
if (PIKA_IS_IMAGE (viewable))
{
image = PIKA_IMAGE (viewable);
width = pika_image_get_width (image);
height = pika_image_get_height (image);
size_title = _("Canvas Size");
layers_title = _("Layers");
}
else if (PIKA_IS_ITEM (viewable))
{
PikaItem *item = PIKA_ITEM (viewable);
image = pika_item_get_image (item);
width = pika_item_get_width (item);
height = pika_item_get_height (item);
size_title = _("Layer Size");
layers_title = _("Fill With");
}
else
{
g_return_val_if_reached (NULL);
}
private = g_slice_new0 (ResizeDialog);
private->parent_context = context;
private->context = pika_context_new (context->pika,
"resize-dialog",
context);
pika_image_get_resolution (image, &xres, &yres);
private->old_xres = xres;
private->old_yres = yres;
private->old_res_unit = pika_image_get_unit (image);
private->viewable = viewable;
private->fill_type = fill_type;
private->layer_set = layer_set;
private->resize_text_layers = resize_text_layers;
private->callback = callback;
private->user_data = user_data;
private->old_width = width;
private->old_height = height;
private->old_unit = unit;
private->old_fill_type = private->fill_type;
private->old_layer_set = private->layer_set;
private->old_resize_text_layers = private->resize_text_layers;
pika_context_set_template (private->context, NULL);
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, viewable), context,
title, role, PIKA_ICON_OBJECT_RESIZE, title,
parent,
help_func, help_id,
_("Re_set"), RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Resize"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) resize_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (resize_dialog_response),
private);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
/* template selector */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Template:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
template_selector = g_object_new (PIKA_TYPE_CONTAINER_COMBO_BOX,
"container", context->pika->templates,
"context", private->context,
"view-size", 16,
"view-border-width", 0,
"ellipsize", PANGO_ELLIPSIZE_NONE,
"focus-on-click", FALSE,
NULL);
gtk_box_pack_start (GTK_BOX (hbox), template_selector, TRUE, TRUE, 0);
gtk_widget_show (template_selector);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), template_selector);
g_signal_connect (private->context,
"template-changed",
G_CALLBACK (template_changed),
private);
/* reset template button */
button = pika_icon_button_new (PIKA_ICON_RESET, NULL);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_image_set_from_icon_name (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (button))),
PIKA_ICON_RESET, GTK_ICON_SIZE_MENU);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button,
"clicked",
G_CALLBACK (reset_template_clicked),
private);
pika_help_set_help_data (button,
_("Reset the template selection"),
NULL);
/* ppi selector box */
private->ppi_box = vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
label = gtk_label_new (_("Template and image print resolution don't match.\n"
"Choose how to scale the canvas:"));
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
gtk_widget_show (hbox);
/* actual label text is set inside template_change fn. */
ppi_image = gtk_radio_button_new_with_label (NULL, "");
ppi_template = gtk_radio_button_new_with_label (NULL, "");
private->ppi_image = ppi_image;
private->ppi_template = ppi_template;
gtk_radio_button_join_group (GTK_RADIO_BUTTON (ppi_template),
GTK_RADIO_BUTTON (ppi_image));
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (ppi_image), FALSE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (ppi_template), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), ppi_image, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), ppi_template, FALSE, FALSE, 0);
gtk_widget_show (ppi_image);
gtk_widget_show (ppi_template);
g_signal_connect (G_OBJECT (ppi_image),
"toggled",
G_CALLBACK (ppi_select_toggled),
private);
g_signal_connect (G_OBJECT (ppi_template),
"toggled",
G_CALLBACK (ppi_select_toggled),
private);
/* For space gain, organize the main widgets in both vertical and
* horizontal layout.
* The size and offset fields are on the center left, while the
* preview and the "Center" button are on center right.
*/
center_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (main_vbox), center_hbox, FALSE, FALSE, 0);
gtk_widget_show (center_hbox);
center_left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
gtk_box_pack_start (GTK_BOX (center_hbox), center_left_vbox, FALSE, FALSE, 0);
gtk_widget_show (center_left_vbox);
center_right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_box_pack_start (GTK_BOX (center_hbox), center_right_vbox, FALSE, FALSE, 0);
gtk_widget_show (center_right_vbox);
/* size select frame */
frame = pika_frame_new (size_title);
gtk_box_pack_start (GTK_BOX (center_left_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* size box */
private->box = g_object_new (PIKA_TYPE_SIZE_BOX,
"width", width,
"height", height,
"unit", unit,
"xresolution", xres,
"yresolution", yres,
"keep-aspect", FALSE,
"edit-resolution", FALSE,
NULL);
gtk_container_add (GTK_CONTAINER (frame), private->box);
gtk_widget_show (private->box);
/* offset frame */
frame = pika_frame_new (_("Offset"));
gtk_box_pack_start (GTK_BOX (center_left_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
/* the offset sizeentry */
adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 0);
spinbutton = pika_spin_button_new (adjustment, 1.0, 2);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), SB_WIDTH);
private->offset = entry = pika_size_entry_new (1, unit, "%p",
TRUE, FALSE, FALSE, SB_WIDTH,
PIKA_SIZE_ENTRY_UPDATE_SIZE);
pika_size_entry_add_field (PIKA_SIZE_ENTRY (entry),
GTK_SPIN_BUTTON (spinbutton), NULL);
gtk_grid_attach (GTK_GRID (entry), spinbutton, 1, 0, 1, 1);
gtk_widget_show (spinbutton);
pika_size_entry_attach_label (PIKA_SIZE_ENTRY (entry),
_("_X:"), 0, 0, 0.0);
pika_size_entry_attach_label (PIKA_SIZE_ENTRY (entry),_("_Y:"), 1, 0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 0, xres, FALSE);
pika_size_entry_set_resolution (PIKA_SIZE_ENTRY (entry), 1, yres, FALSE);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (entry), 0, 0, 0);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (entry), 1, 0, 0);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 0, 0);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (entry), 1, 0);
g_signal_connect (entry, "value-changed",
G_CALLBACK (offset_update),
private);
frame = gtk_frame_new (NULL);
gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (center_right_vbox), frame, FALSE, FALSE, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (frame),
"pika-offset-area-frame");
gtk_widget_show (frame);
private->area = pika_offset_area_new (width, height);
gtk_container_add (GTK_CONTAINER (frame), private->area);
gtk_widget_show (private->area);
pika_viewable_get_preview_size (viewable, 200, TRUE, TRUE, &width, &height);
pixbuf = pika_viewable_get_pixbuf (viewable, context,
width, height);
if (pixbuf)
pika_offset_area_set_pixbuf (PIKA_OFFSET_AREA (private->area), pixbuf);
g_signal_connect (private->area, "offsets-changed",
G_CALLBACK (offsets_changed),
private);
g_signal_connect (private->box, "notify",
G_CALLBACK (size_notify),
private);
/* Button to center the image on canvas just below the preview. */
button = gtk_button_new_with_mnemonic (_("C_enter"));
gtk_box_pack_start (GTK_BOX (center_right_vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "clicked",
G_CALLBACK (offset_center_clicked),
private);
frame = pika_frame_new (layers_title);
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
if (PIKA_IS_IMAGE (viewable))
{
GtkWidget *label;
size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("Resize _layers:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
gtk_size_group_add_widget (size_group, label);
private->layer_set_combo = combo =
pika_enum_combo_box_new (PIKA_TYPE_ITEM_SET);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->layer_set,
G_CALLBACK (pika_int_combo_box_get_active),
&private->layer_set, NULL);
}
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
private->fill_type_combo = combo =
pika_enum_combo_box_new (PIKA_TYPE_FILL_TYPE);
gtk_box_pack_end (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
private->fill_type,
G_CALLBACK (pika_int_combo_box_get_active),
&private->fill_type, NULL);
if (PIKA_IS_IMAGE (viewable))
{
GtkWidget *label;
label = gtk_label_new_with_mnemonic (_("_Fill with:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
gtk_size_group_add_widget (size_group, label);
private->text_layers_button = button =
gtk_check_button_new_with_mnemonic (_("Resize _text layers"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->resize_text_layers);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->resize_text_layers);
pika_help_set_help_data (button,
_("Resizing text layers will make them uneditable"),
NULL);
g_object_unref (size_group);
}
return dialog;
}
/* private functions */
static void
resize_dialog_free (ResizeDialog *private)
{
g_object_unref (private->context);
g_slice_free (ResizeDialog, private);
}
static void
resize_dialog_response (GtkWidget *dialog,
gint response_id,
ResizeDialog *private)
{
PikaSizeEntry *entry = PIKA_SIZE_ENTRY (private->offset);
PikaUnit unit;
gint width;
gint height;
gdouble xres;
gdouble yres;
PikaUnit res_unit;
switch (response_id)
{
case RESPONSE_RESET:
resize_dialog_reset (private);
break;
case GTK_RESPONSE_OK:
g_object_get (private->box,
"width", &width,
"height", &height,
"unit", &unit,
"xresolution", &xres,
"yresolution", &yres,
"resolution-unit", &res_unit,
NULL);
private->callback (dialog,
private->viewable,
private->parent_context,
width,
height,
unit,
pika_size_entry_get_refval (entry, 0),
pika_size_entry_get_refval (entry, 1),
xres,
yres,
res_unit,
private->fill_type,
private->layer_set,
private->resize_text_layers,
private->user_data);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}
static void
resize_dialog_reset (ResizeDialog *private)
{
g_object_set (private->box,
"keep-aspect", FALSE,
NULL);
g_object_set (private->box,
"width", private->old_width,
"height", private->old_height,
"unit", private->old_unit,
"xresolution", private->old_xres,
"yresolution", private->old_yres,
"resolution-unit", private->old_res_unit,
NULL);
if (private->layer_set_combo)
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->layer_set_combo),
private->old_layer_set);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->fill_type_combo),
private->old_fill_type);
if (private->text_layers_button)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->text_layers_button),
private->old_resize_text_layers);
pika_context_set_template (private->context, NULL);
pika_size_entry_set_unit (PIKA_SIZE_ENTRY (private->offset),
private->old_unit);
}
static void
size_notify (PikaSizeBox *box,
GParamSpec *pspec,
ResizeDialog *private)
{
gint diff_x = box->width - private->old_width;
gint diff_y = box->height - private->old_height;
pika_offset_area_set_size (PIKA_OFFSET_AREA (private->area),
box->width, box->height);
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (private->offset), 0,
MIN (0, diff_x), MAX (0, diff_x));
pika_size_entry_set_refval_boundaries (PIKA_SIZE_ENTRY (private->offset), 1,
MIN (0, diff_y), MAX (0, diff_y));
}
static gint
resize_bound_off_x (ResizeDialog *private,
gint offset_x)
{
PikaSizeBox *box = PIKA_SIZE_BOX (private->box);
if (private->old_width <= box->width)
return CLAMP (offset_x, 0, (box->width - private->old_width));
else
return CLAMP (offset_x, (box->width - private->old_width), 0);
}
static gint
resize_bound_off_y (ResizeDialog *private,
gint off_y)
{
PikaSizeBox *box = PIKA_SIZE_BOX (private->box);
if (private->old_height <= box->height)
return CLAMP (off_y, 0, (box->height - private->old_height));
else
return CLAMP (off_y, (box->height - private->old_height), 0);
}
static void
offset_update (GtkWidget *widget,
ResizeDialog *private)
{
PikaSizeEntry *entry = PIKA_SIZE_ENTRY (private->offset);
gint off_x;
gint off_y;
off_x = resize_bound_off_x (private,
RINT (pika_size_entry_get_refval (entry, 0)));
off_y = resize_bound_off_y (private,
RINT (pika_size_entry_get_refval (entry, 1)));
pika_offset_area_set_offsets (PIKA_OFFSET_AREA (private->area), off_x, off_y);
}
static void
offsets_changed (GtkWidget *area,
gint off_x,
gint off_y,
ResizeDialog *private)
{
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset), 0, off_x);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset), 1, off_y);
}
static void
offset_center_clicked (GtkWidget *widget,
ResizeDialog *private)
{
PikaSizeBox *box = PIKA_SIZE_BOX (private->box);
gint off_x;
gint off_y;
off_x = resize_bound_off_x (private, (box->width - private->old_width) / 2);
off_y = resize_bound_off_y (private, (box->height - private->old_height) / 2);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset), 0, off_x);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (private->offset), 1, off_y);
g_signal_emit_by_name (private->offset, "value-changed", 0);
}
static void
template_changed (PikaContext *context,
PikaTemplate *template,
ResizeDialog *private)
{
PikaUnit unit = private->old_unit;
private->template = template;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->ppi_image), TRUE);
gtk_widget_hide (private->ppi_box);
if (template != NULL)
{
gdouble xres;
gdouble yres;
PikaUnit res_unit;
gboolean resolution_mismatch;
unit = pika_template_get_unit (template);
xres = pika_template_get_resolution_x (template);
yres = pika_template_get_resolution_y (template);
res_unit = pika_template_get_resolution_unit (template);
resolution_mismatch = xres != private->old_xres ||
yres != private->old_yres ||
res_unit != private->old_res_unit;
if (resolution_mismatch &&
unit != PIKA_UNIT_PIXEL)
{
gchar *text;
text = g_strdup_printf (_("Scale template to %.2f ppi"),
private->old_xres);
gtk_button_set_label (GTK_BUTTON (private->ppi_image), text);
g_free (text);
text = g_strdup_printf (_("Set image to %.2f ppi"),
xres);
gtk_button_set_label (GTK_BUTTON (private->ppi_template), text);
g_free (text);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (private->ppi_image),
TRUE);
gtk_widget_show (private->ppi_box);
}
}
ppi_select_toggled (NULL, private);
pika_size_entry_set_unit (PIKA_SIZE_ENTRY (private->offset), unit);
}
static void
ppi_select_toggled (GtkWidget *radio,
ResizeDialog *private)
{
gint width;
gint height;
PikaUnit unit;
gdouble xres;
gdouble yres;
PikaUnit res_unit;
GtkToggleButton *image_button;
gboolean use_image_ppi;
width = private->old_width;
height = private->old_height;
xres = private->old_xres;
yres = private->old_yres;
res_unit = private->old_res_unit;
unit = private->old_unit;
image_button = GTK_TOGGLE_BUTTON (private->ppi_image);
use_image_ppi = gtk_toggle_button_get_active (image_button);
if (private->template != NULL)
{
width = pika_template_get_width (private->template);
height = pika_template_get_height (private->template);
unit = pika_template_get_unit (private->template);
xres = pika_template_get_resolution_x (private->template);
yres = pika_template_get_resolution_y (private->template);
res_unit = pika_template_get_resolution_unit (private->template);
}
if (private->template != NULL &&
unit != PIKA_UNIT_PIXEL)
{
if (use_image_ppi)
{
width = ceil (width * (private->old_xres / xres));
height = ceil (height * (private->old_yres / yres));
xres = private->old_xres;
yres = private->old_yres;
}
g_object_set (private->box,
"xresolution", xres,
"yresolution", yres,
"resolution-unit", res_unit,
NULL);
}
else
{
g_object_set (private->box,
"xresolution", private->old_xres,
"yresolution", private->old_yres,
"resolution-unit", private->old_res_unit,
NULL);
}
g_object_set (private->box,
"width", width,
"height", height,
"unit", unit,
NULL);
}
static void
reset_template_clicked (GtkWidget *button,
ResizeDialog *private)
{
pika_context_set_template (private->context, NULL);
}

View File

@ -0,0 +1,58 @@
/* 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/>.
*/
#ifndef __RESIZE_DIALOG_H__
#define __RESIZE_DIALOG_H__
typedef void (* PikaResizeCallback) (GtkWidget *dialog,
PikaViewable *viewable,
PikaContext *context,
gint width,
gint height,
PikaUnit unit,
gint offset_x,
gint offset_y,
gdouble xres,
gdouble yres,
PikaUnit res_unit,
PikaFillType fill_type,
PikaItemSet layer_set,
gboolean resize_text_layers,
gpointer user_data);
GtkWidget * resize_dialog_new (PikaViewable *viewable,
PikaContext *context,
const gchar *title,
const gchar *role,
GtkWidget *parent,
PikaHelpFunc help_func,
const gchar *help_id,
PikaUnit unit,
PikaFillType fill_type,
PikaItemSet layer_set,
gboolean resize_text_layers,
PikaResizeCallback callback,
gpointer user_data);
#endif /* __RESIZE_DIALOG_H__ */

View File

@ -0,0 +1,199 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "resolution-calibrate-dialog.h"
#include "pika-intl.h"
static GtkWidget *calibrate_entry = NULL;
static gdouble calibrate_xres = 1.0;
static gdouble calibrate_yres = 1.0;
static gint ruler_width = 1;
static gint ruler_height = 1;
/**
* resolution_calibrate_dialog:
* @resolution_entry: a #PikaSizeEntry to connect the dialog to
* @icon_name: an optional icon-name for the upper left corner
*
* Displays a dialog that allows the user to interactively determine
* her monitor resolution. This dialog runs it's own GTK main loop and
* is connected to a #PikaSizeEntry handling the resolution to be set.
**/
void
resolution_calibrate_dialog (GtkWidget *resolution_entry,
const gchar *icon_name)
{
GtkWidget *dialog;
GtkWidget *grid;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *ruler;
GtkWidget *label;
GdkRectangle workarea;
g_return_if_fail (PIKA_IS_SIZE_ENTRY (resolution_entry));
g_return_if_fail (gtk_widget_get_realized (resolution_entry));
/* this dialog can only exist once */
if (calibrate_entry)
return;
dialog = pika_dialog_new (_("Calibrate Monitor Resolution"),
"pika-resolution-calibration",
gtk_widget_get_toplevel (resolution_entry),
GTK_DIALOG_DESTROY_WITH_PARENT,
NULL, NULL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gdk_monitor_get_workarea (pika_widget_get_monitor (dialog), &workarea);
ruler_width = workarea.width - 300 - (workarea.width % 100);
ruler_height = workarea.height - 300 - (workarea.height % 100);
grid = gtk_grid_new ();
gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
grid, TRUE, TRUE, 0);
gtk_widget_show (grid);
if (icon_name)
{
GtkWidget *image = gtk_image_new_from_icon_name (icon_name,
GTK_ICON_SIZE_DIALOG);
gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 1);
gtk_widget_show (image);
}
ruler = pika_ruler_new (GTK_ORIENTATION_HORIZONTAL);
gtk_widget_set_size_request (ruler, ruler_width, 32);
pika_ruler_set_range (PIKA_RULER (ruler), 0, ruler_width, ruler_width);
gtk_grid_attach (GTK_GRID (grid), ruler, 1, 0, 2, 1);
gtk_widget_show (ruler);
ruler = pika_ruler_new (GTK_ORIENTATION_VERTICAL);
gtk_widget_set_size_request (ruler, 32, ruler_height);
pika_ruler_set_range (PIKA_RULER (ruler), 0, ruler_height, ruler_height);
gtk_grid_attach (GTK_GRID (grid), ruler, 0, 1, 1, 2);
gtk_widget_show (ruler);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_grid_attach (GTK_GRID (grid), vbox, 1, 1, 1, 1);
gtk_widget_show (vbox);
label =
gtk_label_new (_("Measure the rulers and enter their lengths:"));
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_SCALE, PANGO_SCALE_LARGE,
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
calibrate_xres =
pika_size_entry_get_refval (PIKA_SIZE_ENTRY (resolution_entry), 0);
calibrate_yres =
pika_size_entry_get_refval (PIKA_SIZE_ENTRY (resolution_entry), 1);
calibrate_entry =
pika_coordinates_new (PIKA_UNIT_INCH, "%p",
FALSE, FALSE, 10,
PIKA_SIZE_ENTRY_UPDATE_SIZE,
FALSE,
FALSE,
_("_Horizontal:"),
ruler_width,
calibrate_xres,
1, PIKA_MAX_IMAGE_SIZE,
0, 0,
_("_Vertical:"),
ruler_height,
calibrate_yres,
1, PIKA_MAX_IMAGE_SIZE,
0, 0);
gtk_widget_hide (GTK_WIDGET (PIKA_COORDINATES_CHAINBUTTON (calibrate_entry)));
g_signal_connect (dialog, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&calibrate_entry);
gtk_box_pack_end (GTK_BOX (hbox), calibrate_entry, FALSE, FALSE, 0);
gtk_widget_show (calibrate_entry);
gtk_widget_show (dialog);
switch (pika_dialog_run (PIKA_DIALOG (dialog)))
{
case GTK_RESPONSE_OK:
{
GtkWidget *chain_button;
gdouble x, y;
x = pika_size_entry_get_refval (PIKA_SIZE_ENTRY (calibrate_entry), 0);
y = pika_size_entry_get_refval (PIKA_SIZE_ENTRY (calibrate_entry), 1);
calibrate_xres = (gdouble) ruler_width * calibrate_xres / x;
calibrate_yres = (gdouble) ruler_height * calibrate_yres / y;
chain_button = PIKA_COORDINATES_CHAINBUTTON (resolution_entry);
if (ABS (x - y) > PIKA_MIN_RESOLUTION)
pika_chain_button_set_active (PIKA_CHAIN_BUTTON (chain_button),
FALSE);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (resolution_entry),
0, calibrate_xres);
pika_size_entry_set_refval (PIKA_SIZE_ENTRY (resolution_entry),
1, calibrate_yres);
}
default:
break;
}
gtk_widget_destroy (dialog);
}

View File

@ -0,0 +1,30 @@
/* 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/>.
*/
#ifndef __RESOLUTION_CALIBRATE_DIALOG_H__
#define __RESOLUTION_CALIBRATE_DIALOG_H__
void resolution_calibrate_dialog (GtkWidget *resolution_entry,
const gchar *icon_name);
#endif /* __RESOLUTION_CALIBRATE_DIALOG_H__ */

315
app/dialogs/scale-dialog.c Normal file
View File

@ -0,0 +1,315 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikaitem.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikasizebox.h"
#include "widgets/pikaviewabledialog.h"
#include "scale-dialog.h"
#include "pika-intl.h"
#define RESPONSE_RESET 1
typedef struct _ScaleDialog ScaleDialog;
struct _ScaleDialog
{
PikaViewable *viewable;
PikaUnit unit;
PikaInterpolationType interpolation;
GtkWidget *box;
GtkWidget *combo;
PikaScaleCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void scale_dialog_free (ScaleDialog *private);
static void scale_dialog_response (GtkWidget *dialog,
gint response_id,
ScaleDialog *private);
static void scale_dialog_reset (ScaleDialog *private);
/* public function */
GtkWidget *
scale_dialog_new (PikaViewable *viewable,
PikaContext *context,
const gchar *title,
const gchar *role,
GtkWidget *parent,
PikaHelpFunc help_func,
const gchar *help_id,
PikaUnit unit,
PikaInterpolationType interpolation,
PikaScaleCallback callback,
gpointer user_data)
{
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *label;
ScaleDialog *private;
PikaImage *image = NULL;
const gchar *text = NULL;
gint width, height;
gdouble xres, yres;
g_return_val_if_fail (PIKA_IS_VIEWABLE (viewable), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (callback != NULL, NULL);
if (PIKA_IS_IMAGE (viewable))
{
image = PIKA_IMAGE (viewable);
width = pika_image_get_width (image);
height = pika_image_get_height (image);
text = _("Image Size");
}
else if (PIKA_IS_ITEM (viewable))
{
PikaItem *item = PIKA_ITEM (viewable);
image = pika_item_get_image (item);
width = pika_item_get_width (item);
height = pika_item_get_height (item);
text = _("Layer Size");
}
else
{
g_return_val_if_reached (NULL);
}
private = g_slice_new0 (ScaleDialog);
private->viewable = viewable;
private->interpolation = interpolation;
private->unit = unit;
private->callback = callback;
private->user_data = user_data;
pika_image_get_resolution (image, &xres, &yres);
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, viewable), context,
title, role, PIKA_ICON_OBJECT_SCALE, title,
parent,
help_func, help_id,
_("_Reset"), RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Scale"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) scale_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (scale_dialog_response),
private);
private->box = g_object_new (PIKA_TYPE_SIZE_BOX,
"width", width,
"height", height,
"unit", unit,
"xresolution", xres,
"yresolution", yres,
"resolution-unit", pika_image_get_unit (image),
"keep-aspect", TRUE,
"edit-resolution", PIKA_IS_IMAGE (viewable),
NULL);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
frame = pika_frame_new (text);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
gtk_container_add (GTK_CONTAINER (frame), private->box);
gtk_widget_show (private->box);
frame = pika_frame_new (_("Quality"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("I_nterpolation:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
gtk_size_group_add_widget (PIKA_SIZE_BOX (private->box)->size_group, label);
private->combo = pika_enum_combo_box_new (PIKA_TYPE_INTERPOLATION_TYPE);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), private->combo);
gtk_box_pack_start (GTK_BOX (hbox), private->combo, TRUE, TRUE, 0);
gtk_widget_show (private->combo);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->combo),
private->interpolation);
return dialog;
}
/* private functions */
static void
scale_dialog_free (ScaleDialog *private)
{
g_slice_free (ScaleDialog, private);
}
static void
scale_dialog_response (GtkWidget *dialog,
gint response_id,
ScaleDialog *private)
{
PikaUnit unit = private->unit;
gint interpolation = private->interpolation;
PikaUnit resolution_unit;
gint width, height;
gdouble xres, yres;
switch (response_id)
{
case RESPONSE_RESET:
scale_dialog_reset (private);
break;
case GTK_RESPONSE_OK:
g_object_get (private->box,
"width", &width,
"height", &height,
"unit", &unit,
"xresolution", &xres,
"yresolution", &yres,
"resolution-unit", &resolution_unit,
NULL);
pika_int_combo_box_get_active (PIKA_INT_COMBO_BOX (private->combo),
&interpolation);
private->callback (dialog,
private->viewable,
width, height, unit, interpolation,
xres, yres, resolution_unit,
private->user_data);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}
static void
scale_dialog_reset (ScaleDialog *private)
{
PikaImage *image;
gint width, height;
gdouble xres, yres;
if (PIKA_IS_IMAGE (private->viewable))
{
image = PIKA_IMAGE (private->viewable);
width = pika_image_get_width (image);
height = pika_image_get_height (image);
}
else if (PIKA_IS_ITEM (private->viewable))
{
PikaItem *item = PIKA_ITEM (private->viewable);
image = pika_item_get_image (item);
width = pika_item_get_width (item);
height = pika_item_get_height (item);
}
else
{
g_return_if_reached ();
}
pika_image_get_resolution (image, &xres, &yres);
g_object_set (private->box,
"keep-aspect", FALSE,
NULL);
g_object_set (private->box,
"width", width,
"height", height,
"unit", private->unit,
NULL);
g_object_set (private->box,
"keep-aspect", TRUE,
"xresolution", xres,
"yresolution", yres,
"resolution-unit", pika_image_get_unit (image),
NULL);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->combo),
private->interpolation);
}

View File

@ -0,0 +1,39 @@
/* 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/>.
*/
#ifndef __SCALE_DIALOG_H__
#define __SCALE_DIALOG_H__
GtkWidget * scale_dialog_new (PikaViewable *viewable,
PikaContext *context,
const gchar *title,
const gchar *role,
GtkWidget *parent,
PikaHelpFunc help_func,
const gchar *help_id,
PikaUnit unit,
PikaInterpolationType interpolation,
PikaScaleCallback callback,
gpointer user_data);
#endif /* __SCALE_DIALOG_H__ */

296
app/dialogs/stroke-dialog.c Normal file
View File

@ -0,0 +1,296 @@
/* 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
*
* Copyright (C) 2003 Henrik Brix Andersen <brix@gimp.org>
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pikadrawable.h"
#include "core/pikaimage.h"
#include "core/pikapaintinfo.h"
#include "core/pikastrokeoptions.h"
#include "core/pikatoolinfo.h"
#include "widgets/pikacontainercombobox.h"
#include "widgets/pikacontainerview.h"
#include "widgets/pikaviewabledialog.h"
#include "widgets/pikastrokeeditor.h"
#include "stroke-dialog.h"
#include "pika-intl.h"
#define RESPONSE_RESET 1
typedef struct _StrokeDialog StrokeDialog;
struct _StrokeDialog
{
GList *items;
GList *drawables;
PikaContext *context;
PikaStrokeOptions *options;
PikaStrokeCallback callback;
gpointer user_data;
GtkWidget *tool_combo;
};
/* local function prototypes */
static void stroke_dialog_free (StrokeDialog *private);
static void stroke_dialog_response (GtkWidget *dialog,
gint response_id,
StrokeDialog *private);
static void stroke_dialog_expand_tabs (GtkWidget *widget,
gpointer data);
/* public function */
GtkWidget *
stroke_dialog_new (GList *items,
GList *drawables,
PikaContext *context,
const gchar *title,
const gchar *icon_name,
const gchar *help_id,
GtkWidget *parent,
PikaStrokeOptions *options,
PikaStrokeCallback callback,
gpointer user_data)
{
StrokeDialog *private;
PikaImage *image;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *switcher;
GtkWidget *stack;
GtkWidget *frame;
g_return_val_if_fail (items, NULL);
g_return_val_if_fail (drawables, NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (callback != NULL, NULL);
image = pika_item_get_image (items->data);
private = g_slice_new0 (StrokeDialog);
private->items = g_list_copy (items);
private->drawables = g_list_copy (drawables);
private->context = context;
private->options = pika_stroke_options_new (context->pika, context, TRUE);
private->callback = callback;
private->user_data = user_data;
pika_config_sync (G_OBJECT (options),
G_OBJECT (private->options), 0);
dialog = pika_viewable_dialog_new (g_list_copy (items), context,
title, "pika-stroke-options",
icon_name,
_("Choose Stroke Style"),
parent,
pika_standard_help_func,
help_id,
_("_Reset"), RESPONSE_RESET,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Stroke"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) stroke_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (stroke_dialog_response),
private);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
/* switcher */
switcher = gtk_stack_switcher_new ();
gtk_box_pack_start (GTK_BOX (main_vbox), switcher, TRUE, TRUE, 0);
gtk_widget_show (switcher);
stack = gtk_stack_new ();
gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher),
GTK_STACK (stack));
gtk_box_pack_start (GTK_BOX (main_vbox), stack, TRUE, TRUE, 0);
gtk_widget_show (stack);
/* the stroke frame */
frame = pika_frame_new (NULL);
gtk_stack_add_titled (GTK_STACK (stack),
frame,
"stroke-tool",
"Line");
gtk_widget_show (frame);
{
GtkWidget *stroke_editor;
gdouble xres;
gdouble yres;
pika_image_get_resolution (image, &xres, &yres);
stroke_editor = pika_stroke_editor_new (private->options, yres, FALSE,
FALSE);
gtk_container_add (GTK_CONTAINER (frame), stroke_editor);
gtk_widget_show (stroke_editor);
}
/* the paint tool frame */
frame = pika_frame_new (NULL);
gtk_stack_add_titled (GTK_STACK (stack),
frame,
"paint-tool",
"Paint tool");
gtk_widget_show (frame);
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *combo;
GtkWidget *button;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("P_aint tool:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
combo = pika_container_combo_box_new (image->pika->paint_info_list,
PIKA_CONTEXT (private->options),
16, 0);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
private->tool_combo = combo;
button = pika_prop_check_button_new (G_OBJECT (private->options),
"emulate-brush-dynamics",
_("_Emulate brush dynamics"));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
}
/* Setting hexpand property of all tabs to true */
gtk_container_foreach (GTK_CONTAINER (switcher),
stroke_dialog_expand_tabs,
NULL);
return dialog;
}
/* private functions */
static void
stroke_dialog_free (StrokeDialog *private)
{
g_object_unref (private->options);
g_list_free (private->drawables);
g_list_free (private->items);
g_slice_free (StrokeDialog, private);
}
static void
stroke_dialog_response (GtkWidget *dialog,
gint response_id,
StrokeDialog *private)
{
switch (response_id)
{
case RESPONSE_RESET:
{
PikaToolInfo *tool_info = pika_context_get_tool (private->context);
pika_config_reset (PIKA_CONFIG (private->options));
pika_container_view_select_item (PIKA_CONTAINER_VIEW (private->tool_combo),
PIKA_VIEWABLE (tool_info->paint_info));
}
break;
case GTK_RESPONSE_OK:
private->callback (dialog,
private->items,
private->drawables,
private->context,
private->options,
private->user_data);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}
static void
stroke_dialog_expand_tabs (GtkWidget *widget, gpointer data)
{
gtk_widget_set_hexpand (widget, TRUE);
}

View File

@ -0,0 +1,48 @@
/* 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
*
* Copyright (C) 2003 Simon Budig
*
* 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/>.
*/
#ifndef __STROKE_DIALOG_H__
#define __STROKE_DIALOG_H__
typedef void (* PikaStrokeCallback) (GtkWidget *dialog,
GList *items,
GList *drawables,
PikaContext *context,
PikaStrokeOptions *options,
gpointer user_data);
GtkWidget * stroke_dialog_new (GList *items,
GList *drawables,
PikaContext *context,
const gchar *title,
const gchar *icon_name,
const gchar *help_id,
GtkWidget *parent,
PikaStrokeOptions *options,
PikaStrokeCallback callback,
gpointer user_data);
#endif /* __STROKE_DIALOG_H__ */

View File

@ -0,0 +1,184 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikatemplate.h"
#include "widgets/pikatemplateeditor.h"
#include "widgets/pikaviewabledialog.h"
#include "template-options-dialog.h"
#include "pika-intl.h"
typedef struct _TemplateOptionsDialog TemplateOptionsDialog;
struct _TemplateOptionsDialog
{
PikaTemplate *template;
PikaContext *context;
PikaTemplateOptionsCallback callback;
gpointer user_data;
GtkWidget *editor;
};
/* local function prototypes */
static void template_options_dialog_free (TemplateOptionsDialog *private);
static void template_options_dialog_response (GtkWidget *dialog,
gint response_id,
TemplateOptionsDialog *private);
/* public function */
GtkWidget *
template_options_dialog_new (PikaTemplate *template,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
PikaTemplateOptionsCallback callback,
gpointer user_data)
{
TemplateOptionsDialog *private;
GtkWidget *dialog;
PikaViewable *viewable = NULL;
GtkWidget *vbox;
g_return_val_if_fail (template == NULL || PIKA_IS_TEMPLATE (template), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (role != NULL, NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (desc != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (TemplateOptionsDialog);
private->template = template;
private->context = context;
private->callback = callback;
private->user_data = user_data;
if (template)
{
viewable = PIKA_VIEWABLE (template);
template = pika_config_duplicate (PIKA_CONFIG (template));
}
else
{
template =
pika_config_duplicate (PIKA_CONFIG (context->pika->config->default_image));
viewable = PIKA_VIEWABLE (template);
pika_object_set_static_name (PIKA_OBJECT (template), _("Unnamed"));
}
dialog = pika_viewable_dialog_new (g_list_prepend (NULL, viewable), context,
title, role, icon_name, desc,
parent,
pika_standard_help_func, help_id,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) template_options_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (template_options_dialog_response),
private);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
private->editor = pika_template_editor_new (template, context->pika, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), private->editor, FALSE, FALSE, 0);
gtk_widget_show (private->editor);
g_object_unref (template);
return dialog;
}
/* private functions */
static void
template_options_dialog_free (TemplateOptionsDialog *private)
{
g_slice_free (TemplateOptionsDialog, private);
}
static void
template_options_dialog_response (GtkWidget *dialog,
gint response_id,
TemplateOptionsDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
PikaTemplateEditor *editor = PIKA_TEMPLATE_EDITOR (private->editor);
private->callback (dialog,
private->template,
pika_template_editor_get_template (editor),
private->context,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
}

View File

@ -0,0 +1,45 @@
/* 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/>.
*/
#ifndef __TEMPLATE_OPTIONS_DIALOG_H__
#define __TEMPLATE_OPTIONS_DIALOG_H__
typedef void (* PikaTemplateOptionsCallback) (GtkWidget *dialog,
PikaTemplate *template,
PikaTemplate *edit_template,
PikaContext *context,
gpointer user_data);
GtkWidget * template_options_dialog_new (PikaTemplate *template,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
PikaTemplateOptionsCallback callback,
gpointer user_data);
#endif /* __TEMPLATE_OPTIONS_DIALOG_H__ */

270
app/dialogs/tips-dialog.c Normal file
View File

@ -0,0 +1,270 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "config/pikaguiconfig.h"
#include "core/pika.h"
#include "widgets/pikahelp-ids.h"
#include "tips-dialog.h"
#include "tips-parser.h"
#include "pika-intl.h"
enum
{
RESPONSE_PREVIOUS = 1,
RESPONSE_NEXT = 2
};
static void tips_dialog_set_tip (PikaTip *tip);
static void tips_dialog_response (GtkWidget *dialog,
gint response);
static void tips_dialog_destroy (GtkWidget *widget,
PikaGuiConfig *config);
static gboolean more_button_clicked (GtkWidget *button,
Pika *pika);
static GtkWidget *tips_dialog = NULL;
static GtkWidget *tip_label = NULL;
static GtkWidget *more_button = NULL;
static GList *tips = NULL;
static GList *current_tip = NULL;
GtkWidget *
tips_dialog_create (Pika *pika)
{
PikaGuiConfig *config;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *image;
gint tips_count;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
if (!tips)
{
GError *error = NULL;
GFile *file;
file = pika_data_directory_file ("tips", "pika-tips.xml", NULL);
tips = pika_tips_from_file (file, &error);
if (! tips)
{
PikaTip *tip;
if (! error)
{
tip = pika_tip_new (_("The PIKA tips file is empty!"), NULL);
}
else if (error->code == G_FILE_ERROR_NOENT)
{
tip = pika_tip_new (_("The PIKA tips file appears to be "
"missing!"),
_("There should be a file called '%s'. "
"Please check your installation."),
pika_file_get_utf8_name (file));
}
else
{
tip = pika_tip_new (_("The PIKA tips file could not be parsed!"),
"%s", error->message);
}
tips = g_list_prepend (tips, tip);
}
else if (error)
{
g_printerr ("Error while parsing '%s': %s\n",
pika_file_get_utf8_name (file), error->message);
}
g_clear_error (&error);
g_object_unref (file);
}
tips_count = g_list_length (tips);
config = PIKA_GUI_CONFIG (pika->config);
if (config->last_tip_shown >= tips_count || config->last_tip_shown < 0)
config->last_tip_shown = 0;
current_tip = g_list_nth (tips, config->last_tip_shown);
if (tips_dialog)
return tips_dialog;
tips_dialog = pika_dialog_new (_("PIKA Tip of the Day"),
"pika-tip-of-the-day",
NULL, 0, NULL, NULL,
NULL);
button = gtk_dialog_add_button (GTK_DIALOG (tips_dialog),
_("_Previous Tip"), RESPONSE_PREVIOUS);
gtk_button_set_image (GTK_BUTTON (button),
gtk_image_new_from_icon_name (PIKA_ICON_GO_PREVIOUS,
GTK_ICON_SIZE_BUTTON));
button = gtk_dialog_add_button (GTK_DIALOG (tips_dialog),
_("_Next Tip"), RESPONSE_NEXT);
gtk_button_set_image (GTK_BUTTON (button),
gtk_image_new_from_icon_name (PIKA_ICON_GO_NEXT,
GTK_ICON_SIZE_BUTTON));
gtk_dialog_set_response_sensitive (GTK_DIALOG (tips_dialog),
RESPONSE_NEXT, tips_count > 1);
gtk_dialog_set_response_sensitive (GTK_DIALOG (tips_dialog),
RESPONSE_PREVIOUS, tips_count > 1);
g_signal_connect (tips_dialog, "response",
G_CALLBACK (tips_dialog_response),
NULL);
g_signal_connect (tips_dialog, "destroy",
G_CALLBACK (tips_dialog_destroy),
config);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (tips_dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
image = gtk_image_new_from_icon_name (PIKA_ICON_DIALOG_INFORMATION,
GTK_ICON_SIZE_DIALOG);
gtk_widget_set_valign (image, GTK_ALIGN_START);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
tip_label = gtk_label_new (NULL);
gtk_label_set_selectable (GTK_LABEL (tip_label), TRUE);
gtk_label_set_justify (GTK_LABEL (tip_label), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (tip_label), TRUE);
gtk_label_set_yalign (GTK_LABEL (tip_label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), tip_label, TRUE, TRUE, 0);
gtk_widget_show (tip_label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
more_button = gtk_link_button_new_with_label ("https://docs.pika.org/",
/* a link to the related section in the user manual */
_("Learn more"));
gtk_widget_show (more_button);
gtk_box_pack_start (GTK_BOX (hbox), more_button, FALSE, FALSE, 0);
g_signal_connect (more_button, "activate-link",
G_CALLBACK (more_button_clicked),
pika);
tips_dialog_set_tip (current_tip->data);
return tips_dialog;
}
static void
tips_dialog_destroy (GtkWidget *widget,
PikaGuiConfig *config)
{
/* the last-shown-tip is saved in sessionrc */
config->last_tip_shown = g_list_position (tips, current_tip);
tips_dialog = NULL;
current_tip = NULL;
pika_tips_free (tips);
tips = NULL;
}
static void
tips_dialog_response (GtkWidget *dialog,
gint response)
{
switch (response)
{
case RESPONSE_PREVIOUS:
current_tip = current_tip->prev ? current_tip->prev : g_list_last (tips);
tips_dialog_set_tip (current_tip->data);
break;
case RESPONSE_NEXT:
current_tip = current_tip->next ? current_tip->next : tips;
tips_dialog_set_tip (current_tip->data);
break;
default:
gtk_widget_destroy (dialog);
break;
}
}
static void
tips_dialog_set_tip (PikaTip *tip)
{
g_return_if_fail (tip != NULL);
gtk_label_set_markup (GTK_LABEL (tip_label), tip->text);
/* set the URI to unset the "visited" state */
gtk_link_button_set_uri (GTK_LINK_BUTTON (more_button),
"https://docs.pika.org/");
gtk_widget_set_sensitive (more_button, tip->help_id != NULL);
}
static gboolean
more_button_clicked (GtkWidget *button,
Pika *pika)
{
PikaTip *tip = current_tip->data;
if (tip->help_id)
pika_help (pika, NULL, NULL, tip->help_id);
/* Do not run the link set at construction. */
return TRUE;
}

29
app/dialogs/tips-dialog.h Normal file
View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __TIPS_DIALOG_H__
#define __TIPS_DIALOG_H__
GtkWidget * tips_dialog_create (Pika *pika);
#endif /* __TIPS_DIALOG_H__ */

481
app/dialogs/tips-parser.c Normal file
View File

@ -0,0 +1,481 @@
/* 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
*
* tips-parser.c - Parse the pika-tips.xml file.
* Copyright (C) 2002, 2008 Sven Neumann <sven@gimp.org>
*
* 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 <string.h>
#include <gio/gio.h>
#include "config/config-types.h"
#include "config/pikaxmlparser.h"
#include "tips-parser.h"
#include "pika-intl.h"
typedef enum
{
TIPS_START,
TIPS_IN_TIPS,
TIPS_IN_TIP,
TIPS_IN_THETIP,
TIPS_IN_UNKNOWN
} TipsParserState;
typedef enum
{
TIPS_LOCALE_NONE,
TIPS_LOCALE_MATCH,
TIPS_LOCALE_MISMATCH
} TipsParserLocaleState;
typedef struct
{
TipsParserState state;
TipsParserState last_known_state;
const gchar *locale;
const gchar *help_id;
TipsParserLocaleState locale_state;
gint markup_depth;
gint unknown_depth;
GString *value;
PikaTip *current_tip;
GList *tips;
} TipsParser;
static void tips_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void tips_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void tips_parser_characters (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error);
static void tips_parser_start_markup (TipsParser *parser,
const gchar *markup_name);
static void tips_parser_end_markup (TipsParser *parser,
const gchar *markup_name);
static void tips_parser_start_unknown (TipsParser *parser);
static void tips_parser_end_unknown (TipsParser *parser);
static gchar * tips_parser_parse_help_id (TipsParser *parser,
const gchar **names,
const gchar **values);
static void tips_parser_parse_locale (TipsParser *parser,
const gchar **names,
const gchar **values);
static void tips_parser_set_by_locale (TipsParser *parser,
gchar **dest);
static const GMarkupParser markup_parser =
{
tips_parser_start_element,
tips_parser_end_element,
tips_parser_characters,
NULL, /* passthrough */
NULL /* error */
};
PikaTip *
pika_tip_new (const gchar *title,
const gchar *format,
...)
{
PikaTip *tip = g_slice_new0 (PikaTip);
GString *str = g_string_new (NULL);
if (title)
{
g_string_append (str, "<b>");
g_string_append (str, title);
g_string_append (str, "</b>");
if (format)
g_string_append (str, "\n\n");
}
if (format)
{
va_list args;
va_start (args, format);
g_string_append_vprintf (str, format, args);
va_end (args);
}
tip->text = g_string_free (str, FALSE);
return tip;
}
void
pika_tip_free (PikaTip *tip)
{
if (! tip)
return;
g_free (tip->text);
g_free (tip->help_id);
g_slice_free (PikaTip, tip);
}
/**
* pika_tips_from_file:
* @file: the tips file to parse
* @error: return location for a #GError
*
* Reads a pika-tips XML file, creates a new #PikaTip for
* each tip entry and returns a #GList of them. If a parser
* error occurs at some point, the uncompleted list is
* returned and @error is set (unless @error is %NULL).
* The message set in @error contains a detailed description
* of the problem.
*
* Returns: a #Glist of #PikaTips.
**/
GList *
pika_tips_from_file (GFile *file,
GError **error)
{
PikaXmlParser *xml_parser;
TipsParser parser = { 0, };
const gchar *tips_locale;
GList *tips = NULL;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
parser.value = g_string_new (NULL);
/* This is a special string to specify the language identifier to
look for in the pika-tips.xml file. Please translate the C in it
according to the name of the po file used for pika-tips.xml.
E.g. for the german translation, that would be "tips-locale:de".
*/
tips_locale = _("tips-locale:C");
if (g_str_has_prefix (tips_locale, "tips-locale:"))
{
tips_locale += strlen ("tips-locale:");
if (*tips_locale && *tips_locale != 'C')
parser.locale = tips_locale;
}
else
{
g_warning ("Wrong translation for 'tips-locale:', fix the translation!");
}
xml_parser = pika_xml_parser_new (&markup_parser, &parser);
pika_xml_parser_parse_gfile (xml_parser, file, error);
pika_xml_parser_free (xml_parser);
tips = g_list_reverse (parser.tips);
pika_tip_free (parser.current_tip);
g_string_free (parser.value, TRUE);
return tips;
}
void
pika_tips_free (GList *tips)
{
GList *list;
for (list = tips; list; list = list->next)
pika_tip_free (list->data);
g_list_free (tips);
}
static void
tips_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
TipsParser *parser = user_data;
switch (parser->state)
{
case TIPS_START:
if (strcmp (element_name, "pika-tips") == 0)
{
parser->state = TIPS_IN_TIPS;
}
else
{
tips_parser_start_unknown (parser);
}
break;
case TIPS_IN_TIPS:
if (strcmp (element_name, "tip") == 0)
{
parser->state = TIPS_IN_TIP;
parser->current_tip = g_slice_new0 (PikaTip);
parser->current_tip->help_id = tips_parser_parse_help_id (parser,
attribute_names,
attribute_values);
}
else
{
tips_parser_start_unknown (parser);
}
break;
case TIPS_IN_TIP:
if (strcmp (element_name, "thetip") == 0)
{
parser->state = TIPS_IN_THETIP;
tips_parser_parse_locale (parser, attribute_names, attribute_values);
}
else
{
tips_parser_start_unknown (parser);
}
break;
case TIPS_IN_THETIP:
if (strcmp (element_name, "b" ) == 0 ||
strcmp (element_name, "big") == 0 ||
strcmp (element_name, "tt" ) == 0)
{
tips_parser_start_markup (parser, element_name);
}
else
{
tips_parser_start_unknown (parser);
}
break;
case TIPS_IN_UNKNOWN:
tips_parser_start_unknown (parser);
break;
}
}
static void
tips_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
TipsParser *parser = user_data;
switch (parser->state)
{
case TIPS_START:
g_warning ("%s: shouldn't get here", G_STRLOC);
break;
case TIPS_IN_TIPS:
parser->state = TIPS_START;
break;
case TIPS_IN_TIP:
parser->tips = g_list_prepend (parser->tips, parser->current_tip);
parser->current_tip = NULL;
parser->state = TIPS_IN_TIPS;
break;
case TIPS_IN_THETIP:
if (parser->markup_depth == 0)
{
tips_parser_set_by_locale (parser, &parser->current_tip->text);
g_string_truncate (parser->value, 0);
parser->state = TIPS_IN_TIP;
}
else
tips_parser_end_markup (parser, element_name);
break;
case TIPS_IN_UNKNOWN:
tips_parser_end_unknown (parser);
break;
}
}
static void
tips_parser_characters (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
TipsParser *parser = user_data;
switch (parser->state)
{
case TIPS_IN_THETIP:
if (parser->locale_state != TIPS_LOCALE_MISMATCH)
{
gint i;
/* strip tabs, newlines and adjacent whitespace */
for (i = 0; i < text_len; i++)
{
if (text[i] != ' ' &&
text[i] != '\t' && text[i] != '\n' && text[i] != '\r')
{
g_string_append_c (parser->value, text[i]);
}
else if (parser->value->len > 0 &&
parser->value->str[parser->value->len - 1] != ' ')
{
g_string_append_c (parser->value, ' ');
}
}
}
break;
default:
break;
}
}
static void
tips_parser_start_markup (TipsParser *parser,
const gchar *markup_name)
{
parser->markup_depth++;
g_string_append_printf (parser->value, "<%s>", markup_name);
}
static void
tips_parser_end_markup (TipsParser *parser,
const gchar *markup_name)
{
pika_assert (parser->markup_depth > 0);
parser->markup_depth--;
g_string_append_printf (parser->value, "</%s>", markup_name);
}
static void
tips_parser_start_unknown (TipsParser *parser)
{
if (parser->unknown_depth == 0)
parser->last_known_state = parser->state;
parser->state = TIPS_IN_UNKNOWN;
parser->unknown_depth++;
}
static void
tips_parser_end_unknown (TipsParser *parser)
{
pika_assert (parser->unknown_depth > 0 && parser->state == TIPS_IN_UNKNOWN);
parser->unknown_depth--;
if (parser->unknown_depth == 0)
parser->state = parser->last_known_state;
}
static gchar *
tips_parser_parse_help_id (TipsParser *parser,
const gchar **names,
const gchar **values)
{
while (*names && *values)
{
if (strcmp (*names, "help") == 0 && **values)
return g_strdup (*values);
names++;
values++;
}
return NULL;
}
static void
tips_parser_parse_locale (TipsParser *parser,
const gchar **names,
const gchar **values)
{
parser->locale_state = TIPS_LOCALE_NONE;
while (*names && *values)
{
if (strcmp (*names, "xml:lang") == 0 && **values)
{
parser->locale_state = (parser->locale &&
strcmp (*values, parser->locale) == 0 ?
TIPS_LOCALE_MATCH : TIPS_LOCALE_MISMATCH);
}
names++;
values++;
}
}
static void
tips_parser_set_by_locale (TipsParser *parser,
gchar **dest)
{
switch (parser->locale_state)
{
case TIPS_LOCALE_NONE:
if (!parser->locale)
{
g_free (*dest);
*dest = g_strdup (parser->value->str);
}
else if (*dest == NULL)
{
*dest = g_strdup (parser->value->str);
}
break;
case TIPS_LOCALE_MATCH:
g_free (*dest);
*dest = g_strdup (parser->value->str);
break;
case TIPS_LOCALE_MISMATCH:
break;
}
}

48
app/dialogs/tips-parser.h Normal file
View File

@ -0,0 +1,48 @@
/* 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
*
* tips-parser.h - Parse the pika-tips.xml file.
* Copyright (C) 2002, 2008 Sven Neumann <sven@gimp.org>
*
* 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/>.
*/
#ifndef __TIPS_PARSER_H__
#define __TIPS_PARSER_H__
typedef struct _PikaTip PikaTip;
struct _PikaTip
{
gchar *text;
gchar *help_id;
};
PikaTip * pika_tip_new (const gchar *title,
const gchar *format,
...) G_GNUC_PRINTF(2, 3);
void pika_tip_free (PikaTip *tip);
GList * pika_tips_from_file (GFile *file,
GError **error);
void pika_tips_free (GList *tips);
#endif /* __TIPS_PARSER_H__ */

View File

@ -0,0 +1,158 @@
/* 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
*
* user-install-dialog.c
* Copyright (C) 2000-2006 Michael Natterer and Sven Neumann
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika-user-install.h"
#include "widgets/pikamessagebox.h"
#include "widgets/pikamessagedialog.h"
#include "user-install-dialog.h"
#include "pika-intl.h"
static GtkWidget * user_install_dialog_new (PikaUserInstall *install);
static void user_install_dialog_log (const gchar *message,
gboolean error,
gpointer data);
gboolean
user_install_dialog_run (PikaUserInstall *install)
{
GtkWidget *dialog;
gboolean success;
g_return_val_if_fail (install != NULL, FALSE);
dialog = user_install_dialog_new (install);
success = pika_user_install_run (install,
gtk_widget_get_scale_factor (dialog));
if (! success)
{
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_main_quit),
NULL);
gtk_widget_show (dialog);
gtk_main ();
}
gtk_widget_destroy (dialog);
return success;
}
static GtkWidget *
user_install_dialog_new (PikaUserInstall *install)
{
GtkWidget *dialog;
GtkWidget *frame;
GtkWidget *scrolled;
GtkTextBuffer *buffer;
GtkWidget *view;
pika_icons_init ();
dialog = pika_message_dialog_new (_("PIKA User Installation"),
PIKA_ICON_MASCOT_EEK,
NULL, 0, NULL, NULL,
_("_Quit"), GTK_RESPONSE_OK,
NULL);
pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("User installation failed!"));
pika_message_box_set_text (PIKA_MESSAGE_DIALOG (dialog)->box,
_("The PIKA user installation failed; "
"see the log for details."));
frame = pika_frame_new (_("Installation Log"));
gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (frame), scrolled);
gtk_widget_show (scrolled);
buffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (buffer, "bold",
"weight", PANGO_WEIGHT_BOLD,
NULL);
view = gtk_text_view_new_with_buffer (buffer);
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
gtk_widget_set_size_request (view, -1, 200);
gtk_container_add (GTK_CONTAINER (scrolled), view);
gtk_widget_show (view);
g_object_unref (buffer);
pika_user_install_set_log_handler (install, user_install_dialog_log, buffer);
return dialog;
}
static void
user_install_dialog_log (const gchar *message,
gboolean error,
gpointer data)
{
GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
GtkTextIter cursor;
gtk_text_buffer_get_end_iter (buffer, &cursor);
if (error && message)
{
gtk_text_buffer_insert_with_tags_by_name (buffer, &cursor, message, -1,
"bold", NULL);
}
else if (message)
{
gtk_text_buffer_insert (buffer, &cursor, message, -1);
}
gtk_text_buffer_insert (buffer, &cursor, "\n", -1);
}

View File

@ -0,0 +1,29 @@
/* 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/>.
*/
#ifndef __USER_INSTALL_DIALOG_H__
#define __USER_INSTALL_DIALOG_H__
gboolean user_install_dialog_run (PikaUserInstall *install);
#endif /* __USER_INSTALL_DIALOG_H__ */

View File

@ -0,0 +1,183 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikaimage.h"
#include "vectors-export-dialog.h"
#include "pika-intl.h"
typedef struct _VectorsExportDialog VectorsExportDialog;
struct _VectorsExportDialog
{
PikaImage *image;
gboolean active_only;
PikaVectorsExportCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void vectors_export_dialog_free (VectorsExportDialog *private);
static void vectors_export_dialog_response (GtkWidget *widget,
gint response_id,
VectorsExportDialog *private);
/* public function */
GtkWidget *
vectors_export_dialog_new (PikaImage *image,
GtkWidget *parent,
GFile *export_folder,
gboolean active_only,
PikaVectorsExportCallback callback,
gpointer user_data)
{
VectorsExportDialog *private;
GtkWidget *dialog;
GtkWidget *combo;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (export_folder == NULL || G_IS_FILE (export_folder),
NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (VectorsExportDialog);
private->image = image;
private->active_only = active_only;
private->callback = callback;
private->user_data = user_data;
dialog = gtk_file_chooser_dialog_new (_("Export Path to SVG"), NULL,
GTK_FILE_CHOOSER_ACTION_SAVE,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_role (GTK_WINDOW (dialog), "pika-vectors-export");
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
gtk_window_set_screen (GTK_WINDOW (dialog),
gtk_widget_get_screen (parent));
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
TRUE);
if (export_folder)
gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog),
export_folder, NULL);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) vectors_export_dialog_free, private);
g_signal_connect_object (image, "disconnect",
G_CALLBACK (gtk_widget_destroy),
dialog, 0);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_true),
NULL);
g_signal_connect (dialog, "response",
G_CALLBACK (vectors_export_dialog_response),
private);
combo = pika_int_combo_box_new (_("Export the selected paths"), TRUE,
_("Export all paths from this image"), FALSE,
NULL);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (combo),
private->active_only);
gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), combo);
g_signal_connect (combo, "changed",
G_CALLBACK (pika_int_combo_box_get_active),
&private->active_only);
return dialog;
}
/* private functions */
static void
vectors_export_dialog_free (VectorsExportDialog *private)
{
g_slice_free (VectorsExportDialog, private);
}
static void
vectors_export_dialog_response (GtkWidget *dialog,
gint response_id,
VectorsExportDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
GFile *file;
file = gtk_file_chooser_get_file (chooser);
if (file)
{
GFile *folder;
folder = gtk_file_chooser_get_current_folder_file (chooser);
private->callback (dialog,
private->image,
file,
folder,
private->active_only,
private->user_data);
if (folder)
g_object_unref (folder);
g_object_unref (file);
}
}
else
{
gtk_widget_destroy (dialog);
}
}

View File

@ -0,0 +1,42 @@
/* 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/>.
*/
#ifndef __VECTORS_EXPORT_DIALOG_H__
#define __VECTORS_EXPORT_DIALOG_H__
typedef void (* PikaVectorsExportCallback) (GtkWidget *dialog,
PikaImage *image,
GFile *file,
GFile *export_folder,
gboolean active_only,
gpointer user_data);
GtkWidget * vectors_export_dialog_new (PikaImage *image,
GtkWidget *parent,
GFile *export_folder,
gboolean active_only,
PikaVectorsExportCallback callback,
gpointer user_data);
#endif /* __VECTORS_EXPORT_DIALOG_H__ */

View File

@ -0,0 +1,213 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikaimage.h"
#include "vectors-import-dialog.h"
#include "pika-intl.h"
typedef struct _VectorsImportDialog VectorsImportDialog;
struct _VectorsImportDialog
{
PikaImage *image;
gboolean merge_vectors;
gboolean scale_vectors;
PikaVectorsImportCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void vectors_import_dialog_free (VectorsImportDialog *private);
static void vectors_import_dialog_response (GtkWidget *dialog,
gint response_id,
VectorsImportDialog *private);
/* public function */
GtkWidget *
vectors_import_dialog_new (PikaImage *image,
GtkWidget *parent,
GFile *import_folder,
gboolean merge_vectors,
gboolean scale_vectors,
PikaVectorsImportCallback callback,
gpointer user_data)
{
VectorsImportDialog *private;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *button;
GtkFileFilter *filter;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (import_folder == NULL || G_IS_FILE (import_folder),
NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (VectorsImportDialog);
private->image = image;
private->merge_vectors = merge_vectors;
private->scale_vectors = scale_vectors;
private->callback = callback;
private->user_data = user_data;
dialog = gtk_file_chooser_dialog_new (_("Import Paths from SVG"), NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_role (GTK_WINDOW (dialog), "pika-vectors-import");
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
gtk_window_set_screen (GTK_WINDOW (dialog),
gtk_widget_get_screen (parent));
if (import_folder)
gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog),
import_folder, NULL);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) vectors_import_dialog_free, private);
g_signal_connect_object (image, "disconnect",
G_CALLBACK (gtk_widget_destroy),
dialog, 0);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_true),
NULL);
g_signal_connect (dialog, "response",
G_CALLBACK (vectors_import_dialog_response),
private);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All files (*.*)"));
gtk_file_filter_add_pattern (filter, "*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Scalable SVG image (*.svg)"));
gtk_file_filter_add_pattern (filter, "*.[Ss][Vv][Gg]");
gtk_file_filter_add_mime_type (filter, "image/svg+xml");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), vbox);
gtk_widget_show (vbox);
button = gtk_check_button_new_with_mnemonic (_("_Merge imported paths"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->merge_vectors);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->merge_vectors);
button = gtk_check_button_new_with_mnemonic (_("_Scale imported paths "
"to fit image"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
private->scale_vectors);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "toggled",
G_CALLBACK (pika_toggle_button_update),
&private->scale_vectors);
return dialog;
}
/* private functions */
static void
vectors_import_dialog_free (VectorsImportDialog *private)
{
g_slice_free (VectorsImportDialog, private);
}
static void
vectors_import_dialog_response (GtkWidget *dialog,
gint response_id,
VectorsImportDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
GFile *file;
file = gtk_file_chooser_get_file (chooser);
if (file)
{
GFile *folder;
folder = gtk_file_chooser_get_current_folder_file (chooser);
private->callback (dialog,
private->image,
file,
folder,
private->merge_vectors,
private->scale_vectors,
private->user_data);
if (folder)
g_object_unref (folder);
g_object_unref (file);
}
}
else
{
gtk_widget_destroy (dialog);
}
}

View File

@ -0,0 +1,44 @@
/* 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/>.
*/
#ifndef __VECTORS_IMPORT_DIALOG_H__
#define __VECTORS_IMPORT_DIALOG_H__
typedef void (* PikaVectorsImportCallback) (GtkWidget *dialog,
PikaImage *image,
GFile *file,
GFile *import_folder,
gboolean merge_vectors,
gboolean scale_vectors,
gpointer user_data);
GtkWidget * vectors_import_dialog_new (PikaImage *image,
GtkWidget *parent,
GFile *import_folder,
gboolean merge_vectors,
gboolean scale_vectors,
PikaVectorsImportCallback callback,
gpointer user_data);
#endif /* __VECTORS_IMPORT_DIALOG_H__ */

View File

@ -0,0 +1,165 @@
/* 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 <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "vectors/pikavectors.h"
#include "item-options-dialog.h"
#include "vectors-options-dialog.h"
#include "pika-intl.h"
typedef struct _VectorsOptionsDialog VectorsOptionsDialog;
struct _VectorsOptionsDialog
{
PikaVectorsOptionsCallback callback;
gpointer user_data;
};
/* local function prototypes */
static void vectors_options_dialog_free (VectorsOptionsDialog *private);
static void vectors_options_dialog_callback (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data);
/* public functions */
GtkWidget *
vectors_options_dialog_new (PikaImage *image,
PikaVectors *vectors,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *vectors_name,
gboolean vectors_visible,
PikaColorTag vectors_color_tag,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gboolean vectors_lock_visibility,
PikaVectorsOptionsCallback callback,
gpointer user_data)
{
VectorsOptionsDialog *private;
GtkWidget *dialog;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (vectors == NULL || PIKA_IS_VECTORS (vectors), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (role != NULL, NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (desc != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (callback != NULL, NULL);
private = g_slice_new0 (VectorsOptionsDialog);
private->callback = callback;
private->user_data = user_data;
dialog = item_options_dialog_new (image, PIKA_ITEM (vectors), context,
parent, title, role,
icon_name, desc, help_id,
_("Path _name:"),
PIKA_ICON_LOCK_CONTENT,
_("Lock path _strokes"),
_("Lock path _position"),
_("Lock path _visibility"),
vectors_name,
vectors_visible,
vectors_color_tag,
vectors_lock_content,
vectors_lock_position,
vectors_lock_visibility,
vectors_options_dialog_callback,
private);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) vectors_options_dialog_free, private);
return dialog;
}
/* private functions */
static void
vectors_options_dialog_free (VectorsOptionsDialog *private)
{
g_slice_free (VectorsOptionsDialog, private);
}
static void
vectors_options_dialog_callback (GtkWidget *dialog,
PikaImage *image,
PikaItem *item,
PikaContext *context,
const gchar *item_name,
gboolean item_visible,
PikaColorTag item_color_tag,
gboolean item_lock_content,
gboolean item_lock_position,
gboolean item_lock_visibility,
gpointer user_data)
{
VectorsOptionsDialog *private = user_data;
private->callback (dialog,
image,
PIKA_VECTORS (item),
context,
item_name,
item_visible,
item_color_tag,
item_lock_content,
item_lock_position,
item_lock_visibility,
private->user_data);
}

View File

@ -0,0 +1,58 @@
/* 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/>.
*/
#ifndef __VECTORS_OPTIONS_DIALOG_H__
#define __VECTORS_OPTIONS_DIALOG_H__
typedef void (* PikaVectorsOptionsCallback) (GtkWidget *dialog,
PikaImage *image,
PikaVectors *vectors,
PikaContext *context,
const gchar *vectors_name,
gboolean vectors_visible,
PikaColorTag vectors_color_tag,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gboolean vectors_lock_visibility,
gpointer user_data);
GtkWidget * vectors_options_dialog_new (PikaImage *image,
PikaVectors *vectors,
PikaContext *context,
GtkWidget *parent,
const gchar *title,
const gchar *role,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *vectors_name,
gboolean vectors_visible,
PikaColorTag vectors_color_tag,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gboolean vectors_lock_visibility,
PikaVectorsOptionsCallback callback,
gpointer user_data);
#endif /* __VECTORS_OPTIONS_DIALOG_H__ */

View File

@ -0,0 +1,647 @@
/* 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
*
* welcome-dialog.c
* Copyright (C) 2022 Jehan
*
* 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 <gegl.h>
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#include "libpikabase/pikabase.h"
#include "libpikawidgets/pikawidgets.h"
#include "dialogs-types.h"
#include "core/pika.h"
#include "core/pika-utils.h"
#include "widgets/pikawidgets-utils.h"
#include "welcome-dialog.h"
#include "welcome-dialog-data.h"
#include "pika-intl.h"
static void welcome_dialog_release_item_activated (GtkListBox *listbox,
GtkListBoxRow *row,
gpointer user_data);
static void welcome_add_link (GtkGrid *grid,
gint column,
gint *row,
const gchar *emoji,
const gchar *title,
const gchar *link);
static void welcome_size_allocate (GtkWidget *welcome_dialog,
GtkAllocation *allocation,
gpointer user_data);
GtkWidget *
welcome_dialog_create (Pika *pika)
{
GtkWidget *welcome_dialog;
GList *windows;
GtkWidget *main_vbox;
GtkWidget *stack;
GtkWidget *grid;
GtkWidget *switcher;
GtkWidget *scrolled_window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *image;
GtkWidget *listbox;
GtkWidget *widget;
gchar *release_link;
gchar *title;
gchar *markup;
gchar *tmp;
gint row;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
/* Translators: the %s string will be the version, e.g. "3.0". */
title = g_strdup_printf (_("Welcome to PIKA %s"), PIKA_VERSION);
windows = pika_get_image_windows (pika);
welcome_dialog = pika_dialog_new (title,
"pika-welcome-dialog",
windows ? windows->data : NULL,
0, NULL, NULL,
NULL);
g_list_free (windows);
gtk_window_set_position (GTK_WINDOW (welcome_dialog), GTK_WIN_POS_CENTER_ON_PARENT);
g_free (title);
g_signal_connect (welcome_dialog,
"response",
G_CALLBACK (gtk_widget_destroy),
NULL);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (welcome_dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
stack = gtk_stack_new ();
gtk_box_pack_start (GTK_BOX (main_vbox), stack, TRUE, TRUE, 0);
gtk_widget_show (stack);
/****************/
/* Welcome page */
/****************/
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_stack_add_titled (GTK_STACK (stack), vbox, "welcome",
_("Welcome"));
gtk_widget_show (vbox);
image = gtk_image_new_from_icon_name ("pika-mascot",
GTK_ICON_SIZE_DIALOG);
gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
g_signal_connect (welcome_dialog,
"size-allocate",
G_CALLBACK (welcome_size_allocate),
image);
/* Welcome title. */
/* Translators: the %s string will be the version, e.g. "3.0". */
tmp = g_strdup_printf (_("You installed PIKA %s!"), PIKA_VERSION);
markup = g_strdup_printf ("<big>%s</big>", tmp);
g_free (tmp);
widget = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (widget), markup);
g_free (markup);
gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_CENTER);
gtk_label_set_line_wrap (GTK_LABEL (widget), FALSE);
gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
grid = gtk_grid_new ();
gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
gtk_grid_set_row_spacing (GTK_GRID (grid), 0);
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
gtk_box_pack_start (GTK_BOX (vbox), grid, TRUE, TRUE, 0);
gtk_widget_show (grid);
/* Welcome message: left */
markup = _("PIKA is a Free Software for image authoring and manipulation.\n"
"Want to know more?");
widget = gtk_label_new (NULL);
gtk_label_set_max_width_chars (GTK_LABEL (widget), 30);
/*gtk_widget_set_size_request (widget, max_width / 2, -1);*/
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_widget_set_vexpand (widget, FALSE);
gtk_widget_set_hexpand (widget, FALSE);
/* Making sure the labels are well top aligned to avoid some ugly
* misalignment if left and right labels have different sizes,
* but also left-aligned so that the messages are slightly to the left
* of the emoji/link list below.
* Following design decisions by Aryeom.
*/
gtk_label_set_xalign (GTK_LABEL (widget), 0.0);
gtk_label_set_yalign (GTK_LABEL (widget), 0.0);
gtk_widget_set_margin_bottom (widget, 10);
gtk_label_set_markup (GTK_LABEL (widget), markup);
gtk_grid_attach (GTK_GRID (grid), widget, 0, 0, 1, 1);
gtk_widget_show (widget);
row = 1;
welcome_add_link (GTK_GRID (grid), 0, &row,
/* "globe with meridians" emoticone in UTF-8. */
"\xf0\x9f\x8c\x90",
_("PIKA website"), "https://heckin.technology/AlderconeStudio/PIKApp/");
welcome_add_link (GTK_GRID (grid), 0, &row,
/* "graduation cap" emoticone in UTF-8. */
"\xf0\x9f\x8e\x93",
_("Tutorials"),
"https://heckin.technology/AlderconeStudio/PIKApp/tutorials/");
welcome_add_link (GTK_GRID (grid), 0, &row,
/* "open book" emoticone in UTF-8. */
"\xf0\x9f\x93\x96",
_("Documentation"),
"https://docs.pika.org/");
/* XXX: should we add API docs for plug-in developers once it's
* properly set up? */
/* Welcome message: right */
markup = _("PIKA is a Community Software under the GNU general public license v3.\n"
"Want to contribute?");
widget = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_label_set_max_width_chars (GTK_LABEL (widget), 30);
/*gtk_widget_set_size_request (widget, max_width / 2, -1);*/
/* Again the alignments are important. */
gtk_label_set_xalign (GTK_LABEL (widget), 0.0);
gtk_widget_set_vexpand (widget, FALSE);
gtk_widget_set_hexpand (widget, FALSE);
gtk_label_set_xalign (GTK_LABEL (widget), 0.0);
gtk_label_set_yalign (GTK_LABEL (widget), 0.0);
gtk_widget_set_margin_bottom (widget, 10);
gtk_label_set_markup (GTK_LABEL (widget), markup);
gtk_grid_attach (GTK_GRID (grid), widget, 1, 0, 1, 1);
gtk_widget_show (widget);
row = 1;
welcome_add_link (GTK_GRID (grid), 1, &row,
/* "keyboard" emoticone in UTF-8. */
"\xe2\x8c\xa8",
_("Contributing"),
"https://heckin.technology/AlderconeStudio/PIKApp/develop/");
welcome_add_link (GTK_GRID (grid), 1, &row,
/* "love letter" emoticone in UTF-8. */
"\xf0\x9f\x92\x8c",
_("Donating"),
"https://heckin.technology/AlderconeStudio/PIKApp/donating/");
/*****************/
/* Release Notes */
/*****************/
if (pika_welcome_dialog_n_items > 0)
{
gint n_demos = 0;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_stack_add_titled (GTK_STACK (stack), vbox, "release-notes",
_("Release Notes"));
gtk_widget_show (vbox);
/* Release note title. */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* Translators: the %s string will be the version, e.g. "3.0". */
tmp = g_strdup_printf (_("PIKA %s Release Notes"), PIKA_VERSION);
markup = g_strdup_printf ("<b><big>%s</big></b>", tmp);
g_free (tmp);
widget = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (widget), markup);
g_free (markup);
gtk_label_set_selectable (GTK_LABEL (widget), FALSE);
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_CENTER);
gtk_label_set_line_wrap (GTK_LABEL (widget), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
image = gtk_image_new_from_icon_name ("pika-user-manual",
GTK_ICON_SIZE_DIALOG);
gtk_widget_set_valign (image, GTK_ALIGN_START);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
/* Release note introduction. */
if (pika_welcome_dialog_intro_n_paragraphs)
{
GString *introduction = NULL;
for (gint i = 0; i < pika_welcome_dialog_intro_n_paragraphs; i++)
{
if (i == 0)
introduction = g_string_new (_(pika_welcome_dialog_intro[i]));
else
g_string_append_printf (introduction, "\n%s",
_(pika_welcome_dialog_intro[i]));
}
widget = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (widget), introduction->str);
gtk_label_set_max_width_chars (GTK_LABEL (widget), 70);
gtk_label_set_selectable (GTK_LABEL (widget), FALSE);
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
g_string_free (introduction, TRUE);
}
/* Release note's change items. */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
gtk_widget_show (scrolled_window);
listbox = gtk_list_box_new ();
for (gint i = 0; i < pika_welcome_dialog_n_items; i++)
{
GtkWidget *row;
gchar *markup;
/* Add a bold dot for pretty listing. */
if (i < pika_welcome_dialog_n_items &&
pika_welcome_dialog_demos[i] != NULL)
{
markup = g_strdup_printf ("<span weight='ultrabold'>\xe2\x96\xb6</span> %s",
_((gchar *) pika_welcome_dialog_items[i]));
n_demos++;
}
else
{
markup = g_strdup_printf ("<span weight='ultrabold'>\xe2\x80\xa2</span> %s",
_((gchar *) pika_welcome_dialog_items[i]));
}
row = gtk_list_box_row_new ();
widget = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (widget), markup);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_label_set_xalign (GTK_LABEL (widget), 0.0);
gtk_container_add (GTK_CONTAINER (row), widget);
gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1);
gtk_widget_show_all (row);
g_free (markup);
}
gtk_container_add (GTK_CONTAINER (scrolled_window), listbox);
gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox),
GTK_SELECTION_NONE);
g_signal_connect (listbox, "row-activated",
G_CALLBACK (welcome_dialog_release_item_activated),
pika);
gtk_widget_show (listbox);
if (n_demos > 0)
{
/* A small explicative string to help discoverability of the demo
* ability.
*/
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
image = gtk_image_new_from_icon_name ("dialog-information",
GTK_ICON_SIZE_MENU);
gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_show (image);
widget = gtk_label_new (NULL);
tmp = g_strdup_printf (_("Click on release items with a %s bullet point to get a tour."),
"<span weight='ultrabold'>\xe2\x96\xb6</span>");
markup = g_strdup_printf ("<i>%s</i>", tmp);
g_free (tmp);
gtk_label_set_markup (GTK_LABEL (widget), markup);
g_free (markup);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
/* TODO: if a demo changed settings, should we add a "reset"
* button to get back to previous state?
*/
}
/* Link to full release notes on web site at the bottom. */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
if (PIKA_MINOR_VERSION % 2 == 0)
release_link = g_strdup_printf ("https://heckin.technology/AlderconeStudio/PIKApp/release-notes/pika-%d.%d.html",
PIKA_MAJOR_VERSION, PIKA_MINOR_VERSION);
else
release_link = g_strdup ("https://heckin.technology/AlderconeStudio/PIKApp/");
widget = gtk_link_button_new_with_label (release_link, _("Learn more"));
gtk_widget_show (widget);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
g_free (release_link);
/*****************/
/* Task switcher */
/*****************/
switcher = gtk_stack_switcher_new ();
gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher),
GTK_STACK (stack));
gtk_box_pack_start (GTK_BOX (main_vbox), switcher, FALSE, FALSE, 0);
gtk_widget_set_halign (switcher, GTK_ALIGN_CENTER);
gtk_widget_show (switcher);
}
/**************/
/* Info label */
/**************/
widget = gtk_label_new (NULL);
markup = g_strdup_printf ("<small>%s</small>",
_("This welcome dialog is only shown at first launch. "
"You can show it again from the \"Help\" menu."));
gtk_label_set_markup (GTK_LABEL (widget), markup);
g_free (markup);
gtk_widget_show (widget);
gtk_box_pack_start (GTK_BOX (main_vbox), widget, FALSE, FALSE, 0);
return welcome_dialog;
}
static void
welcome_dialog_release_item_activated (GtkListBox *listbox,
GtkListBoxRow *row,
gpointer user_data)
{
Pika *pika = user_data;
GList *blink_script = NULL;
const gchar *script_string;
gchar **script_steps;
gint row_index;
gint i;
row_index = gtk_list_box_row_get_index (row);
g_return_if_fail (row_index < pika_welcome_dialog_n_items);
script_string = pika_welcome_dialog_demos[row_index];
if (script_string == NULL)
/* Not an error. Some release items have no demos. */
return;
script_steps = g_strsplit (script_string, ",", 0);
for (i = 0; script_steps[i]; i++)
{
gchar **ids;
gchar *dockable_id = NULL;
gchar *widget_id = NULL;
gchar **settings = NULL;
gchar *settings_value = NULL;
ids = g_strsplit (script_steps[i], ":", 2);
/* Even if the string doesn't contain a second part, it is
* NULL-terminated, hence the widget_id will simply be NULL, which
* is fine when you just want to blink a dialog.
*/
dockable_id = ids[0];
widget_id = ids[1];
if (widget_id != NULL)
{
settings = g_strsplit (widget_id, "=", 2);
widget_id = settings[0];
settings_value = settings[1];
}
/* Allowing white spaces so that the demo in XML metadata can be
* spaced-out or even on multiple lines for clarity.
*/
dockable_id = g_strstrip (dockable_id);
if (widget_id != NULL)
widget_id = g_strstrip (widget_id);
/* All our dockable IDs start with "pika-". This allows to write
* shorter names in the demo script.
*/
if (! g_str_has_prefix (dockable_id, "pika-"))
{
gchar *tmp = g_strdup_printf ("pika-%s", dockable_id);
g_free (ids[0]);
dockable_id = ids[0] = tmp;
}
/* Blink widget. */
if (g_strcmp0 (dockable_id, "pika-toolbox") == 0)
{
/* All tool button IDs start with "tools-". This allows to
* write shorter tool names in the demo script.
*/
if (widget_id != NULL && ! g_str_has_prefix (widget_id, "tools-"))
{
gchar *tmp = g_strdup_printf ("tools-%s", widget_id);
g_free (settings[0]);
widget_id = settings[0] = tmp;
}
pika_blink_toolbox (pika, widget_id, &blink_script);
}
else
{
pika_blink_dockable (pika, dockable_id,
widget_id, settings_value,
&blink_script);
}
g_strfreev (ids);
if (settings)
g_strfreev (settings);
}
if (blink_script != NULL)
{
GList *windows = pika_get_image_windows (pika);
/* Losing forcus on the welcome dialog on purpose for the main GUI
* to be more readable.
*/
if (windows)
gtk_window_present (windows->data);
pika_blink_play_script (blink_script);
g_list_free (windows);
}
g_strfreev (script_steps);
}
static void
welcome_add_link (GtkGrid *grid,
gint column,
gint *row,
const gchar *emoji,
const gchar *title,
const gchar *link)
{
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *icon;
/* TODO: Aryeom doesn't like the spacing here. There is too much
* spacing between the link lines and between emojis and links. But we
* didn't manage to find how to close a bit these 2 spacings in GTK.
* :-/
*/
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_grid_attach (grid, hbox, column, *row, 1, 1);
/* These margin are by design to emphasize a bit the link list by
* moving them a tiny bit to the right instead of being exactly
* aligned with the top text.
*/
gtk_widget_set_margin_start (hbox, 10);
gtk_widget_show (hbox);
++(*row);
icon = gtk_label_new (emoji);
gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
gtk_widget_show (icon);
button = gtk_link_button_new_with_label (link, title);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
}
static void
welcome_size_allocate (GtkWidget *welcome_dialog,
GtkAllocation *allocation,
gpointer user_data)
{
GtkWidget *image = GTK_WIDGET (user_data);
GError *error = NULL;
GFile *splash_file;
GdkPixbuf *pixbuf;
GdkMonitor *monitor;
GdkRectangle workarea;
gint min_width;
gint min_height;
gint max_width;
gint max_height;
gint image_width;
gint image_height;
if (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_PIXBUF)
return;
monitor = pika_get_monitor_at_pointer ();
gdk_monitor_get_workarea (monitor, &workarea);
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()))
{
/* See the long comment in app/gui/splash.c on why we do this
* weird stuff for Wayland only.
* See also #5322.
*/
min_width = workarea.width / 8;
min_height = workarea.height / 8;
max_width = workarea.width / 4;
max_height = workarea.height / 4;
}
else
#endif
{
min_width = workarea.width / 4;
min_height = workarea.height / 4;
max_width = workarea.width / 2;
max_height = workarea.height / 2;
}
image_width = allocation->width + 20;
image_height = allocation->height + 20;
/* On big monitors, we get very huge images with a lot of empty space.
* So let's go with a logic so that we want a max and min size
* (relatively to desktop area), but we also want to avoid too much
* empty space. This is why we compute first the dialog size without
* any image in there.
*/
image_width = CLAMP (image_width, min_width, max_width);
image_height = CLAMP (image_height, min_height, max_height);
splash_file = pika_data_directory_file ("images", "pika-splash.png", NULL);
pixbuf = gdk_pixbuf_new_from_file_at_scale (g_file_peek_path (splash_file),
image_width, image_height,
TRUE, &error);
if (pixbuf)
{
gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
g_object_unref (pixbuf);
}
g_object_unref (splash_file);
gtk_widget_show (image);
gtk_window_set_resizable (GTK_WINDOW (welcome_dialog), FALSE);
}

View File

@ -0,0 +1,32 @@
/* 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
*
* welcome-dialog.h
* Copyright (C) 2022 Jehan
*
* 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/>.
*/
#ifndef __WELCOME_DIALOG_H__
#define __WELCOME_DIALOG_H__
GtkWidget * welcome_dialog_create (Pika *pika);
#endif /* __WELCOME_DIALOG_H__ */