Update upstream

This commit is contained in:
Cassowary 2023-12-02 11:03:24 -08:00
parent 84ea557696
commit d472f6348d
129 changed files with 17814 additions and 14162 deletions

View File

@ -184,19 +184,31 @@ static const PikaEnumActionEntry edit_paste_actions[] =
PIKA_HELP_EDIT_PASTE_IN_PLACE },
{ "edit-paste-into", PIKA_ICON_EDIT_PASTE_INTO,
NC_("edit-action", "Paste _Into Selection"), NULL, { NULL },
NC_("edit-action", "Paste as Floating Data _Into Selection"), NULL, { NULL },
NC_("edit-action",
"Paste the content of the clipboard into the current selection"),
PIKA_PASTE_TYPE_FLOATING_INTO, FALSE,
PIKA_HELP_EDIT_PASTE_INTO },
{ "edit-paste-into-in-place", PIKA_ICON_EDIT_PASTE_INTO,
NC_("edit-action", "Paste Int_o Selection In Place"), NULL, { NULL },
NC_("edit-action", "Paste as Floating Data Int_o Selection In Place"), NULL, { NULL },
NC_("edit-action",
"Paste the content of the clipboard into the current selection "
"at its original position"),
PIKA_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
PIKA_HELP_EDIT_PASTE_INTO_IN_PLACE }
PIKA_HELP_EDIT_PASTE_INTO_IN_PLACE },
{ "edit-paste-float", PIKA_ICON_EDIT_PASTE,
NC_("edit-action", "Paste as _Floating Data"), NULL, { NULL },
NC_("edit-action", "Paste the content of the clipboard as Floating Data"),
PIKA_PASTE_TYPE_FLOATING, FALSE,
PIKA_HELP_EDIT_PASTE },
{ "edit-paste-float-in-place", PIKA_ICON_EDIT_PASTE,
NC_("edit-action", "Paste as Floa_ting Data In Place"), NULL, { NULL },
NC_("edit-action", "Paste the content of the clipboard as Floating Data at its original position"),
PIKA_PASTE_TYPE_FLOATING_IN_PLACE, FALSE,
PIKA_HELP_EDIT_PASTE }
};
static const PikaEnumActionEntry edit_fill_actions[] =

View File

@ -972,7 +972,7 @@ layers_actions_update (PikaActionGroup *group,
SET_SENSITIVE ("layers-new", image);
SET_SENSITIVE ("layers-new-last-values", image);
SET_SENSITIVE ("layers-new-from-visible", image);
SET_SENSITIVE ("layers-new-group", image && !indexed);
SET_SENSITIVE ("layers-new-group", image && !indexed && !fs);
SET_SENSITIVE ("layers-duplicate", n_selected_layers > 0 && !fs && !ac);
SET_SENSITIVE ("layers-delete", n_selected_layers > 0 && !ac);

View File

@ -62,10 +62,16 @@ static const PikaActionEntry select_actions[] =
select_invert_cmd_callback,
PIKA_HELP_SELECTION_INVERT },
{ "select-float", PIKA_ICON_LAYER_FLOATING_SELECTION,
NC_("select-action", "_Float"), NULL, { "<primary><shift>L", NULL },
NC_("select-action", "Create a floating selection"),
select_float_cmd_callback,
{ "select-cut-float", PIKA_ICON_LAYER_FLOATING_SELECTION,
NC_("select-action", "Cu_t and Float"), NULL, { "<primary><shift>L", NULL },
NC_("select-action", "Cut the selection directly into a floating selection"),
select_cut_float_cmd_callback,
PIKA_HELP_SELECTION_FLOAT },
{ "select-copy-float", PIKA_ICON_LAYER_FLOATING_SELECTION,
NC_("select-action", "_Copy and Float"), NULL, { NULL },
NC_("select-action", "Copy the selection directly into a floating selection"),
select_copy_float_cmd_callback,
PIKA_HELP_SELECTION_FLOAT },
{ "select-feather", NULL,
@ -186,9 +192,13 @@ select_actions_update (PikaActionGroup *group,
SET_SENSITIVE ("select-all", image && ! sel_all);
SET_SENSITIVE ("select-none", image && sel);
SET_SENSITIVE ("select-invert", image);
SET_SENSITIVE ("select-float", g_list_length (drawables) == 1 && sel &&
! pika_item_is_content_locked (drawables->data, NULL) &&
! pika_viewable_get_children (drawables->data));
SET_SENSITIVE ("select-cut-float", g_list_length (drawables) == 1 && sel &&
! pika_item_is_content_locked (drawables->data, NULL) &&
! pika_viewable_get_children (drawables->data));
SET_SENSITIVE ("select-copy-float", g_list_length (drawables) == 1 && sel &&
! pika_item_is_content_locked (drawables->data, NULL) &&
! pika_viewable_get_children (drawables->data));
SET_SENSITIVE ("select-feather", image && sel);
SET_SENSITIVE ("select-sharpen", image && sel);

View File

@ -71,6 +71,10 @@ static void select_shrink_callback (GtkWidget *widget,
gdouble size,
PikaUnit unit,
gpointer data);
static void select_float (PikaAction *action,
GVariant *value,
gboolean cut,
gpointer data);
/* public functions */
@ -112,33 +116,19 @@ select_invert_cmd_callback (PikaAction *action,
}
void
select_float_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data)
select_cut_float_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data)
{
PikaImage *image;
GtkWidget *widget;
GList *drawables;
GError *error = NULL;
return_if_no_image (image, data);
return_if_no_widget (widget, data);
select_float (action, value, TRUE, data);
}
drawables = pika_image_get_selected_drawables (image);
if (pika_selection_float (PIKA_SELECTION (pika_image_get_mask (image)),
drawables,
action_data_get_context (data),
TRUE, 0, 0, &error))
{
pika_image_flush (image);
}
else
{
pika_message_literal (image->pika,
G_OBJECT (widget), PIKA_MESSAGE_WARNING,
error->message);
g_clear_error (&error);
}
g_list_free (drawables);
void
select_copy_float_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data)
{
select_float (action, value, FALSE, data);
}
void
@ -696,3 +686,34 @@ select_shrink_callback (GtkWidget *widget,
TRUE);
pika_image_flush (image);
}
static void
select_float (PikaAction *action,
GVariant *value,
gboolean cut,
gpointer data)
{
PikaImage *image;
GtkWidget *widget;
GList *drawables;
GError *error = NULL;
return_if_no_image (image, data);
return_if_no_widget (widget, data);
drawables = pika_image_get_selected_drawables (image);
if (pika_selection_float (PIKA_SELECTION (pika_image_get_mask (image)),
drawables,
action_data_get_context (data),
cut, 0, 0, &error))
{
pika_image_flush (image);
}
else
{
pika_message_literal (image->pika,
G_OBJECT (widget), PIKA_MESSAGE_WARNING,
error->message);
g_clear_error (&error);
}
g_list_free (drawables);
}

View File

@ -32,7 +32,10 @@ void select_none_cmd_callback (PikaAction *action,
void select_invert_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data);
void select_float_cmd_callback (PikaAction *action,
void select_cut_float_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data);
void select_copy_float_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data);
void select_feather_cmd_callback (PikaAction *action,

View File

@ -98,6 +98,7 @@ enum
PROP_GLOBAL_PALETTE,
PROP_GLOBAL_GRADIENT,
PROP_GLOBAL_FONT,
PROP_GLOBAL_EXPAND,
PROP_DEFAULT_IMAGE,
PROP_DEFAULT_GRID,
PROP_UNDO_LEVELS,
@ -540,6 +541,13 @@ pika_core_config_class_init (PikaCoreConfigClass *klass)
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_GLOBAL_EXPAND,
"global-expand",
"Global expand",
GLOBAL_EXPAND_BLURB,
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PROP_DEFAULT_IMAGE,
"default-image",
"Default image",
@ -1061,6 +1069,9 @@ pika_core_config_set_property (GObject *object,
case PROP_GLOBAL_FONT:
core_config->global_font = g_value_get_boolean (value);
break;
case PROP_GLOBAL_EXPAND:
core_config->global_expand = g_value_get_boolean (value);
break;
case PROP_DEFAULT_IMAGE:
if (g_value_get_object (value))
pika_config_sync (g_value_get_object (value) ,
@ -1337,6 +1348,9 @@ pika_core_config_get_property (GObject *object,
case PROP_GLOBAL_FONT:
g_value_set_boolean (value, core_config->global_font);
break;
case PROP_GLOBAL_EXPAND:
g_value_set_boolean (value, core_config->global_expand);
break;
case PROP_DEFAULT_IMAGE:
g_value_set_object (value, core_config->default_image);
break;

View File

@ -82,6 +82,7 @@ struct _PikaCoreConfig
gboolean global_palette;
gboolean global_gradient;
gboolean global_font;
gboolean global_expand;
PikaTemplate *default_image;
PikaGrid *default_grid;
gint levels_of_undo;

View File

@ -181,6 +181,9 @@ _("When enabled, the selected pattern will be used for all tools.")
#define GLOBAL_PALETTE_BLURB \
"When enabled, the selected palette will be used for all tools."
#define GLOBAL_EXPAND_BLURB \
"When enabled, the selected auto expand layer settings will be used for all tools."
#define GRADIENT_PATH_BLURB \
"Sets the gradient search path."

View File

@ -715,6 +715,7 @@ typedef enum /*< pdb-skip, skip >*/
PIKA_CONTEXT_PROP_BUFFER = 18,
PIKA_CONTEXT_PROP_IMAGEFILE = 19,
PIKA_CONTEXT_PROP_TEMPLATE = 20,
PIKA_CONTEXT_PROP_EXPAND = 21,
PIKA_CONTEXT_PROP_LAST = PIKA_CONTEXT_PROP_TEMPLATE
} PikaContextPropType;
@ -741,6 +742,7 @@ typedef enum /*< pdb-skip, skip >*/
PIKA_CONTEXT_PROP_MASK_BUFFER = 1 << 18,
PIKA_CONTEXT_PROP_MASK_IMAGEFILE = 1 << 19,
PIKA_CONTEXT_PROP_MASK_TEMPLATE = 1 << 20,
PIKA_CONTEXT_PROP_MASK_EXPAND = 1 << 21,
/* aliases */
PIKA_CONTEXT_PROP_MASK_PAINT = (PIKA_CONTEXT_PROP_MASK_FOREGROUND |
@ -750,7 +752,8 @@ typedef enum /*< pdb-skip, skip >*/
PIKA_CONTEXT_PROP_MASK_BRUSH |
PIKA_CONTEXT_PROP_MASK_DYNAMICS |
PIKA_CONTEXT_PROP_MASK_PATTERN |
PIKA_CONTEXT_PROP_MASK_GRADIENT),
PIKA_CONTEXT_PROP_MASK_GRADIENT |
PIKA_CONTEXT_PROP_MASK_EXPAND),
PIKA_CONTEXT_PROP_MASK_ALL = (PIKA_CONTEXT_PROP_MASK_IMAGE |
PIKA_CONTEXT_PROP_MASK_DISPLAY |

View File

@ -557,6 +557,9 @@ user_update_menurc_over20 (const GMatchInfo *matched_value,
else if (g_strcmp0 (action_match, "view-rotate-reset") == 0 &&
install->old_major == 2)
new_action_name = g_strdup ("view-reset");
/* select-float became select-cut-float in 3.0 (select-copy-float added). */
else if (g_strcmp0 (action_match, "select-float") == 0)
new_action_name = g_strdup ("select-cut-float");
if (new_action_name == NULL)
new_action_name = g_strdup (action_match);

View File

@ -286,7 +286,8 @@ pika_brush_get_new_preview (PikaViewable *viewable,
guchar *mask;
guchar *buf;
gint x, y;
gboolean scaled = FALSE;
gboolean free_mask = FALSE;
gdouble scale = 1.0;
mask_width = pika_temp_buf_get_width (mask_buf);
mask_height = pika_temp_buf_get_height (mask_buf);
@ -295,45 +296,47 @@ pika_brush_get_new_preview (PikaViewable *viewable,
{
gdouble ratio_x = (gdouble) width / (gdouble) mask_width;
gdouble ratio_y = (gdouble) height / (gdouble) mask_height;
gdouble scale = MIN (ratio_x, ratio_y);
if (scale != 1.0)
scale = MIN (ratio_x, ratio_y);
}
if (PIKA_IS_BRUSH_GENERATED (brush) || scale != 1.0)
{
pika_brush_begin_use (brush);
if (PIKA_IS_BRUSH_GENERATED (brush))
{
pika_brush_begin_use (brush);
PikaBrushGenerated *gen_brush = PIKA_BRUSH_GENERATED (brush);
if (PIKA_IS_BRUSH_GENERATED (brush))
{
PikaBrushGenerated *gen_brush = PIKA_BRUSH_GENERATED (brush);
mask_buf = pika_brush_transform_mask (brush, scale,
(pika_brush_generated_get_aspect_ratio (gen_brush) - 1.0) * 20.0 / 19.0,
pika_brush_generated_get_angle (gen_brush) / -360.0,
FALSE,
pika_brush_generated_get_hardness (gen_brush));
}
else
{
mask_buf = pika_brush_transform_mask (brush, scale, 0.0, 0.0, FALSE, 1.0);
}
mask_buf = pika_brush_transform_mask (brush, scale,
(pika_brush_generated_get_aspect_ratio (gen_brush) - 1.0) * 20.0 / 19.0,
pika_brush_generated_get_angle (gen_brush) / 360.0,
FALSE,
pika_brush_generated_get_hardness (gen_brush));
}
else
mask_buf = pika_brush_transform_mask (brush, scale,
if (! mask_buf)
{
mask_buf = pika_temp_buf_new (1, 1, babl_format ("Y u8"));
pika_temp_buf_data_clear ((PikaTempBuf *) mask_buf);
}
else
{
pika_temp_buf_ref ((PikaTempBuf *) mask_buf);
}
if (pixmap_buf)
pixmap_buf = pika_brush_transform_pixmap (brush, scale,
0.0, 0.0, FALSE, 1.0);
if (! mask_buf)
{
mask_buf = pika_temp_buf_new (1, 1, babl_format ("Y u8"));
pika_temp_buf_data_clear ((PikaTempBuf *) mask_buf);
}
else
{
pika_temp_buf_ref ((PikaTempBuf *) mask_buf);
}
mask_width = pika_temp_buf_get_width (mask_buf);
mask_height = pika_temp_buf_get_height (mask_buf);
if (pixmap_buf)
pixmap_buf = pika_brush_transform_pixmap (brush, scale,
0.0, 0.0, FALSE, 1.0);
mask_width = pika_temp_buf_get_width (mask_buf);
mask_height = pika_temp_buf_get_height (mask_buf);
scaled = TRUE;
}
free_mask = TRUE;
}
return_buf = pika_temp_buf_new (mask_width, mask_height,
@ -381,7 +384,7 @@ pika_brush_get_new_preview (PikaViewable *viewable,
pika_temp_buf_unlock (mask_buf, mask_data);
if (scaled)
if (free_mask)
{
pika_temp_buf_unref ((PikaTempBuf *) mask_buf);

View File

@ -747,7 +747,7 @@ pika_channel_resize (PikaItem *item,
gint offset_x,
gint offset_y)
{
PIKA_ITEM_CLASS (parent_class)->resize (item, context, PIKA_FILL_TRANSPARENT,
PIKA_ITEM_CLASS (parent_class)->resize (item, context, fill_type,
new_width, new_height,
offset_x, offset_y);

View File

@ -45,6 +45,8 @@ struct _PikaDrawablePrivate
GeglBuffer *paint_buffer;
cairo_region_t *paint_copy_region;
cairo_region_t *paint_update_region;
gboolean push_resize_undo;
};
#endif /* __PIKA_DRAWABLE_PRIVATE_H__ */

View File

@ -632,7 +632,10 @@ pika_drawable_resize (PikaItem *item,
copy_y - new_offset_y, 0, 0));
}
pika_drawable_set_buffer_full (drawable, pika_item_is_attached (item), NULL,
pika_drawable_set_buffer_full (drawable,
pika_item_is_attached (item) &&
drawable->private->push_resize_undo,
NULL,
new_buffer,
GEGL_RECTANGLE (new_offset_x, new_offset_y,
0, 0),
@ -910,6 +913,10 @@ pika_drawable_real_set_buffer (PikaDrawable *drawable,
}
g_set_object (&drawable->private->buffer, buffer);
if (pika_drawable_is_painting (drawable))
g_set_object (&drawable->private->paint_buffer, buffer);
g_clear_object (&drawable->private->format_profile);
if (drawable->private->buffer_source_node)
@ -1076,6 +1083,8 @@ pika_drawable_new (GType type,
pika_drawable_set_buffer (drawable, FALSE, NULL, buffer);
g_object_unref (buffer);
pika_drawable_enable_resize_undo (drawable);
return drawable;
}
@ -1676,6 +1685,22 @@ pika_drawable_push_undo (PikaDrawable *drawable,
x, y, width, height);
}
void
pika_drawable_disable_resize_undo (PikaDrawable *drawable)
{
g_return_if_fail (PIKA_IS_DRAWABLE (drawable));
drawable->private->push_resize_undo = FALSE;
}
void
pika_drawable_enable_resize_undo (PikaDrawable *drawable)
{
g_return_if_fail (PIKA_IS_DRAWABLE (drawable));
drawable->private->push_resize_undo = TRUE;
}
const Babl *
pika_drawable_get_space (PikaDrawable *drawable)
{

View File

@ -209,6 +209,9 @@ void pika_drawable_push_undo (PikaDrawable *drawable,
gint width,
gint height);
void pika_drawable_disable_resize_undo (PikaDrawable *drawable);
void pika_drawable_enable_resize_undo (PikaDrawable *drawable);
const Babl * pika_drawable_get_space (PikaDrawable *drawable);
const Babl * pika_drawable_get_format (PikaDrawable *drawable);
const Babl * pika_drawable_get_format_with_alpha(PikaDrawable *drawable);

View File

@ -1083,9 +1083,6 @@ pika_palette_load_ase (PikaContext *context,
}
g_free (palette_name);
/* Header blocks are considered a "color" so we offset the count here */
num_cols -= 1;
for (i = 0; i < num_cols; i++)
{
gchar color_space[4];
@ -1108,6 +1105,23 @@ pika_palette_load_ase (PikaContext *context,
}
skip_first = FALSE;
/* Skip group marker padding */
group = GINT16_FROM_BE (group);
if (group < 0)
{
gchar marker[4];
if (! g_input_stream_read_all (input, &marker, sizeof (marker),
&bytes_read, NULL, error))
{
g_printerr ("Invalid ASE group marker: %s.",
pika_file_get_utf8_name (file));
break;
}
num_cols--;
continue;
}
color_name = pika_palette_load_ase_block_name (input, file_size, error);
if (! color_name)
break;
@ -1148,7 +1162,7 @@ pika_palette_load_ase (PikaContext *context,
for (gint j = 0; j < components; j++)
{
gint tmp;
gint32 tmp;
if (! g_input_stream_read_all (input, &tmp, sizeof (tmp),
&bytes_read, NULL, error))
@ -1162,7 +1176,7 @@ pika_palette_load_ase (PikaContext *context,
/* Convert 4 bytes to a 32bit float value */
tmp = GINT32_FROM_BE (tmp);
pixels[j] = *(gfloat *) &tmp;
memcpy (&pixels[j], &tmp, 4);
}
if (! valid_color)

View File

@ -2,7 +2,7 @@
* 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):
* 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
@ -34,6 +34,8 @@
#include "config/pikacoreconfig.h"
#include "widgets/pikawidgets-utils.h"
#include "about.h"
#include "git-version.h"
@ -45,22 +47,34 @@
#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 *dialog;
Pika *pika;
GtkWidget *update_frame;
PikaCoreConfig *config;
GtkWidget *anim_area;
PangoLayout *layout;
GtkWidget *anim_area;
PangoLayout *layout;
guint timer;
gint n_authors;
gint shuffle[G_N_ELEMENTS (authors) - 1]; /* NULL terminated */
gint index;
gint animstep;
gint state;
gboolean visible;
guint timer;
gint index;
gint animstep;
gint state;
gboolean visible;
} PikaAboutDialog;
@ -93,7 +107,8 @@ static void about_dialog_download_clicked
const gchar *link);
GtkWidget *
about_dialog_create (PikaCoreConfig *config)
about_dialog_create (Pika *pika,
PikaCoreConfig *config)
{
static PikaAboutDialog dialog;
@ -106,6 +121,8 @@ about_dialog_create (PikaCoreConfig *config)
gchar *copyright;
gchar *version;
dialog.pika = pika;
dialog.n_authors = G_N_ELEMENTS (authors) - 1;
dialog.config = config;
pixbuf = about_dialog_load_logo ();
@ -134,6 +151,9 @@ about_dialog_create (PikaCoreConfig *config)
"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"),
@ -196,6 +216,10 @@ about_dialog_map (GtkWidget *widget,
dialog->timer = g_timeout_add (800, about_dialog_timer, dialog);
}
#ifdef G_OS_WIN32
pika_window_set_title_bar_theme (dialog->pika, widget, FALSE);
#endif
}
static void
@ -466,6 +490,27 @@ about_dialog_add_update (PikaAboutDialog *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
@ -642,11 +687,17 @@ about_dialog_timer (gpointer data)
return FALSE;
case 1:
text = insert_spacers (_("PIKA is brought to you by Aldercone Studio"));
text = insert_spacers (_("PIKA is brought to you by"));
dialog->state += 1;
break;
case 2:
return FALSE;
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);

View File

@ -23,7 +23,8 @@
#define __ABOUT_DIALOG_H__
GtkWidget * about_dialog_create (PikaCoreConfig *config);
GtkWidget * about_dialog_create (Pika *pika,
PikaCoreConfig *config);
#endif /* __ABOUT_DIALOG_H__ */

View File

@ -221,7 +221,7 @@ dialogs_about_get (PikaDialogFactory *factory,
PikaUIManager *ui_manager,
gint view_size)
{
return about_dialog_create (context->pika);
return about_dialog_create (context->pika, context->pika->edit_config);
}
GtkWidget *

View File

@ -1856,6 +1856,9 @@ prefs_dialog_new (Pika *pika,
prefs_check_button_add_with_icon (object, "global-gradient",
_("_Gradient"), PIKA_ICON_GRADIENT,
GTK_BOX (vbox2), size_group);
prefs_check_button_add_with_icon (object, "global-expand",
_("E_xpand Layers"), PIKA_ICON_TOOL_SCALE,
GTK_BOX (vbox2), size_group);
/* Move Tool */
vbox2 = prefs_frame_new (_("Move Tool"),

View File

@ -46,6 +46,11 @@ static void pika_display_bounds_changed_handler (PikaImage *image,
gint old_x,
gint old_y,
PikaDisplay *display);
static void pika_display_flush_handler (PikaImage *image,
gboolean invalidate_preview,
PikaDisplay *display);
static gboolean
pika_display_flush_handler_idle (gpointer user_data);
/* public functions */
@ -122,3 +127,23 @@ pika_display_bounds_changed_handler (PikaImage *image,
{
pika_display_update_bounding_box (display);
}
static void
pika_display_flush_handler (PikaImage *image,
gboolean invalidate_preview,
PikaDisplay *display)
{
g_idle_add_full (G_PRIORITY_LOW,
(GSourceFunc) pika_display_flush_handler_idle,
g_object_ref (display), g_object_unref);
}
static gboolean
pika_display_flush_handler_idle (gpointer user_data)
{
PikaDisplay *display = user_data;
pika_display_flush (display);
return G_SOURCE_REMOVE;
}

View File

@ -26,13 +26,19 @@
#include <string.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <gegl-plugin.h>
#include "libpikacolor/pikacolor.h"
#include "pika-gegl-types.h"
#include "core/pikapattern.h"
#include "core/pikaprogress.h"
#include "pika-babl.h"
#include "pika-gegl-loops.h"
#include "pika-gegl-utils.h"
@ -337,6 +343,100 @@ pika_gegl_buffer_dup (GeglBuffer *buffer)
return new_buffer;
}
GeglBuffer *
pika_gegl_buffer_resize (GeglBuffer *buffer,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y,
PikaRGB *color,
PikaPattern *pattern,
gint pattern_offset_x,
gint pattern_offset_y)
{
GeglBuffer *new_buffer;
gboolean intersect;
GeglRectangle copy_rect;
const GeglRectangle *extent;
const Babl *format;
g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
extent = gegl_buffer_get_extent (buffer);
format = gegl_buffer_get_format (buffer);
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height),
format);
intersect = gegl_rectangle_intersect (&copy_rect,
GEGL_RECTANGLE (0, 0, extent->width,
extent->height),
GEGL_RECTANGLE (offset_x, offset_y,
new_width, new_height));
if (! intersect ||
copy_rect.width != new_width ||
copy_rect.height != new_height)
{
/* Clear the new buffer if needed and color/pattern is given */
if (pattern)
{
GeglBuffer *src_buffer;
GeglBuffer *dest_buffer;
PikaColorProfile *src_profile;
PikaColorProfile *dest_profile;
src_buffer = pika_pattern_create_buffer (pattern);
src_profile = pika_babl_format_get_color_profile (
gegl_buffer_get_format (src_buffer));
dest_profile = pika_babl_format_get_color_profile (
gegl_buffer_get_format (new_buffer));
if (pika_color_transform_can_gegl_copy (src_profile, dest_profile))
{
dest_buffer = g_object_ref (src_buffer);
}
else
{
dest_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer),
gegl_buffer_get_format (new_buffer));
pika_gegl_convert_color_profile (src_buffer, NULL, src_profile,
dest_buffer, NULL, dest_profile,
PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL,
TRUE, NULL);
}
g_object_unref (src_profile);
g_object_unref (dest_profile);
gegl_buffer_set_pattern (new_buffer, NULL, dest_buffer,
pattern_offset_x, pattern_offset_y);
g_object_unref (src_buffer);
g_object_unref (dest_buffer);
}
else if (color)
{
GeglColor *gegl_color;
gegl_color = pika_gegl_color_new (color, gegl_buffer_get_format (buffer));
gegl_buffer_set_color (new_buffer, NULL, gegl_color);
g_object_unref (gegl_color);
}
}
if (intersect && copy_rect.width && copy_rect.height)
{
/* Copy the pixels in the intersection */
pika_gegl_buffer_copy (buffer, &copy_rect, GEGL_ABYSS_NONE, new_buffer,
GEGL_RECTANGLE (copy_rect.x - offset_x,
copy_rect.y - offset_y, 0, 0));
}
return new_buffer;
}
gboolean
pika_gegl_buffer_set_extent (GeglBuffer *buffer,
const GeglRectangle *extent)

View File

@ -59,6 +59,15 @@ gboolean pika_gegl_param_spec_has_key (GParamSpec *pspe
const gchar *value);
GeglBuffer * pika_gegl_buffer_dup (GeglBuffer *buffer);
GeglBuffer * pika_gegl_buffer_resize (GeglBuffer *buffer,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y,
PikaRGB *color,
PikaPattern *pattern,
gint pattern_offset_x,
gint pattern_offset_y);
gboolean pika_gegl_buffer_set_extent (GeglBuffer *buffer,
const GeglRectangle *extent);

View File

@ -85,5 +85,12 @@ typedef enum /*< skip, pdb-skip >*/
PIKA_PAINT_STATE_FINISH /* Cleanup and/or reset PaintFunc operation */
} PikaPaintState;
/* State of lock blinking */
typedef enum /*< skip, pdb-skip >*/
{
PIKA_PAINT_LOCK_NOT_BLINKED,
PIKA_PAINT_LOCK_BLINK_PENDING,
PIKA_PAINT_LOCK_BLINKED,
} PikaPaintLockBlinkState;
#endif /* __PAINT_ENUMS_H__ */

View File

@ -819,6 +819,8 @@ pika_brush_core_get_paint_buffer (PikaPaintCore *paint_core,
gint x1, y1, x2, y2;
gint drawable_width, drawable_height;
gint brush_width, brush_height;
gint offset_change_x, offset_change_y;
PikaCoords new_coords;
pika_brush_transform_size (core->brush,
core->scale, core->aspect_ratio,
@ -835,11 +837,31 @@ pika_brush_core_get_paint_buffer (PikaPaintCore *paint_core,
x = (gint) floor (coords->x) - (brush_width / 2);
y = (gint) floor (coords->y) - (brush_height / 2);
x1 = x - 1;
y1 = y - 1;
x2 = x + brush_width + 1;
y2 = y + brush_height + 1;
pika_paint_core_expand_drawable (paint_core, drawable, paint_options,
x1, x2, y1, y2,
&offset_change_x, &offset_change_y);
if (offset_change_x || offset_change_y)
{
x += offset_change_x;
y += offset_change_y;
new_coords = *coords;
new_coords.x = coords->x + offset_change_x;
new_coords.y = coords->y + offset_change_y;
pika_symmetry_set_origin (paint_core->sym, drawable, &new_coords);
}
drawable_width = pika_item_get_width (PIKA_ITEM (drawable));
drawable_height = pika_item_get_height (PIKA_ITEM (drawable));
x1 = CLAMP (x - 1, 0, drawable_width);
y1 = CLAMP (y - 1, 0, drawable_height);
x1 = CLAMP (x - 1, 0, drawable_width);
y1 = CLAMP (y - 1, 0, drawable_height);
x2 = CLAMP (x + brush_width + 1, 0, drawable_width);
y2 = CLAMP (y + brush_height + 1, 0, drawable_height);

View File

@ -470,6 +470,21 @@ pika_blob_duplicate (PikaBlob *b)
return g_memdup2 (b, sizeof (PikaBlob) + sizeof (PikaBlobSpan) * (b->height - 1));
}
void
pika_blob_move (PikaBlob *b,
gint x,
gint y)
{
gint i = 0;
b->y += y;
for (i = 0; i < b->height; i++)
{
b->data[i].left += x;
b->data[i].right += x;
}
}
#if 0
void
pika_blob_dump (PikaBlob *b)

View File

@ -86,6 +86,9 @@ void pika_blob_bounds (PikaBlob *b,
PikaBlob * pika_blob_convex_union (PikaBlob *b1,
PikaBlob *b2);
PikaBlob * pika_blob_duplicate (PikaBlob *b);
void pika_blob_move (PikaBlob *b,
gint x,
gint y);
#endif /* __PIKA_INK_BLOB_H__ */

View File

@ -242,17 +242,49 @@ pika_ink_get_paint_buffer (PikaPaintCore *paint_core,
gint *paint_width,
gint *paint_height)
{
PikaInk *ink = PIKA_INK (paint_core);
gint x, y;
gint width, height;
gint dwidth, dheight;
gint x1, y1, x2, y2;
PikaInk *ink = PIKA_INK (paint_core);
gint x, y;
gint width, height;
gint dwidth, dheight;
gint x1, y1, x2, y2;
gint offset_change_x, offset_change_y;
PikaCoords new_coords;
GList *iter;
pika_blob_bounds (ink->cur_blob, &x, &y, &width, &height);
x1 = x / SUBSAMPLE - 1;
y1 = y / SUBSAMPLE - 1;
x2 = (x + width) / SUBSAMPLE + 2;
y2 = (y + height) / SUBSAMPLE + 2;
pika_paint_core_expand_drawable (paint_core, drawable, paint_options,
x1, x2, y1, y2,
&offset_change_x, &offset_change_y);
dwidth = pika_item_get_width (PIKA_ITEM (drawable));
dheight = pika_item_get_height (PIKA_ITEM (drawable));
if (offset_change_x || offset_change_y)
{
x += SUBSAMPLE * offset_change_x;
y += SUBSAMPLE * offset_change_y;
new_coords = *coords;
new_coords.x = coords->x + offset_change_x;
new_coords.y = coords->y + offset_change_y;
pika_symmetry_set_origin (paint_core->sym, drawable, &new_coords);
for (iter = ink->blobs_to_render; iter; iter = g_list_next (iter))
pika_blob_move (iter->data,
SUBSAMPLE * offset_change_x,
SUBSAMPLE * offset_change_y);
for (iter = ink->last_blobs; iter; iter = g_list_next (iter))
pika_blob_move (iter->data,
SUBSAMPLE * offset_change_x,
SUBSAMPLE * offset_change_y);
}
x1 = CLAMP (x / SUBSAMPLE - 1, 0, dwidth);
y1 = CLAMP (y / SUBSAMPLE - 1, 0, dheight);
x2 = CLAMP ((x + width) / SUBSAMPLE + 2, 0, dwidth);
@ -319,7 +351,6 @@ pika_ink_motion (PikaPaintCore *paint_core,
PikaInk *ink = PIKA_INK (paint_core);
PikaInkOptions *options = PIKA_INK_OPTIONS (paint_options);
PikaContext *context = PIKA_CONTEXT (paint_options);
GList *blob_unions = NULL;
GList *blobs_to_render = NULL;
GeglBuffer *paint_buffer;
gint paint_buffer_x;
@ -338,6 +369,7 @@ pika_ink_motion (PikaPaintCore *paint_core,
coords.x -= off_x;
coords.y -= off_y;
pika_symmetry_set_origin (sym, drawable, &coords);
paint_core->sym = sym;
n_strokes = pika_symmetry_get_size (sym);
@ -377,7 +409,8 @@ pika_ink_motion (PikaPaintCore *paint_core,
last_blob);
ink->start_blobs = g_list_prepend (ink->start_blobs,
pika_blob_duplicate (last_blob));
blobs_to_render = g_list_prepend (blobs_to_render, last_blob);
blobs_to_render = g_list_prepend (blobs_to_render,
pika_blob_duplicate (last_blob));
}
ink->start_blobs = g_list_reverse (ink->start_blobs);
ink->last_blobs = g_list_reverse (ink->last_blobs);
@ -411,7 +444,6 @@ pika_ink_motion (PikaPaintCore *paint_core,
g_list_nth (ink->last_blobs, i)->data = blob;
blobs_to_render = g_list_prepend (blobs_to_render, blob_union);
blob_unions = g_list_prepend (blob_unions, blob_union);
}
blobs_to_render = g_list_reverse (blobs_to_render);
}
@ -422,6 +454,7 @@ pika_ink_motion (PikaPaintCore *paint_core,
pika_pickable_srgb_to_image_color (PIKA_PICKABLE (drawable),
&foreground, &foreground);
color = pika_gegl_color_new (&foreground, pika_drawable_get_space (drawable));
ink->blobs_to_render = blobs_to_render;
for (i = 0; i < n_strokes; i++)
{
@ -467,8 +500,7 @@ pika_ink_motion (PikaPaintCore *paint_core,
g_object_unref (color);
g_list_free_full (blob_unions, g_free);
g_list_free (blobs_to_render);
g_list_free_full (blobs_to_render, g_free);
}
static PikaBlob *

View File

@ -41,10 +41,11 @@ struct _PikaInk
{
PikaPaintCore parent_instance;
GList *start_blobs; /* starting blobs per stroke (for undo) */
GList *start_blobs; /* starting blobs per stroke (for undo) */
PikaBlob *cur_blob; /* current blob */
GList *last_blobs; /* blobs for last stroke positions */
PikaBlob *cur_blob; /* current blob */
GList *last_blobs; /* blobs for last stroke positions */
GList *blobs_to_render;
};
struct _PikaInkClass

View File

@ -259,7 +259,7 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
{
PikaMybrushCore *mybrush = PIKA_MYBRUSH_CORE (paint_core);
MyPaintRectangle rect;
PikaCoords coords;
PikaCoords origin;
GList *iter;
gdouble dt = 0.0;
gint off_x, off_y;
@ -269,10 +269,10 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
n_strokes = pika_symmetry_get_size (sym);
coords = *(pika_symmetry_get_origin (sym));
coords.x -= off_x;
coords.y -= off_y;
pika_symmetry_set_origin (sym, drawable, &coords);
origin = *(pika_symmetry_get_origin (sym));
origin.x -= off_x;
origin.y -= off_y;
pika_symmetry_set_origin (sym, drawable, &origin);
/* The number of strokes may change during a motion, depending on
* the type of symmetry. When that happens, reset the brushes.
@ -291,9 +291,8 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
iter;
iter = g_list_next (iter), i++)
{
MyPaintBrush *brush = iter->data;
coords = *(pika_symmetry_get_coords (sym, i));
MyPaintBrush *brush = iter->data;
PikaCoords coords = *(pika_symmetry_get_coords (sym, i));
mypaint_brush_stroke_to (brush,
(MyPaintSurface *) mybrush->private->surface,
@ -326,6 +325,42 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
MyPaintBrush *brush = iter->data;
PikaCoords coords = *(pika_symmetry_get_coords (sym, i));
gdouble pressure = coords.pressure;
gboolean expanded;
gfloat radius = 100;
gint x1, x2, y1, y2;
gint offset_change_x, offset_change_y;
gint off_x_surf, off_y_surf;
gint off_x, off_y;
x1 = coords.x - radius;
y1 = coords.y - radius;
x2 = coords.x + radius;
y2 = coords.y + radius;
expanded = pika_paint_core_expand_drawable (paint_core, drawable, paint_options,
x1, x2, y1, y2,
&offset_change_x, &offset_change_y);
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
if (expanded)
pika_mypaint_surface_set_buffer (mybrush->private->surface, pika_drawable_get_buffer (drawable),
off_x, off_y);
pika_mypaint_surface_get_offset (mybrush->private->surface, &off_x_surf, &off_y_surf);
coords.x -= off_x_surf;
coords.y -= off_y_surf;
if (offset_change_x || offset_change_y)
{
pika_mypaint_surface_set_offset (mybrush->private->surface,
off_x_surf + offset_change_x,
off_y_surf + offset_change_y);
origin = *(pika_symmetry_get_origin (sym));
origin.x += offset_change_x;
origin.y += offset_change_y;
pika_symmetry_set_origin (sym, drawable, &origin);
}
mypaint_brush_stroke_to (brush,
(MyPaintSurface *) mybrush->private->surface,

View File

@ -38,13 +38,15 @@
struct _PikaMybrushSurface
{
MyPaintSurface surface;
GeglBuffer *buffer;
GeglBuffer *paint_mask;
gint paint_mask_x;
gint paint_mask_y;
GeglRectangle dirty;
PikaComponentMask component_mask;
MyPaintSurface surface;
GeglBuffer *buffer;
GeglBuffer *paint_mask;
gint paint_mask_x;
gint paint_mask_y;
gint off_x;
gint off_y;
GeglRectangle dirty;
PikaComponentMask component_mask;