Compare commits
8 Commits
098531073c
...
0.0.0+GnuI
Author | SHA1 | Date | |
---|---|---|---|
4b829a4b3c | |||
af7dc8395d | |||
8ac3f8a548 | |||
63b2780499 | |||
d472f6348d | |||
84ea557696 | |||
852cbfc1fb | |||
3bbdd873ef |
100
.gitlab-ci.yml
100
.gitlab-ci.yml
@ -18,7 +18,8 @@
|
||||
# - PIKA_CI_CROSSROAD_WIN64: trigger the crossroad/meson build for Win 64-bit.
|
||||
# - PIKA_CI_MSYS2_WIN32: trigger the native MSYS2 build for Win 32-bit.
|
||||
# - PIKA_CI_MSYS2_WIN64: trigger the native MSYS2 build for Win 64-bit.
|
||||
# - PIKA_CI_WIN_INSTALLER: trigger both native MSYS2 builds then creates Windows installer.
|
||||
# - PIKA_CI_MSYS2_WIN_AARCH64: trigger the native MSYS2 build for Windows/Aarch64.
|
||||
# - PIKA_CI_WIN_INSTALLER: trigger all native MSYS2 builds then creates Windows installer.
|
||||
# - PIKA_CI_SOURCES: trigger the meson/gcc build and the source tarball job.
|
||||
# - PIKA_CI_CPPCHECK: trigger cppcheck static analysis.
|
||||
# - PIKA_CI_FLATPAK: trigger the nightly flatpak build and publishing.
|
||||
@ -375,7 +376,7 @@ pika-meson-raster-icons:
|
||||
- ninja -C _build
|
||||
- ninja -C _build test
|
||||
|
||||
## WINDOWS 64-bit CI (native MSYS2) ##
|
||||
## WINDOWS x86_64 CI (native MSYS2) ##
|
||||
|
||||
deps-win64-native:
|
||||
rules:
|
||||
@ -462,7 +463,7 @@ packaging-win64-native:
|
||||
- done-dll.list
|
||||
needs: ["pika-win64-native"]
|
||||
|
||||
## WINDOWS 32-bit CI (native MSYS2) ##
|
||||
## WINDOWS x86 CI (native MSYS2) ##
|
||||
|
||||
deps-win32-native:
|
||||
rules:
|
||||
@ -548,6 +549,96 @@ packaging-win32-native:
|
||||
- done-dll.list
|
||||
needs: ["pika-win32-native"]
|
||||
|
||||
## WINDOWS Aarch64 CI (native MSYS2) ##
|
||||
|
||||
deps-win-aarch64-native:
|
||||
rules:
|
||||
# On releases.
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
# Custom builds though web GUI, API or schedules.
|
||||
- if: '$PIKA_CI_MSYS2_WIN_AARCH64 != null'
|
||||
- if: '$PIKA_CI_WIN_INSTALLER != null'
|
||||
# Merge requests with appropriate label.
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
|
||||
stage: dependencies
|
||||
variables:
|
||||
MSYSTEM: "CLANGARM64"
|
||||
CHERE_INVOKING: "yes"
|
||||
tags:
|
||||
- windows-aarch64
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/build-deps-msys2.sh"
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
|
||||
when: always
|
||||
expire_in: 2 hours
|
||||
paths:
|
||||
- _install-arm64
|
||||
needs: []
|
||||
|
||||
pika-win-aarch64-native:
|
||||
rules:
|
||||
# On releases.
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
# Custom builds though web GUI, API or schedules.
|
||||
- if: '$PIKA_CI_MSYS2_WIN_AARCH64 != null'
|
||||
- if: '$PIKA_CI_WIN_INSTALLER != null'
|
||||
# Merge requests with appropriate label.
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
|
||||
stage: pika
|
||||
variables:
|
||||
MSYSTEM: "CLANGARM64"
|
||||
CHERE_INVOKING: "yes"
|
||||
tags:
|
||||
- windows-aarch64
|
||||
script:
|
||||
# Temporary patch until we use the latest LLVM.
|
||||
- git apply ./build/windows/patches/0001-clang-rc-files-fix.patch
|
||||
- git apply ./build/windows/patches/0004-clang-windres.patch
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/build-pika-msys2.sh"
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
|
||||
when: always
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- _install-arm64
|
||||
- _build-arm64/build/windows/installer/
|
||||
- _build-arm64/meson-*/
|
||||
cache:
|
||||
paths:
|
||||
- _ccache/
|
||||
needs: ["deps-win-aarch64-native"]
|
||||
|
||||
packaging-win-aarch64-native:
|
||||
rules:
|
||||
# On releases.
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
# Custom builds though web GUI, API or schedules.
|
||||
- if: '$PIKA_CI_WIN_INSTALLER != null'
|
||||
# Merge requests with appropriate label.
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
|
||||
stage: packaging
|
||||
variables:
|
||||
MSYSTEM: "CLANGARM64"
|
||||
CHERE_INVOKING: "yes"
|
||||
tags:
|
||||
- windows-aarch64
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/package-pika-msys2.sh"
|
||||
- cd pika-arm64
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ../build/windows/gitlab-ci/split-debug-msys2.sh"
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
|
||||
when: always
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- pika-arm64
|
||||
- done-dll.list
|
||||
needs: ["pika-win-aarch64-native"]
|
||||
|
||||
## WINDOWS 64-bit CI (cross-build crossroad) ##
|
||||
|
||||
deps-win64:
|
||||
@ -822,6 +913,7 @@ win-installer-nightly:
|
||||
dependencies:
|
||||
- packaging-win64-native
|
||||
- packaging-win32-native
|
||||
- packaging-win-aarch64-native
|
||||
# This is needed for the BMP image generation for the installer.
|
||||
# See commit e1203e9f76f.
|
||||
- pika-meson-debian
|
||||
@ -835,7 +927,7 @@ win-installer-nightly:
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/installer-pika-msys2.sh > installer.log 2>&1"
|
||||
needs: ["packaging-win32-native", "packaging-win64-native", "pika-meson-debian"]
|
||||
needs: ["packaging-win32-native", "packaging-win64-native", "packaging-win-aarch64-native", "pika-meson-debian"]
|
||||
|
||||
sources-meson:
|
||||
rules:
|
||||
|
8
README
8
README
@ -39,13 +39,7 @@ similar.
|
||||
|
||||
Partial package list on Debian/Ubuntu/etc:
|
||||
|
||||
appstream-util bison build-essential cmake desktop-file-utils flex gjs libaa1-dev libappstream-glib-dev libarchive-dev
|
||||
libatk1.0-dev libcairo2-dev libcfitsio-dev libexiv2-dev libfontconfig-dev libfreetype-dev libgdk-pixbuf-2.0-dev
|
||||
libgexiv2-dev libglib2.0-dev libgs-dev libgtk-3-dev libgudev-1.0-dev libharfbuzz-dev libheif-dev libjpeg-dev
|
||||
libjson-glib-dev liblcms2-dev libmng-dev libmypaint-dev libopenexr-dev libopenjp2-7-dev libpango1.0-dev libpng-dev
|
||||
libpoppler-dev libpoppler-glib-dev librsvg2-dev libtiff-dev libunwind-dev libwebp-dev libwmf-dev libx11-dev
|
||||
libxcursor-dev libxext-dev libxfixes-dev libxmu-dev libxpm-dev libzstd-dev luajit meson mypaint-brushes ninja-build
|
||||
pappler-data python3-gi-dev xmllint xsltproc
|
||||
appstream-util bison build-essential cmake desktop-file-utils flex gjs libaa1-dev libappstream-glib-dev libarchive-dev libatk1.0-dev libcairo2-dev libcfitsio-dev libexiv2-dev libfontconfig-dev libfreetype-dev libgdk-pixbuf-2.0-dev libgexiv2-dev libglib2.0-dev libgs-dev libgtk-3-dev libgudev-1.0-dev libharfbuzz-dev libheif-dev libjpeg-dev libjson-glib-dev liblcms2-dev libmng-dev libmypaint-dev libopenexr-dev libopenjp2-7-dev libpango1.0-dev libpng-dev libpoppler-dev libpoppler-glib-dev librsvg2-dev libtiff-dev libunwind-dev libwebp-dev libwmf-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxmu-dev libxpm-dev libzstd-dev luajit meson mypaint-brushes ninja-build poppler-data python3-gi libxml2-utils xsltproc gobject-introspection libgirepository1.0-dev libbz2-dev gettext
|
||||
|
||||
Seems like a lot! But many of these are for format support. This is for the maximal setup we've tested.
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "core/pikaimage-colormap.h"
|
||||
|
||||
#include "widgets/pikaactiongroup.h"
|
||||
#include "widgets/pikacolormapeditor.h"
|
||||
#include "widgets/pikahelp-ids.h"
|
||||
|
||||
#include "actions.h"
|
||||
@ -49,6 +50,12 @@ static const PikaActionEntry colormap_actions[] =
|
||||
NC_("colormap-action", "_Edit Color..."), NULL, { NULL },
|
||||
NC_("colormap-action", "Edit this color"),
|
||||
colormap_edit_color_cmd_callback,
|
||||
PIKA_HELP_INDEXED_PALETTE_EDIT },
|
||||
|
||||
{ "colormap-delete-color", PIKA_ICON_EDIT_DELETE,
|
||||
NC_("colormap-action", "_Delete Color..."), NULL, { NULL },
|
||||
NC_("colormap-action", "Delete this color"),
|
||||
colormap_delete_color_cmd_callback,
|
||||
PIKA_HELP_INDEXED_PALETTE_EDIT }
|
||||
};
|
||||
|
||||
@ -116,13 +123,14 @@ void
|
||||
colormap_actions_update (PikaActionGroup *group,
|
||||
gpointer data)
|
||||
{
|
||||
PikaImage *image = action_data_get_image (data);
|
||||
PikaContext *context = action_data_get_context (data);
|
||||
gboolean indexed = FALSE;
|
||||
gboolean drawable_indexed = FALSE;
|
||||
gint num_colors = 0;
|
||||
PikaRGB fg;
|
||||
PikaRGB bg;
|
||||
PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
|
||||
PikaImage *image = action_data_get_image (data);
|
||||
PikaContext *context = action_data_get_context (data);
|
||||
gboolean indexed = FALSE;
|
||||
gboolean drawable_indexed = FALSE;
|
||||
gint num_colors = 0;
|
||||
PikaRGB fg;
|
||||
PikaRGB bg;
|
||||
|
||||
if (image)
|
||||
{
|
||||
@ -154,6 +162,9 @@ colormap_actions_update (PikaActionGroup *group,
|
||||
|
||||
SET_SENSITIVE ("colormap-edit-color",
|
||||
indexed && num_colors > 0);
|
||||
SET_SENSITIVE ("colormap-delete-color",
|
||||
indexed && num_colors > 0 &&
|
||||
pika_colormap_editor_is_color_deletable (editor));
|
||||
|
||||
SET_SENSITIVE ("colormap-add-color-from-fg",
|
||||
indexed && num_colors < 256);
|
||||
|
@ -50,6 +50,16 @@ colormap_edit_color_cmd_callback (PikaAction *action,
|
||||
pika_colormap_editor_edit_color (editor);
|
||||
}
|
||||
|
||||
void
|
||||
colormap_delete_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data)
|
||||
{
|
||||
PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
|
||||
|
||||
pika_colormap_editor_delete_color (editor);
|
||||
}
|
||||
|
||||
void
|
||||
colormap_add_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
|
@ -26,6 +26,9 @@
|
||||
void colormap_edit_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
void colormap_delete_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
void colormap_add_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
|
@ -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[] =
|
||||
|
@ -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);
|
||||
|
||||
|
@ -446,7 +446,7 @@ pika_gegl_procedure_new (Pika *pika,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_int ("n-drawables",
|
||||
g_param_spec_int ("num-drawables",
|
||||
"N drawables",
|
||||
"The number of drawables",
|
||||
0, G_MAXINT32, 0,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -44,7 +44,7 @@
|
||||
#endif
|
||||
|
||||
#define DEFAULT_USER_MANUAL_ONLINE_URI \
|
||||
"https://docs.pika.org/" PIKA_APP_VERSION_STRING
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/wiki/" PIKA_APP_VERSION_STRING
|
||||
|
||||
|
||||
enum
|
||||
|
@ -50,7 +50,7 @@ _("Timestamp of the last update check.")
|
||||
"Defines the color management behavior."
|
||||
|
||||
#define COLOR_PROFILE_POLICY_BLURB \
|
||||
_("How to handle embedded color profiles when opening a file.")
|
||||
_("What to do when opening a file with an embedded ICC color profile.")
|
||||
|
||||
#define COLOR_PROFILE_PATH_BLURB \
|
||||
_("Sets the default folder path for all color profile file dialogs.")
|
||||
@ -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."
|
||||
|
||||
|
@ -1195,6 +1195,7 @@ pika_undo_type_get_type (void)
|
||||
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, "PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE", "group-image-vectors-merge" },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, "PIKA_UNDO_GROUP_IMAGE_QUICK_MASK", "group-image-quick-mask" },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_GRID, "PIKA_UNDO_GROUP_IMAGE_GRID", "group-image-grid" },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, "PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP", "group-image-colormap-remap" },
|
||||
{ PIKA_UNDO_GROUP_GUIDE, "PIKA_UNDO_GROUP_GUIDE", "group-guide" },
|
||||
{ PIKA_UNDO_GROUP_SAMPLE_POINT, "PIKA_UNDO_GROUP_SAMPLE_POINT", "group-sample-point" },
|
||||
{ PIKA_UNDO_GROUP_DRAWABLE, "PIKA_UNDO_GROUP_DRAWABLE", "group-drawable" },
|
||||
@ -1303,6 +1304,7 @@ pika_undo_type_get_type (void)
|
||||
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, NC_("undo-type", "Merge paths"), NULL },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, NC_("undo-type", "Quick Mask"), NULL },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, NC_("undo-type", "Colormap remapping"), NULL },
|
||||
{ PIKA_UNDO_GROUP_GUIDE, NC_("undo-type", "Guide"), NULL },
|
||||
{ PIKA_UNDO_GROUP_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
|
||||
{ PIKA_UNDO_GROUP_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL },
|
||||
|
@ -548,6 +548,7 @@ typedef enum /*< pdb-skip >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, /*< desc="Merge paths" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, /*< desc="Quick Mask" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, /*< desc="Colormap remapping" >*/
|
||||
PIKA_UNDO_GROUP_GUIDE, /*< desc="Guide" >*/
|
||||
PIKA_UNDO_GROUP_SAMPLE_POINT, /*< desc="Sample Point" >*/
|
||||
PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/
|
||||
@ -714,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;
|
||||
@ -740,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 |
|
||||
@ -749,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 |
|
||||
|
@ -33,8 +33,10 @@
|
||||
#include "pikacontainer.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadrawable.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaprogress.h"
|
||||
#include "pikaresource.h"
|
||||
#include "pikawaitable.h"
|
||||
|
||||
#include "about.h"
|
||||
@ -325,17 +327,17 @@ pika_get_empty_display (Pika *pika)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guint32
|
||||
GBytes *
|
||||
pika_get_display_window_id (Pika *pika,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), -1);
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), -1);
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
|
||||
|
||||
if (pika->gui.display_get_window_id)
|
||||
return pika->gui.display_get_window_id (display);
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PikaDisplay *
|
||||
@ -407,10 +409,11 @@ gboolean
|
||||
pika_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
...)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
@ -418,7 +421,10 @@ pika_pdb_dialog_new (Pika *pika,
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
|
||||
g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE), FALSE);
|
||||
g_return_val_if_fail (object == NULL ||
|
||||
g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
|
||||
g_return_val_if_fail (title != NULL, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
|
||||
@ -426,12 +432,11 @@ pika_pdb_dialog_new (Pika *pika,
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, object_name);
|
||||
va_start (args, object);
|
||||
|
||||
retval = pika->gui.pdb_dialog_new (pika, context, progress,
|
||||
container, title,
|
||||
callback_name, object_name,
|
||||
args);
|
||||
contents_type, parent_handle, title,
|
||||
callback_name, object, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
@ -440,27 +445,28 @@ pika_pdb_dialog_new (Pika *pika,
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
pika_pdb_dialog_set (Pika *pika,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
PikaObject *object,
|
||||
...)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
|
||||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
g_return_val_if_fail (object_name != NULL, FALSE);
|
||||
g_return_val_if_fail (object == NULL || g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_set)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, object_name);
|
||||
va_start (args, object);
|
||||
|
||||
retval = pika->gui.pdb_dialog_set (pika, container, callback_name,
|
||||
object_name, args);
|
||||
retval = pika->gui.pdb_dialog_set (pika, contents_type, callback_name,
|
||||
object, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
@ -470,15 +476,16 @@ pika_pdb_dialog_set (Pika *pika,
|
||||
|
||||
gboolean
|
||||
pika_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
|
||||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_close)
|
||||
return pika->gui.pdb_dialog_close (pika, container, callback_name);
|
||||
return pika->gui.pdb_dialog_close (pika, contents_type, callback_name);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ struct _PikaGui
|
||||
|
||||
PikaObject * (* get_window_strategy) (Pika *pika);
|
||||
PikaDisplay * (* get_empty_display) (Pika *pika);
|
||||
guint32 (* display_get_window_id) (PikaDisplay *display);
|
||||
GBytes * (* display_get_window_id) (PikaDisplay *display);
|
||||
PikaDisplay * (* display_create) (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
@ -77,18 +77,19 @@ struct _PikaGui
|
||||
gboolean (* pdb_dialog_new) (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args);
|
||||
gboolean (* pdb_dialog_set) (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args);
|
||||
gboolean (* pdb_dialog_close) (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name);
|
||||
gboolean (* recent_list_add_file) (Pika *pika,
|
||||
GFile *file,
|
||||
@ -126,7 +127,7 @@ PikaDisplay * pika_get_display_by_id (Pika *pika,
|
||||
gint ID);
|
||||
gint pika_get_display_id (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
guint32 pika_get_display_window_id (Pika *pika,
|
||||
GBytes * pika_get_display_window_id (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
PikaDisplay * pika_create_display (Pika *pika,
|
||||
PikaImage *image,
|
||||
@ -175,19 +176,21 @@ GFile * pika_get_icon_theme_dir (Pika *pika);
|
||||
gboolean pika_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean pika_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean pika_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name);
|
||||
|
||||
gboolean pika_recent_list_add_file (Pika *pika,
|
||||
GFile *file,
|
||||
const gchar *mime_type);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -202,6 +202,7 @@ pika_container_class_init (PikaContainerClass *klass)
|
||||
klass->search = NULL;
|
||||
klass->get_unique_names = NULL;
|
||||
klass->get_child_by_name = NULL;
|
||||
klass->get_children_by_name = NULL;
|
||||
klass->get_child_by_index = NULL;
|
||||
klass->get_child_index = NULL;
|
||||
|
||||
@ -885,6 +886,34 @@ pika_container_get_unique_names (PikaContainer *container)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GList *
|
||||
pika_container_get_children_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), NULL);
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name != NULL &&
|
||||
! pika_container_get_unique_names (container))
|
||||
{
|
||||
return PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name (container,
|
||||
name);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaObject *child;
|
||||
|
||||
child = PIKA_CONTAINER_GET_CLASS (container)->get_child_by_name (container, name);
|
||||
|
||||
if (child != NULL)
|
||||
return g_list_prepend (NULL, child);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PikaObject *
|
||||
pika_container_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
|
@ -79,6 +79,8 @@ struct _PikaContainerClass
|
||||
gboolean (* get_unique_names) (PikaContainer *container);
|
||||
PikaObject * (* get_child_by_name) (PikaContainer *container,
|
||||
const gchar *name);
|
||||
GList * (* get_children_by_name) (PikaContainer *container,
|
||||
const gchar *name);
|
||||
PikaObject * (* get_child_by_index) (PikaContainer *container,
|
||||
gint index);
|
||||
gint (* get_child_index) (PikaContainer *container,
|
||||
@ -121,6 +123,8 @@ PikaObject * pika_container_search (PikaContainer *contain
|
||||
|
||||
gboolean pika_container_get_unique_names (PikaContainer *container);
|
||||
|
||||
GList * pika_container_get_children_by_name (PikaContainer *container,
|
||||
const gchar *name);
|
||||
PikaObject * pika_container_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name);
|
||||
PikaObject * pika_container_get_child_by_index (PikaContainer *container,
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "pika-memsize.h"
|
||||
#include "pikadata.h"
|
||||
#include "pikaidtable.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikatag.h"
|
||||
#include "pikatagged.h"
|
||||
|
||||
@ -51,6 +52,7 @@ enum
|
||||
PROP_0,
|
||||
PROP_ID,
|
||||
PROP_FILE,
|
||||
PROP_IMAGE,
|
||||
PROP_WRITABLE,
|
||||
PROP_DELETABLE,
|
||||
PROP_MIME_TYPE
|
||||
@ -59,8 +61,10 @@ enum
|
||||
|
||||
struct _PikaDataPrivate
|
||||
{
|
||||
gint ID;
|
||||
GFile *file;
|
||||
gint ID;
|
||||
GFile *file;
|
||||
PikaImage *image;
|
||||
|
||||
GQuark mime_type;
|
||||
guint writable : 1;
|
||||
guint deletable : 1;
|
||||
@ -172,6 +176,11 @@ pika_data_class_init (PikaDataClass *klass)
|
||||
G_TYPE_FILE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_IMAGE,
|
||||
g_param_spec_object ("image", NULL, NULL,
|
||||
PIKA_TYPE_IMAGE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WRITABLE,
|
||||
g_param_spec_boolean ("writable", NULL, NULL,
|
||||
FALSE,
|
||||
@ -268,6 +277,12 @@ pika_data_set_property (GObject *object,
|
||||
private->deletable);
|
||||
break;
|
||||
|
||||
case PROP_IMAGE:
|
||||
pika_data_set_image (data,
|
||||
g_value_get_object (value),
|
||||
private->writable,
|
||||
private->deletable);
|
||||
break;
|
||||
case PROP_WRITABLE:
|
||||
private->writable = g_value_get_boolean (value);
|
||||
break;
|
||||
@ -307,6 +322,10 @@ pika_data_get_property (GObject *object,
|
||||
g_value_set_object (value, private->file);
|
||||
break;
|
||||
|
||||
case PROP_IMAGE:
|
||||
g_value_set_object (value, private->image);
|
||||
break;
|
||||
|
||||
case PROP_WRITABLE:
|
||||
g_value_set_boolean (value, private->writable);
|
||||
break;
|
||||
@ -462,7 +481,7 @@ pika_data_get_identifier (PikaTagged *tagged)
|
||||
gchar *identifier = NULL;
|
||||
gchar *collection = NULL;
|
||||
|
||||
g_return_val_if_fail (private->internal || private->file != NULL, NULL);
|
||||
g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
|
||||
|
||||
collection = pika_data_get_collection (data);
|
||||
/* The identifier is guaranteed to be unique because we use 2 directory
|
||||
@ -503,7 +522,7 @@ pika_data_get_collection (PikaData *data)
|
||||
PikaDataPrivate *private = PIKA_DATA_GET_PRIVATE (data);
|
||||
gchar *collection = NULL;
|
||||
|
||||
g_return_val_if_fail (private->internal || private->file != NULL, NULL);
|
||||
g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
|
||||
|
||||
if (private->file)
|
||||
{
|
||||
@ -551,6 +570,10 @@ pika_data_get_collection (PikaData *data)
|
||||
|
||||
g_free (path);
|
||||
}
|
||||
else if (private->image)
|
||||
{
|
||||
collection = g_strdup_printf ("[image-id-%d]", pika_image_get_id (private->image));
|
||||
}
|
||||
else if (private->internal)
|
||||
{
|
||||
collection = g_strdup (private->collection);
|
||||
@ -603,7 +626,7 @@ pika_data_save (PikaData *data,
|
||||
|
||||
g_return_val_if_fail (private->writable == TRUE, FALSE);
|
||||
|
||||
if (private->internal)
|
||||
if (private->internal || private->image != NULL)
|
||||
{
|
||||
private->dirty = FALSE;
|
||||
return TRUE;
|
||||
@ -862,6 +885,8 @@ pika_data_set_file (PikaData *data,
|
||||
if (private->internal)
|
||||
return;
|
||||
|
||||
g_return_if_fail (private->image == NULL);
|
||||
|
||||
g_set_object (&private->file, file);
|
||||
|
||||
private->writable = FALSE;
|
||||
@ -937,6 +962,53 @@ pika_data_get_file (PikaData *data)
|
||||
return private->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_data_set_image:
|
||||
* @data: A #PikaData object
|
||||
* @image: Image to assign to @data.
|
||||
* @writable: %TRUE if we want to be able to write to this file.
|
||||
* @deletable: %TRUE if we want to be able to delete this file.
|
||||
*
|
||||
* This function assigns an image to @data. This can only be done if no file has
|
||||
* been assigned (a non-internal data can be attached either to a file or to an
|
||||
* image).
|
||||
**/
|
||||
void
|
||||
pika_data_set_image (PikaData *data,
|
||||
PikaImage *image,
|
||||
gboolean writable,
|
||||
gboolean deletable)
|
||||
{
|
||||
PikaDataPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DATA (data));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
|
||||
private = PIKA_DATA_GET_PRIVATE (data);
|
||||
|
||||
if (private->internal)
|
||||
return;
|
||||
|
||||
g_return_if_fail (private->file == NULL);
|
||||
|
||||
g_set_object (&private->image, image);
|
||||
|
||||
private->writable = writable ? TRUE : FALSE;
|
||||
private->deletable = deletable ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
pika_data_get_image (PikaData *data)
|
||||
{
|
||||
PikaDataPrivate *private;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DATA (data), NULL);
|
||||
|
||||
private = PIKA_DATA_GET_PRIVATE (data);
|
||||
|
||||
return private->image;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_data_create_filename:
|
||||
* @data: a #Pikadata object.
|
||||
|
@ -102,6 +102,11 @@ void pika_data_set_file (PikaData *data,
|
||||
gboolean writable,
|
||||
gboolean deletable);
|
||||
GFile * pika_data_get_file (PikaData *data);
|
||||
void pika_data_set_image (PikaData *data,
|
||||
PikaImage *image,
|
||||
gboolean writable,
|
||||
gboolean deletable);
|
||||
PikaImage * pika_data_get_image (PikaData *data);
|
||||
|
||||
void pika_data_create_filename (PikaData *data,
|
||||
GFile *dest_dir);
|
||||
|
@ -403,6 +403,9 @@ pika_data_factory_real_data_save (PikaDataFactory *factory)
|
||||
PikaData *data = list->data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (pika_data_get_image (data))
|
||||
continue;
|
||||
|
||||
if (! pika_data_get_file (data))
|
||||
pika_data_create_filename (data, writable_dir);
|
||||
|
||||
@ -460,6 +463,7 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
|
||||
gint copy_len;
|
||||
gint number;
|
||||
gchar *new_name;
|
||||
GError *error = NULL;
|
||||
|
||||
ext = strrchr (name, '#');
|
||||
copy_len = strlen (_("copy"));
|
||||
@ -479,8 +483,12 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
|
||||
|
||||
pika_object_take_name (PIKA_OBJECT (new_data), new_name);
|
||||
|
||||
if (! pika_data_factory_data_save_single (factory, new_data, &error))
|
||||
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
|
||||
|
||||
pika_container_add (priv->container, PIKA_OBJECT (new_data));
|
||||
g_object_unref (new_data);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
return new_data;
|
||||
@ -674,8 +682,14 @@ pika_data_factory_data_new (PikaDataFactory *factory,
|
||||
|
||||
if (data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (! pika_data_factory_data_save_single (factory, data, &error))
|
||||
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
|
||||
|
||||
pika_container_add (priv->container, PIKA_OBJECT (data));
|
||||
g_object_unref (data);
|
||||
g_clear_error (&error);
|
||||
|
||||
return data;
|
||||
}
|
||||
@ -750,7 +764,7 @@ pika_data_factory_data_save_single (PikaDataFactory *factory,
|
||||
g_return_val_if_fail (PIKA_IS_DATA (data), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (! pika_data_is_dirty (data))
|
||||
if (! pika_data_is_dirty (data) || pika_data_get_image (data))
|
||||
return TRUE;
|
||||
|
||||
if (! pika_data_get_file (data))
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -31,25 +31,43 @@
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikageglconfig.h"
|
||||
|
||||
#include "gegl/pika-babl.h"
|
||||
#include "gegl/pika-gegl-loops.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pikacontainer.h"
|
||||
#include "pikadatafactory.h"
|
||||
#include "pikadrawable.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-colormap.h"
|
||||
#include "pikaimage-private.h"
|
||||
#include "pikaimage-undo.h"
|
||||
#include "pikaimage-undo-push.h"
|
||||
#include "pikapalette.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GeglBuffer *buffer;
|
||||
const Babl *format;
|
||||
|
||||
/* Shared by jobs. */
|
||||
gboolean *found;
|
||||
GRWLock *lock;
|
||||
} IndexUsedJobData;
|
||||
|
||||
|
||||
/* local function prototype */
|
||||
|
||||
static void pika_image_colormap_set_palette_entry (PikaImage *image,
|
||||
const PikaRGB *color,
|
||||
gint index);
|
||||
static void pika_image_colormap_set_palette_entry (PikaImage *image,
|
||||
const PikaRGB *color,
|
||||
gint index);
|
||||
static void pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
|
||||
gint index);
|
||||
|
||||
|
||||
/* public functions */
|
||||
@ -80,7 +98,7 @@ pika_image_colormap_init (PikaImage *image)
|
||||
|
||||
pika_palette_set_columns (private->palette, 16);
|
||||
|
||||
pika_data_make_internal (PIKA_DATA (private->palette), palette_id);
|
||||
pika_data_set_image (PIKA_DATA (private->palette), image, TRUE, FALSE);
|
||||
|
||||
palettes = pika_data_factory_get_container (image->pika->palette_factory);
|
||||
|
||||
@ -319,9 +337,8 @@ pika_image_set_colormap (PikaImage *image,
|
||||
pika_image_colormap_set_palette_entry (image, &color, i);
|
||||
}
|
||||
|
||||
pika_data_thaw (PIKA_DATA (private->palette));
|
||||
|
||||
pika_image_colormap_changed (image, -1);
|
||||
pika_data_thaw (PIKA_DATA (private->palette));
|
||||
}
|
||||
|
||||
void
|
||||
@ -347,6 +364,45 @@ pika_image_unset_colormap (PikaImage *image,
|
||||
pika_image_colormap_changed (image, -1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_image_colormap_is_index_used (PikaImage *image,
|
||||
gint color_index)
|
||||
{
|
||||
GList *layers;
|
||||
GList *iter;
|
||||
GThreadPool *pool;
|
||||
GRWLock lock;
|
||||
gboolean found = FALSE;
|
||||
gint num_processors;
|
||||
|
||||
g_rw_lock_init (&lock);
|
||||
num_processors = PIKA_GEGL_CONFIG (image->pika->config)->num_processors;
|
||||
layers = pika_image_get_layer_list (image);
|
||||
|
||||
pool = g_thread_pool_new_full ((GFunc) pika_image_colormap_thread_is_index_used,
|
||||
GINT_TO_POINTER (color_index),
|
||||
(GDestroyNotify) g_free,
|
||||
num_processors, TRUE, NULL);
|
||||
for (iter = layers; iter; iter = g_list_next (iter))
|
||||
{
|
||||
IndexUsedJobData *job_data;
|
||||
|
||||
job_data = g_malloc (sizeof (IndexUsedJobData ));
|
||||
job_data->buffer = pika_drawable_get_buffer (iter->data);
|
||||
job_data->format = pika_drawable_get_format_without_alpha (iter->data);
|
||||
job_data->found = &found;
|
||||
job_data->lock = &lock;
|
||||
|
||||
g_thread_pool_push (pool, job_data, NULL);
|
||||
}
|
||||
|
||||
g_thread_pool_free (pool, FALSE, TRUE);
|
||||
g_rw_lock_clear (&lock);
|
||||
g_list_free (layers);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void
|
||||
pika_image_get_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
@ -420,6 +476,57 @@ pika_image_add_colormap_entry (PikaImage *image,
|
||||
pika_image_colormap_changed (image, -1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_image_delete_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
gboolean push_undo)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
|
||||
|
||||
if (! pika_image_colormap_is_index_used (image, color_index))
|
||||
{
|
||||
PikaImagePrivate *private;
|
||||
PikaPaletteEntry *entry;
|
||||
GList *layers;
|
||||
GList *iter;
|
||||
|
||||
if (push_undo)
|
||||
{
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP,
|
||||
C_("undo-type", "Delete Colormap entry"));
|
||||
|
||||
pika_image_undo_push_image_colormap (image, NULL);
|
||||
}
|
||||
|
||||
private = PIKA_IMAGE_GET_PRIVATE (image);
|
||||
layers = pika_image_get_layer_list (image);
|
||||
|
||||
for (iter = layers; iter; iter = g_list_next (iter))
|
||||
{
|
||||
if (push_undo)
|
||||
pika_image_undo_push_drawable_mod (image, NULL, iter->data, TRUE);
|
||||
|
||||
pika_gegl_shift_index (pika_drawable_get_buffer (iter->data), NULL,
|
||||
pika_drawable_get_format (iter->data),
|
||||
color_index, -1);
|
||||
}
|
||||
|
||||
entry = pika_palette_get_entry (private->palette, color_index);
|
||||
pika_palette_delete_entry (private->palette, entry);
|
||||
|
||||
g_list_free (layers);
|
||||
|
||||
if (push_undo)
|
||||
pika_image_undo_group_end (image);
|
||||
|
||||
pika_image_colormap_changed (image, -1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
@ -442,3 +549,22 @@ pika_image_colormap_set_palette_entry (PikaImage *image,
|
||||
|
||||
pika_palette_set_entry (private->palette, index, name, color);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
|
||||
gint index)
|
||||
{
|
||||
g_rw_lock_reader_lock (data->lock);
|
||||
if (*data->found)
|
||||
{
|
||||
g_rw_lock_reader_unlock (data->lock);
|
||||
return;
|
||||
}
|
||||
g_rw_lock_reader_unlock (data->lock);
|
||||
if (pika_gegl_is_index_used (data->buffer, NULL, data->format, index))
|
||||
{
|
||||
g_rw_lock_writer_lock (data->lock);
|
||||
*data->found = TRUE;
|
||||
g_rw_lock_writer_unlock (data->lock);
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ void pika_image_set_colormap (PikaImage *image,
|
||||
void pika_image_unset_colormap (PikaImage *image,
|
||||
gboolean push_undo);
|
||||
|
||||
gboolean pika_image_colormap_is_index_used (PikaImage *image,
|
||||
gint color_index);
|
||||
|
||||
void pika_image_get_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
PikaRGB *color);
|
||||
@ -59,6 +62,9 @@ void pika_image_set_colormap_entry (PikaImage *image,
|
||||
|
||||
void pika_image_add_colormap_entry (PikaImage *image,
|
||||
const PikaRGB *color);
|
||||
gboolean pika_image_delete_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
gboolean push_undo);
|
||||
|
||||
|
||||
#endif /* __PIKA_IMAGE_COLORMAP_H__ */
|
||||
|
@ -24,17 +24,22 @@
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
#include <gexiv2/gexiv2.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-color-profile.h"
|
||||
#include "pikaimage-metadata.h"
|
||||
#include "pikaimage-private.h"
|
||||
#include "pikaimage-rotate.h"
|
||||
#include "pikaimage-undo.h"
|
||||
#include "pikaimage-undo-push.h"
|
||||
#include "pikalayer-new.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
@ -186,3 +191,110 @@ pika_image_metadata_update_colorspace (PikaImage *image)
|
||||
pika_metadata_set_colorspace (metadata, space);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_image_metadata_load_thumbnail:
|
||||
* @pika: The #Pika object.
|
||||
* @file: A #GFile image.
|
||||
* @full_image_width: the width of the full image (not the thumbnail).
|
||||
* @full_image_height: the height of the full image (not the thumbnail).
|
||||
* @error: Return location for error message
|
||||
*
|
||||
* Retrieves a thumbnail from metadata in @file if present.
|
||||
* It does not need to actually load the full image, only the metadata through
|
||||
* GExiv2, which makes it fast.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #PikaImage of the @file thumbnail.
|
||||
*/
|
||||
PikaImage *
|
||||
pika_image_metadata_load_thumbnail (Pika *pika,
|
||||
GFile *file,
|
||||
gint *full_image_width,
|
||||
gint *full_image_height,
|
||||
const Babl **format,
|
||||
GError **error)
|
||||
{
|
||||
PikaMetadata *metadata;
|
||||
GInputStream *input_stream;
|
||||
GdkPixbuf *pixbuf;
|
||||
guint8 *thumbnail_buffer;
|
||||
gint thumbnail_size;
|
||||
PikaImage *image = NULL;
|
||||
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
metadata = pika_metadata_load_from_file (file, error);
|
||||
if (! metadata)
|
||||
return NULL;
|
||||
|
||||
if (! gexiv2_metadata_get_exif_thumbnail (GEXIV2_METADATA (metadata),
|
||||
&thumbnail_buffer,
|
||||
&thumbnail_size))
|
||||
{
|
||||
g_object_unref (metadata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input_stream = g_memory_input_stream_new_from_data (thumbnail_buffer,
|
||||
thumbnail_size,
|
||||
(GDestroyNotify) g_free);
|
||||
pixbuf = gdk_pixbuf_new_from_stream (input_stream, NULL, error);
|
||||
g_object_unref (input_stream);
|
||||
|
||||
if (pixbuf)
|
||||
{
|
||||
PikaLayer *layer;
|
||||
|
||||
image = pika_image_new (pika,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf),
|
||||
PIKA_RGB, PIKA_PRECISION_U8_NON_LINEAR);
|
||||
pika_image_undo_disable (image);
|
||||
|
||||
/* XXX This is possibly wrong, because an image of a given color space may
|
||||
* have a thumbnail stored in a different colorspace. This is even more
|
||||
* true with PIKA which always exports RGB thumbnails (see code in
|
||||
* pika_image_metadata_save_filter()), even for say grayscale images.
|
||||
* Nevertheless other software may store thumbnail using the same
|
||||
* colorspace.
|
||||
*/
|
||||
*format = pika_pixbuf_get_format (pixbuf);
|
||||
layer = pika_layer_new_from_pixbuf (pixbuf, image,
|
||||
pika_image_get_layer_format (image, FALSE),
|
||||
/* No need to localize; this image is short-lived. */
|
||||
"Background",
|
||||
PIKA_OPACITY_OPAQUE,
|
||||
pika_image_get_default_new_layer_mode (image));
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
pika_image_add_layer (image, layer, NULL, 0, FALSE);
|
||||
|
||||
pika_image_apply_metadata_orientation (image, pika_get_user_context (pika), metadata, NULL);
|
||||
}
|
||||
|
||||
/* This is the unoriented dimensions. Should we switch when there is a 90 or
|
||||
* 270 degree rotation? We don't actually know if the metadata orientation is
|
||||
* correct.
|
||||
*/
|
||||
*full_image_width = gexiv2_metadata_get_pixel_width (GEXIV2_METADATA (metadata));
|
||||
*full_image_height = gexiv2_metadata_get_pixel_height (GEXIV2_METADATA (metadata));
|
||||
|
||||
if (*full_image_width < 1 || *full_image_height < 1)
|
||||
{
|
||||
/* Dimensions stored in metadata might be less accurate, yet it's still
|
||||
* informational.
|
||||
*/
|
||||
*full_image_width = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
|
||||
*full_image_height = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
|
||||
}
|
||||
if (*full_image_width < 1 || *full_image_height < 1)
|
||||
{
|
||||
*full_image_width = 0;
|
||||
*full_image_height = 0;
|
||||
}
|
||||
|
||||
g_object_unref (metadata);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
@ -33,5 +33,12 @@ void pika_image_metadata_update_bits_per_sample (PikaImage *image);
|
||||
void pika_image_metadata_update_resolution (PikaImage *image);
|
||||
void pika_image_metadata_update_colorspace (PikaImage *image);
|
||||
|
||||
PikaImage * pika_image_metadata_load_thumbnail (Pika *pika,
|
||||
GFile *file,
|
||||
gint *full_image_width,
|
||||
gint *full_image_height,
|
||||
const Babl **format,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_IMAGE_METADATA_H__ */
|
||||
|
@ -282,6 +282,17 @@ pika_image_import_rotation_metadata (PikaImage *image,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_image_apply_metadata_orientation (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaMetadata *metadata,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
pika_image_metadata_rotate (image, context,
|
||||
gexiv2_metadata_try_get_orientation (GEXIV2_METADATA (metadata), NULL),
|
||||
progress);
|
||||
}
|
||||
|
||||
|
||||
/* Private Functions */
|
||||
|
||||
|
@ -23,14 +23,20 @@
|
||||
#define __PIKA_IMAGE_ROTATE_H__
|
||||
|
||||
|
||||
void pika_image_rotate (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaRotationType rotate_type,
|
||||
PikaProgress *progress);
|
||||
void pika_image_rotate (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaRotationType rotate_type,
|
||||
PikaProgress *progress);
|
||||
|
||||
void pika_image_import_rotation_metadata (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
gboolean interactive);
|
||||
|
||||
void pika_image_apply_metadata_orientation (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaMetadata *metadata,
|
||||
PikaProgress *progress);
|
||||
|
||||
void pika_image_import_rotation_metadata (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
gboolean interactive);
|
||||
|
||||
#endif /* __PIKA_IMAGE_ROTATE_H__ */
|
||||
|
@ -625,6 +625,9 @@ pika_image_undo_dirty_from_type (PikaUndoType undo_type)
|
||||
case PIKA_UNDO_GROUP_IMAGE_CONVERT:
|
||||
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
|
||||
|
||||
case PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP:
|
||||
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
|
||||
|
||||
case PIKA_UNDO_GROUP_IMAGE_LAYERS_MERGE:
|
||||
return PIKA_DIRTY_IMAGE_STRUCTURE | PIKA_DIRTY_DRAWABLE;
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "pikacontainer.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-metadata.h"
|
||||
#include "pikaimagefile.h"
|
||||
#include "pikapickable.h"
|
||||
#include "pikaprogress.h"
|
||||
@ -486,19 +487,37 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
|
||||
if (error && *error)
|
||||
{
|
||||
g_printerr ("Info: Thumbnail load procedure failed: %s\n"
|
||||
" Falling back to file load procedure.\n",
|
||||
" Falling back to metadata or file load.\n",
|
||||
(*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
|
||||
image = file_open_image (private->pika, context, progress,
|
||||
private->file,
|
||||
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
|
||||
&status, &mime_type, error);
|
||||
|
||||
image = pika_image_metadata_load_thumbnail (private->pika, private->file, &width, &height, &format, error);
|
||||
if (image)
|
||||
pika_thumbnail_set_info_from_image (private->thumbnail,
|
||||
mime_type, image);
|
||||
{
|
||||
pika_thumbnail_set_info (private->thumbnail,
|
||||
mime_type, width, height,
|
||||
format, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error && *error)
|
||||
{
|
||||
g_printerr ("Info: metadata load failed: %s\n"
|
||||
" Falling back to file load procedure.\n",
|
||||
(*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
|
||||
image = file_open_image (private->pika, context, progress,
|
||||
private->file,
|
||||
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
|
||||
&status, &mime_type, error);
|
||||
|
||||
if (image)
|
||||
pika_thumbnail_set_info_from_image (private->thumbnail,
|
||||
mime_type, image);
|
||||
}
|
||||
}
|
||||
|
||||
if (image)
|
||||
|
@ -76,6 +76,8 @@ static PikaObject * pika_list_search (PikaContainer *conta
|
||||
PikaContainerSearchFunc func,
|
||||
gpointer user_data);
|
||||
static gboolean pika_list_get_unique_names (PikaContainer *container);
|
||||
static GList * pika_list_get_children_by_name (PikaContainer *container,
|
||||
const gchar *name);
|
||||
static PikaObject * pika_list_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name);
|
||||
static PikaObject * pika_list_get_child_by_index (PikaContainer *container,
|
||||
@ -101,23 +103,24 @@ pika_list_class_init (PikaListClass *klass)
|
||||
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
|
||||
PikaContainerClass *container_class = PIKA_CONTAINER_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_list_finalize;
|
||||
object_class->set_property = pika_list_set_property;
|
||||
object_class->get_property = pika_list_get_property;
|
||||
object_class->finalize = pika_list_finalize;
|
||||
object_class->set_property = pika_list_set_property;
|
||||
object_class->get_property = pika_list_get_property;
|
||||
|
||||
pika_object_class->get_memsize = pika_list_get_memsize;
|
||||
pika_object_class->get_memsize = pika_list_get_memsize;
|
||||
|
||||
container_class->add = pika_list_add;
|
||||
container_class->remove = pika_list_remove;
|
||||
container_class->reorder = pika_list_reorder;
|
||||
container_class->clear = pika_list_clear;
|
||||
container_class->have = pika_list_have;
|
||||
container_class->foreach = pika_list_foreach;
|
||||
container_class->search = pika_list_search;
|
||||
container_class->get_unique_names = pika_list_get_unique_names;
|
||||
container_class->get_child_by_name = pika_list_get_child_by_name;
|
||||
container_class->get_child_by_index = pika_list_get_child_by_index;
|
||||
container_class->get_child_index = pika_list_get_child_index;
|
||||
container_class->add = pika_list_add;
|
||||
container_class->remove = pika_list_remove;
|
||||
container_class->reorder = pika_list_reorder;
|
||||
container_class->clear = pika_list_clear;
|
||||
container_class->have = pika_list_have;
|
||||
container_class->foreach = pika_list_foreach;
|
||||
container_class->search = pika_list_search;
|
||||
container_class->get_unique_names = pika_list_get_unique_names;
|
||||
container_class->get_children_by_name = pika_list_get_children_by_name;
|
||||
container_class->get_child_by_name = pika_list_get_child_by_name;
|
||||
container_class->get_child_by_index = pika_list_get_child_by_index;
|
||||
container_class->get_child_index = pika_list_get_child_index;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_UNIQUE_NAMES,
|
||||
g_param_spec_boolean ("unique-names",
|
||||
@ -369,6 +372,29 @@ pika_list_get_unique_names (PikaContainer *container)
|
||||
return list->unique_names;
|
||||
}
|
||||
|
||||
static GList *
|
||||
pika_list_get_children_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
{
|
||||
PikaList *list = PIKA_LIST (container);
|
||||
GList *children = NULL;
|
||||
GList *iter;
|
||||
|
||||
for (iter = list->queue->head; iter; iter = g_list_next (iter))
|
||||
{
|
||||
PikaObject *object = iter->data;
|
||||
|
||||
if (! strcmp (pika_object_get_name (object), name))
|
||||
{
|
||||
children = g_list_prepend (children, object);
|
||||
if (list->unique_names)
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
static PikaObject *
|
||||
pika_list_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
|
@ -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)
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-memsize.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-undo-push.h"
|
||||
#include "pikapalette.h"
|
||||
#include "pikapalette-load.h"
|
||||
#include "pikapalette-save.h"
|
||||
@ -44,6 +46,12 @@
|
||||
|
||||
#define RGB_EPSILON 1e-6
|
||||
|
||||
enum
|
||||
{
|
||||
ENTRY_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
@ -75,6 +83,8 @@ static gchar * pika_palette_get_description (PikaViewable *viewa
|
||||
static const gchar * pika_palette_get_extension (PikaData *data);
|
||||
static void pika_palette_copy (PikaData *data,
|
||||
PikaData *src_data);
|
||||
static void pika_palette_real_entry_changed (PikaPalette *palette,
|
||||
gint index);
|
||||
|
||||
static void pika_palette_entry_free (PikaPaletteEntry *entry);
|
||||
static gint64 pika_palette_entry_get_memsize (PikaPaletteEntry *entry,
|
||||
@ -88,6 +98,7 @@ G_DEFINE_TYPE_WITH_CODE (PikaPalette, pika_palette, PIKA_TYPE_DATA,
|
||||
|
||||
#define parent_class pika_palette_parent_class
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
pika_palette_class_init (PikaPaletteClass *klass)
|
||||
@ -97,6 +108,14 @@ pika_palette_class_init (PikaPaletteClass *klass)
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
|
||||
|
||||
signals[ENTRY_CHANGED] = g_signal_new ("entry-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (PikaPaletteClass, entry_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_INT);
|
||||
|
||||
object_class->finalize = pika_palette_finalize;
|
||||
|
||||
pika_object_class->get_memsize = pika_palette_get_memsize;
|
||||
@ -110,6 +129,8 @@ pika_palette_class_init (PikaPaletteClass *klass)
|
||||
data_class->save = pika_palette_save;
|
||||
data_class->get_extension = pika_palette_get_extension;
|
||||
data_class->copy = pika_palette_copy;
|
||||
|
||||
klass->entry_changed = pika_palette_real_entry_changed;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -344,6 +365,16 @@ pika_palette_copy (PikaData *data,
|
||||
pika_data_thaw (data);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_palette_real_entry_changed (PikaPalette *palette,
|
||||
gint index)
|
||||
{
|
||||
PikaImage *image = pika_data_get_image (PIKA_DATA (palette));
|
||||
|
||||
if (image != NULL)
|
||||
pika_image_colormap_changed (image, index);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
pika_palette_get_checksum (PikaTagged *tagged)
|
||||
{
|
||||
@ -406,11 +437,17 @@ pika_palette_move_entry (PikaPalette *palette,
|
||||
|
||||
if (g_list_find (palette->colors, entry))
|
||||
{
|
||||
gint old_position = g_list_index (palette->colors, entry);
|
||||
|
||||
palette->colors = g_list_remove (palette->colors,
|
||||
entry);
|
||||
palette->colors = g_list_insert (palette->colors,
|
||||
entry, position);
|
||||
|
||||
if (! pika_data_is_frozen (PIKA_DATA (palette)))
|
||||
for (gint i = MIN (position, old_position); i <= MAX (position, old_position); i++)
|
||||
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
|
||||
|
||||
pika_data_dirty (PIKA_DATA (palette));
|
||||
}
|
||||
}
|
||||
@ -442,6 +479,10 @@ pika_palette_add_entry (PikaPalette *palette,
|
||||
|
||||
palette->n_colors += 1;
|
||||
|
||||
if (! pika_data_is_frozen (PIKA_DATA (palette)))
|
||||
for (gint i = position; i < palette->n_colors; i++)
|
||||
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
|
||||
|
||||
pika_data_dirty (PIKA_DATA (palette));
|
||||
|
||||
return entry;
|
||||
@ -456,12 +497,18 @@ pika_palette_delete_entry (PikaPalette *palette,
|
||||
|
||||
if (g_list_find (palette->colors, entry))
|
||||
{
|
||||
gint old_position = g_list_index (palette->colors, entry);
|
||||
|
||||
pika_palette_entry_free (entry);
|
||||
|
||||
palette->colors = g_list_remove (palette->colors, entry);
|
||||
|
||||
palette->n_colors--;
|
||||
|
||||
if (! pika_data_is_frozen (PIKA_DATA (palette)))
|
||||
for (gint i = old_position; i < palette->n_colors; i++)
|
||||
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
|
||||
|
||||
pika_data_dirty (PIKA_DATA (palette));
|
||||
}
|
||||
}
|
||||
@ -489,6 +536,9 @@ pika_palette_set_entry (PikaPalette *palette,
|
||||
|
||||
entry->name = g_strdup (name);
|
||||
|
||||
if (! pika_data_is_frozen (PIKA_DATA (palette)))
|
||||
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
|
||||
|
||||
pika_data_dirty (PIKA_DATA (palette));
|
||||
|
||||
return TRUE;
|
||||
@ -497,7 +547,8 @@ pika_palette_set_entry (PikaPalette *palette,
|
||||
gboolean
|
||||
pika_palette_set_entry_color (PikaPalette *palette,
|
||||
gint position,
|
||||
const PikaRGB *color)
|
||||
const PikaRGB *color,
|
||||
gboolean push_undo_if_image)
|
||||
{
|
||||
PikaPaletteEntry *entry;
|
||||
|
||||
@ -509,8 +560,15 @@ pika_palette_set_entry_color (PikaPalette *palette,
|
||||
if (! entry)
|
||||
return FALSE;
|
||||
|
||||
if (push_undo_if_image && pika_data_get_image (PIKA_DATA (palette)))
|
||||
pika_image_undo_push_image_colormap (pika_data_get_image (PIKA_DATA (palette)),
|
||||
C_("undo-type", "Change Colormap entry"));
|
||||
|
||||
entry->color = *color;
|
||||
|
||||
if (! pika_data_is_frozen (PIKA_DATA (palette)))
|
||||
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
|
||||
|
||||
pika_data_dirty (PIKA_DATA (palette));
|
||||
|
||||
return TRUE;
|
||||
@ -535,6 +593,9 @@ pika_palette_set_entry_name (PikaPalette *palette,
|
||||
|
||||
entry->name = g_strdup (name);
|
||||
|
||||
if (! pika_data_is_frozen (PIKA_DATA (palette)))
|
||||
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
|
||||
|
||||
pika_data_dirty (PIKA_DATA (palette));
|
||||
|
||||
return TRUE;
|
||||
|
@ -56,6 +56,9 @@ struct _PikaPalette
|
||||
struct _PikaPaletteClass
|
||||
{
|
||||
PikaDataClass parent_class;
|
||||
|
||||
void (* entry_changed) (PikaPalette *palette,
|
||||
gint index);
|
||||
};
|
||||
|
||||
|
||||
@ -85,7 +88,8 @@ gboolean pika_palette_set_entry (PikaPalette *palette,
|
||||
const PikaRGB *color);
|
||||
gboolean pika_palette_set_entry_color (PikaPalette *palette,
|
||||
gint position,
|
||||
const PikaRGB *color);
|
||||
const PikaRGB *color,
|
||||
gboolean push_undo_if_image);
|
||||
gboolean pika_palette_set_entry_name (PikaPalette *palette,
|
||||
gint position,
|
||||
const gchar *name);
|
||||
|
@ -217,7 +217,7 @@ pika_palette_mru_add (PikaPaletteMru *mru,
|
||||
/* Even though they are nearly the same color, let's make them
|
||||
* exactly equal.
|
||||
*/
|
||||
pika_palette_set_entry_color (palette, 0, color);
|
||||
pika_palette_set_entry_color (palette, 0, color, FALSE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ static void pika_pdb_progress_progress_set_value (PikaProgress *progress
|
||||
gdouble percentage);
|
||||
static gdouble pika_pdb_progress_progress_get_value (PikaProgress *progress);
|
||||
static void pika_pdb_progress_progress_pulse (PikaProgress *progress);
|
||||
static guint32 pika_pdb_progress_progress_get_window_id (PikaProgress *progress);
|
||||
static GBytes * pika_pdb_progress_progress_get_window_id (PikaProgress *progress);
|
||||
|
||||
|
||||
static GObjectClass *parent_class = NULL;
|
||||
@ -241,14 +241,13 @@ pika_pdb_progress_set_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static gdouble
|
||||
pika_pdb_progress_run_callback (PikaPdbProgress *progress,
|
||||
PikaProgressCommand command,
|
||||
const gchar *text,
|
||||
gdouble value)
|
||||
static void
|
||||
pika_pdb_progress_run_callback (PikaPdbProgress *progress,
|
||||
PikaProgressCommand command,
|
||||
const gchar *text,
|
||||
gdouble value,
|
||||
GBytes **handle)
|
||||
{
|
||||
gdouble retval = 0;
|
||||
|
||||
if (progress->callback_name && ! progress->callback_busy)
|
||||
{
|
||||
PikaValueArray *return_vals;
|
||||
@ -274,17 +273,16 @@ pika_pdb_progress_run_callback (PikaPdbProgress *progress,
|
||||
g_type_name (G_TYPE_FROM_INSTANCE (progress)));
|
||||
}
|
||||
else if (pika_value_array_length (return_vals) >= 2 &&
|
||||
G_VALUE_HOLDS_DOUBLE (pika_value_array_index (return_vals, 1)))
|
||||
handle != NULL &&
|
||||
G_VALUE_HOLDS_BOXED (pika_value_array_index (return_vals, 1)))
|
||||
{
|
||||
retval = g_value_get_double (pika_value_array_index (return_vals, 1));
|
||||
*handle = g_value_dup_boxed (pika_value_array_index (return_vals, 1));
|
||||
}
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
|
||||
progress->callback_busy = FALSE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static PikaProgress *
|
||||
@ -298,7 +296,7 @@ pika_pdb_progress_progress_start (PikaProgress *progress,
|
||||
{
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_START,
|
||||
message, 0.0);
|
||||
message, 0.0, NULL);
|
||||
|
||||
pdb_progress->active = TRUE;
|
||||
pdb_progress->value = 0.0;
|
||||
@ -318,7 +316,7 @@ pika_pdb_progress_progress_end (PikaProgress *progress)
|
||||
{
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_END,
|
||||
NULL, 0.0);
|
||||
NULL, 0.0, NULL);
|
||||
|
||||
pdb_progress->active = FALSE;
|
||||
pdb_progress->value = 0.0;
|
||||
@ -342,7 +340,7 @@ pika_pdb_progress_progress_set_text (PikaProgress *progress,
|
||||
if (pdb_progress->active)
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_SET_TEXT,
|
||||
message, 0.0);
|
||||
message, 0.0, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -355,7 +353,7 @@ pika_pdb_progress_progress_set_value (PikaProgress *progress,
|
||||
{
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_SET_VALUE,
|
||||
NULL, percentage);
|
||||
NULL, percentage, NULL);
|
||||
pdb_progress->value = percentage;
|
||||
}
|
||||
}
|
||||
@ -377,18 +375,19 @@ pika_pdb_progress_progress_pulse (PikaProgress *progress)
|
||||
if (pdb_progress->active)
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_PULSE,
|
||||
NULL, 0.0);
|
||||
NULL, 0.0, NULL);
|
||||
}
|
||||
|
||||
static guint32
|
||||
static GBytes *
|
||||
pika_pdb_progress_progress_get_window_id (PikaProgress *progress)
|
||||
{
|
||||
PikaPdbProgress *pdb_progress = PIKA_PDB_PROGRESS (progress);
|
||||
GBytes *handle = NULL;
|
||||
|
||||
return (guint32)
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_GET_WINDOW,
|
||||
NULL, 0.0);
|
||||
pika_pdb_progress_run_callback (pdb_progress,
|
||||
PIKA_PROGRESS_COMMAND_GET_WINDOW,
|
||||
NULL, 0.0, &handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
PikaPdbProgress *
|
||||
|
@ -209,7 +209,7 @@ pika_progress_pulse (PikaProgress *progress)
|
||||
progress_iface->pulse (progress);
|
||||
}
|
||||
|
||||
guint32
|
||||
GBytes *
|
||||
pika_progress_get_window_id (PikaProgress *progress)
|
||||
{
|
||||
PikaProgressInterface *progress_iface;
|
||||
@ -221,7 +221,7 @@ pika_progress_get_window_id (PikaProgress *progress)
|
||||
if (progress_iface->get_window_id)
|
||||
return progress_iface->get_window_id (progress);
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -48,7 +48,7 @@ struct _PikaProgressInterface
|
||||
gdouble (* get_value) (PikaProgress *progress);
|
||||
void (* pulse) (PikaProgress *progress);
|
||||
|
||||
guint32 (* get_window_id) (PikaProgress *progress);
|
||||
GBytes * (* get_window_id) (PikaProgress *progress);
|
||||
|
||||
gboolean (* message) (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
@ -78,7 +78,7 @@ void pika_progress_set_value (PikaProgress *progress,
|
||||
gdouble pika_progress_get_value (PikaProgress *progress);
|
||||
void pika_progress_pulse (PikaProgress *progress);
|
||||
|
||||
guint32 pika_progress_get_window_id (PikaProgress *progress);
|
||||
GBytes * pika_progress_get_window_id (PikaProgress *progress);
|
||||
|
||||
gboolean pika_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
|
@ -59,7 +59,7 @@ static void pika_sub_progress_set_value (PikaProgress *prog
|
||||
gdouble percentage);
|
||||
static gdouble pika_sub_progress_get_value (PikaProgress *progress);
|
||||
static void pika_sub_progress_pulse (PikaProgress *progress);
|
||||
static guint32 pika_sub_progress_get_window_id (PikaProgress *progress);
|
||||
static GBytes * pika_sub_progress_get_window_id (PikaProgress *progress);
|
||||
static gboolean pika_sub_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
PikaMessageSeverity severity,
|
||||
@ -228,7 +228,7 @@ pika_sub_progress_pulse (PikaProgress *progress)
|
||||
pika_progress_pulse (sub->progress);
|
||||
}
|
||||
|
||||
static guint32
|
||||
static GBytes *
|
||||
pika_sub_progress_get_window_id (PikaProgress *progress)
|
||||
{
|
||||
PikaSubProgress *sub = PIKA_SUB_PROGRESS (progress);
|
||||
@ -236,7 +236,7 @@ pika_sub_progress_get_window_id (PikaProgress *progress)
|
||||
if (sub->progress)
|
||||
return pika_progress_get_window_id (sub->progress);
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -34,11 +34,12 @@
|
||||
|
||||
#include "config/pikacoreconfig.h"
|
||||
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
|
||||
#include "about.h"
|
||||
#include "git-version.h"
|
||||
|
||||
#include "about-dialog.h"
|
||||
#include "authors.h"
|
||||
#include "pika-update.h"
|
||||
#include "pika-version.h"
|
||||
|
||||
@ -47,20 +48,22 @@
|
||||
|
||||
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;
|
||||
guint timer;
|
||||
|
||||
gint index;
|
||||
gint animstep;
|
||||
gint state;
|
||||
gboolean visible;
|
||||
gint index;
|
||||
gint animstep;
|
||||
gint state;
|
||||
gboolean visible;
|
||||
} PikaAboutDialog;
|
||||
|
||||
|
||||
@ -93,7 +96,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 +110,7 @@ about_dialog_create (PikaCoreConfig *config)
|
||||
gchar *copyright;
|
||||
gchar *version;
|
||||
|
||||
dialog.pika = pika;
|
||||
dialog.config = config;
|
||||
|
||||
pixbuf = about_dialog_load_logo ();
|
||||
@ -134,9 +139,6 @@ about_dialog_create (PikaCoreConfig *config)
|
||||
"logo", pixbuf,
|
||||
"website", "https://heckin.technology/AlderconeStudio/PIKApp/",
|
||||
"website-label", _("Visit the PIKA website"),
|
||||
/* Translators: insert your names here,
|
||||
separated by newline */
|
||||
"translator-credits", _("translator-credits"),
|
||||
NULL);
|
||||
|
||||
if (pixbuf)
|
||||
@ -196,6 +198,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
|
||||
@ -264,203 +270,6 @@ 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
|
||||
@ -625,82 +434,6 @@ decorate_text (PikaAboutDialog *dialog,
|
||||
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 Aldercone Studio"));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
return FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -221,7 +221,7 @@ dialogs_about_get (PikaDialogFactory *factory,
|
||||
PikaUIManager *ui_manager,
|
||||
gint view_size)
|
||||
{
|
||||
return about_dialog_create (context->pika->edit_config);
|
||||
return about_dialog_create (context->pika, context->pika->edit_config);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
|
@ -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"),
|
||||
|
@ -151,6 +151,13 @@ quit_close_all_dialog_new (Pika *pika,
|
||||
GClosure *closure;
|
||||
gint rows;
|
||||
gint view_size;
|
||||
GdkRectangle geometry;
|
||||
GdkMonitor *monitor;
|
||||
gint max_rows;
|
||||
gint scale_factor;
|
||||
const gfloat rows_per_height = 32 / 1440.0f;
|
||||
const gint greatest_max_rows = 36;
|
||||
const gint least_max_rows = 6;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
@ -206,8 +213,28 @@ quit_close_all_dialog_new (Pika *pika,
|
||||
|
||||
private->box = PIKA_MESSAGE_DIALOG (private->dialog)->box;
|
||||
|
||||
monitor = pika_widget_get_monitor (private->dialog);
|
||||
scale_factor = gdk_monitor_get_scale_factor (monitor);
|
||||
gdk_monitor_get_geometry (monitor, &geometry);
|
||||
|
||||
if (scale_factor > 1)
|
||||
{
|
||||
#ifdef GDK_WINDOWING_WIN32
|
||||
max_rows = (geometry.height * scale_factor * rows_per_height)
|
||||
/ (scale_factor + 1);
|
||||
#else
|
||||
max_rows = (geometry.height * rows_per_height) / (scale_factor + 1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
max_rows = geometry.height * rows_per_height;
|
||||
}
|
||||
|
||||
max_rows = CLAMP (max_rows, least_max_rows, greatest_max_rows);
|
||||
|
||||
view_size = pika->config->layer_preview_size;
|
||||
rows = CLAMP (pika_container_get_n_children (private->images), 3, 6);
|
||||
rows = CLAMP (pika_container_get_n_children (private->images), 3, max_rows);
|
||||
|
||||
view = pika_container_tree_view_new (private->images, private->context,
|
||||
view_size, 1);
|
||||
|
@ -191,7 +191,7 @@ tips_dialog_create (Pika *pika)
|
||||
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/",
|
||||
more_button = gtk_link_button_new_with_label ("https://heckin.technology/AlderconeStudio/PIKApp/wiki/",
|
||||
/* a link to the related section in the user manual */
|
||||
_("Learn more"));
|
||||
gtk_widget_show (more_button);
|
||||
@ -251,7 +251,7 @@ tips_dialog_set_tip (PikaTip *tip)
|
||||
|
||||
/* set the URI to unset the "visited" state */
|
||||
gtk_link_button_set_uri (GTK_LINK_BUTTON (more_button),
|
||||
"https://docs.pika.org/");
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/wiki/");
|
||||
|
||||
gtk_widget_set_sensitive (more_button, tip->help_id != NULL);
|
||||
}
|
||||
|
@ -191,12 +191,12 @@ welcome_dialog_create (Pika *pika)
|
||||
/* "graduation cap" emoticone in UTF-8. */
|
||||
"\xf0\x9f\x8e\x93",
|
||||
_("Tutorials"),
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/tutorials/");
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/");
|
||||
welcome_add_link (GTK_GRID (grid), 0, &row,
|
||||
/* "open book" emoticone in UTF-8. */
|
||||
"\xf0\x9f\x93\x96",
|
||||
_("Documentation"),
|
||||
"https://docs.pika.org/");
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/wiki/");
|
||||
|
||||
/* XXX: should we add API docs for plug-in developers once it's
|
||||
* properly set up? */
|
||||
@ -229,12 +229,12 @@ welcome_dialog_create (Pika *pika)
|
||||
/* "keyboard" emoticone in UTF-8. */
|
||||
"\xe2\x8c\xa8",
|
||||
_("Contributing"),
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/develop/");
|
||||
"https://heckin.technology/AlderconeStudio/PIKApp/");
|
||||
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/");
|
||||
"https://mastodon.art/@aldercone/");
|
||||
|
||||
/*****************/
|
||||
/* Release Notes */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ static void pika_display_progress_set_value (PikaProgress *progre
|
||||
gdouble percentage);
|
||||
static gdouble pika_display_progress_get_value (PikaProgress *progress);
|
||||
static void pika_display_progress_pulse (PikaProgress *progress);
|
||||
static guint32 pika_display_progress_get_window_id (PikaProgress *progress);
|
||||
static GBytes * pika_display_progress_get_window_id (PikaProgress *progress);
|
||||
static gboolean pika_display_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
PikaMessageSeverity severity,
|
||||
@ -323,7 +323,7 @@ pika_display_progress_pulse (PikaProgress *progress)
|
||||
pika_progress_pulse (PIKA_PROGRESS (display->priv->shell));
|
||||
}
|
||||
|
||||
static guint32
|
||||
static GBytes *
|
||||
pika_display_progress_get_window_id (PikaProgress *progress)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
@ -331,7 +331,7 @@ pika_display_progress_get_window_id (PikaProgress *progress)
|
||||
if (display->priv->shell)
|
||||
return pika_progress_get_window_id (PIKA_PROGRESS (display->priv->shell));
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -103,15 +103,16 @@ pika_display_shell_progress_pulse (PikaProgress *progress)
|
||||
pika_progress_pulse (PIKA_PROGRESS (statusbar));
|
||||
}
|
||||
|
||||
static guint32
|
||||
static GBytes *
|
||||
pika_display_shell_progress_get_window_id (PikaProgress *progress)
|
||||
{
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (progress));
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (progress);
|
||||
GBytes *handle = NULL;
|
||||
|
||||
if (GTK_IS_WINDOW (toplevel))
|
||||
return pika_window_get_native_id (GTK_WINDOW (toplevel));
|
||||
if (shell->window_handle)
|
||||
handle = g_bytes_ref (shell->window_handle);
|
||||
|
||||
return 0;
|
||||
return handle;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
#include <gdk/gdkwayland.h>
|
||||
#endif
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
@ -587,6 +591,8 @@ pika_display_shell_constructed (GObject *object)
|
||||
G_CALLBACK (pika_display_shell_canvas_grab_notify),
|
||||
shell);
|
||||
|
||||
pika_widget_set_native_handle (GTK_WIDGET (shell), &shell->window_handle);
|
||||
|
||||
g_signal_connect (shell->canvas, "realize",
|
||||
G_CALLBACK (pika_display_shell_canvas_realize),
|
||||
shell);
|
||||
@ -851,6 +857,17 @@ pika_display_shell_dispose (GObject *object)
|
||||
|
||||
shell->display = NULL;
|
||||
|
||||
if (shell->window_handle != NULL)
|
||||
{
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()) &&
|
||||
/* The GdkWindow is likely already destroyed. */
|
||||
gtk_widget_get_window (GTK_WIDGET (shell)) != NULL)
|
||||
gdk_wayland_window_unexport_handle (gtk_widget_get_window (GTK_WIDGET (shell)));
|
||||
#endif
|
||||
g_clear_pointer (&shell->window_handle, g_bytes_unref);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,8 @@ struct _PikaDisplayShell
|
||||
|
||||
PikaDisplay *display;
|
||||
|
||||
GBytes *window_handle;
|
||||
|
||||
PikaUIManager *popup_manager;
|
||||
GdkMonitor *initial_monitor;
|
||||
|
||||
|
@ -1174,9 +1174,6 @@ pika_image_window_set_aux_info (PikaSessionManaged *session_managed,
|
||||
else if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED ||
|
||||
StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE ||
|
||||
StartupInfo.wShowWindow == SW_MINIMIZE)
|
||||
/* XXX Iconification does not seem to work. I see the
|
||||
* window being iconified and immediately re-raised.
|
||||
* I leave this piece of code for later improvement. */
|
||||
gtk_window_iconify (GTK_WINDOW (session_managed));
|
||||
else
|
||||
/* Another show property not relevant to min/max.
|
||||
|
@ -2026,8 +2026,10 @@ static void
|
||||
pika_tool_rectangle_update_options (PikaToolRectangle *rectangle)
|
||||
{
|
||||
PikaToolRectanglePrivate *private = rectangle->private;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
gdouble x1 = 0;
|
||||
gdouble y1 = 0;
|
||||
gdouble x2 = 0;
|
||||
gdouble y2 = 0;
|
||||
|
||||
pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2);
|
||||
|
||||
@ -2162,7 +2164,10 @@ static void
|
||||
pika_tool_rectangle_update_status (PikaToolRectangle *rectangle)
|
||||
{
|
||||
PikaToolRectanglePrivate *private = rectangle->private;
|
||||
gdouble x1, y1, x2, y2;
|
||||
gdouble x1 = 0;
|
||||
gdouble y1 = 0;
|
||||
gdouble x2 = 0;
|
||||
gdouble y2 = 0;
|
||||
|
||||
pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2);
|
||||
|
||||
@ -2436,7 +2441,10 @@ pika_tool_rectangle_coord_on_handle (PikaToolRectangle *rectangle,
|
||||
{
|
||||
PikaToolRectanglePrivate *private = rectangle->private;
|
||||
PikaDisplayShell *shell;
|
||||
gdouble x1, y1, x2, y2;
|
||||
gdouble x1 = 0;
|
||||
gdouble y1 = 0;
|
||||
gdouble x2 = 0;
|
||||
gdouble y2 = 0;
|
||||
gdouble rect_w, rect_h;
|
||||
gdouble handle_x = 0;
|
||||
gdouble handle_y = 0;
|
||||
@ -2838,7 +2846,10 @@ pika_tool_rectangle_setup_snap_offsets (PikaToolRectangle *rectangle,
|
||||
{
|
||||
PikaToolWidget *widget = PIKA_TOOL_WIDGET (rectangle);
|
||||
PikaToolRectanglePrivate *private = rectangle->private;
|
||||
gdouble x1, y1, x2, y2;
|
||||
gdouble x1 = 0;
|
||||
gdouble y1 = 0;
|
||||
gdouble x2 = 0;
|
||||
gdouble y2 = 0;
|
||||
gdouble coord_x, coord_y;
|
||||
|
||||
pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2);
|
||||
@ -4185,7 +4196,10 @@ pika_tool_rectangle_point_in_rectangle (PikaToolRectangle *rectangle,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
gdouble x1, y1, x2, y2;
|
||||
gdouble x1 = 0;
|
||||
gdouble y1 = 0;
|
||||
gdouble x2 = 0;
|
||||
gdouble y2 = 0;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_TOOL_RECTANGLE (rectangle), FALSE);
|
||||
|
||||
|
@ -35,11 +35,15 @@
|
||||
#include "core/pikabrush.h"
|
||||
#include "core/pikabrush-load.h"
|
||||
#include "core/pikabrush-private.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikadrawable.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikalayer-new.h"
|
||||
#include "core/pikaimage-merge.h"
|
||||
#include "core/pikaimage-new.h"
|
||||
#include "core/pikaimage-resize.h"
|
||||
#include "core/pikalayer-new.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
#include "core/pikapickable.h"
|
||||
#include "core/pikatempbuf.h"
|
||||
|
||||
#include "pdb/pikaprocedure.h"
|
||||
@ -51,12 +55,14 @@
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static PikaImage * file_gbr_brush_to_image (Pika *pika,
|
||||
PikaBrush *brush);
|
||||
static PikaBrush * file_gbr_image_to_brush (PikaImage *image,
|
||||
PikaDrawable *drawable,
|
||||
const gchar *name,
|
||||
gdouble spacing);
|
||||
static PikaImage * file_gbr_brush_to_image (Pika *pika,
|
||||
PikaBrush *brush);
|
||||
static PikaBrush * file_gbr_image_to_brush (PikaImage *image,
|
||||
PikaContext *context,
|
||||
gint n_drawables,
|
||||
PikaDrawable **drawables,
|
||||
const gchar *name,
|
||||
gdouble spacing);
|
||||
|
||||
|
||||
/* public functions */
|
||||
@ -119,24 +125,26 @@ file_gbr_save_invoker (PikaProcedure *procedure,
|
||||
const PikaValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
PikaValueArray *return_vals;
|
||||
PikaImage *image;
|
||||
PikaDrawable *drawable;
|
||||
PikaBrush *brush;
|
||||
const gchar *name;
|
||||
GFile *file;
|
||||
gint spacing;
|
||||
gboolean success;
|
||||
PikaValueArray *return_vals;
|
||||
PikaImage *image;
|
||||
PikaDrawable **drawables;
|
||||
gint n_drawables;
|
||||
PikaBrush *brush;
|
||||
const gchar *name;
|
||||
GFile *file;
|
||||
gint spacing;
|
||||
gboolean success;
|
||||
|
||||
pika_set_busy (pika);
|
||||
|
||||
image = g_value_get_object (pika_value_array_index (args, 1));
|
||||
drawable = g_value_get_object (pika_value_array_index (args, 2));
|
||||
file = g_value_get_object (pika_value_array_index (args, 3));
|
||||
spacing = g_value_get_int (pika_value_array_index (args, 4));
|
||||
name = g_value_get_string (pika_value_array_index (args, 5));
|
||||
image = g_value_get_object (pika_value_array_index (args, 1));
|
||||
n_drawables = g_value_get_int (pika_value_array_index (args, 2));
|
||||
drawables = (PikaDrawable **) pika_value_get_object_array (pika_value_array_index (args, 3));
|
||||
file = g_value_get_object (pika_value_array_index (args, 4));
|
||||
spacing = g_value_get_int (pika_value_array_index (args, 5));
|
||||
name = g_value_get_string (pika_value_array_index (args, 6));
|
||||
|
||||
brush = file_gbr_image_to_brush (image, drawable, name, spacing);
|
||||
brush = file_gbr_image_to_brush (image, context, n_drawables, drawables, name, spacing);
|
||||
|
||||
pika_data_set_file (PIKA_DATA (brush), file, TRUE, TRUE);
|
||||
|
||||
@ -417,15 +425,49 @@ file_gbr_brush_to_image (Pika *pika,
|
||||
}
|
||||
|
||||
static PikaBrush *
|
||||
file_gbr_image_to_brush (PikaImage *image,
|
||||
PikaDrawable *drawable,
|
||||
const gchar *name,
|
||||
gdouble spacing)
|
||||
file_gbr_image_to_brush (PikaImage *image,
|
||||
PikaContext *context,
|
||||
gint n_drawables,
|
||||
PikaDrawable **drawables,
|
||||
const gchar *name,
|
||||
gdouble spacing)
|
||||
{
|
||||
gint width = pika_item_get_width (PIKA_ITEM (drawable));
|
||||
gint height = pika_item_get_height (PIKA_ITEM (drawable));
|
||||
PikaBrush *brush;
|
||||
PikaImage *subimage = NULL;
|
||||
PikaDrawable *drawable;
|
||||
gint width;
|
||||
gint height;
|
||||
|
||||
return file_gbr_drawable_to_brush (drawable,
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
name, spacing);
|
||||
g_return_val_if_fail (n_drawables > 0, NULL);
|
||||
g_return_val_if_fail (drawables != NULL, NULL);
|
||||
|
||||
if (n_drawables > 1)
|
||||
{
|
||||
GList *drawable_list = NULL;
|
||||
|
||||
for (gint i = 0; i < n_drawables; i++)
|
||||
drawable_list = g_list_prepend (drawable_list, drawables[i]);
|
||||
|
||||
subimage = pika_image_new_from_drawables (image->pika, drawable_list, FALSE, FALSE);
|
||||
g_list_free (drawable_list);
|
||||
pika_container_remove (image->pika->images, PIKA_OBJECT (subimage));
|
||||
pika_image_resize_to_layers (subimage, context,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
drawable = PIKA_DRAWABLE (pika_image_merge_visible_layers (subimage, context, PIKA_CLIP_TO_IMAGE,
|
||||
FALSE, TRUE, NULL));
|
||||
pika_pickable_flush (PIKA_PICKABLE (subimage));
|
||||
}
|
||||
else
|
||||
{
|
||||
drawable = drawables[0];
|
||||
}
|
||||
width = pika_item_get_width (PIKA_ITEM (drawable));
|
||||
height = pika_item_get_height (PIKA_ITEM (drawable));
|
||||
|
||||
brush = file_gbr_drawable_to_brush (drawable,
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
name, spacing);
|
||||
g_clear_object (&subimage);
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
@ -260,6 +260,7 @@ file_pat_image_to_pattern (PikaImage *image,
|
||||
gint height;
|
||||
|
||||
g_return_val_if_fail (n_drawables > 0, NULL);
|
||||
g_return_val_if_fail (drawables != NULL, NULL);
|
||||
|
||||
if (n_drawables > 1)
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ file_data_init (Pika *pika)
|
||||
"1995-2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
@ -145,7 +145,7 @@ file_data_init (Pika *pika)
|
||||
"1995-2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
@ -158,12 +158,17 @@ file_data_init (Pika *pika)
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_drawable ("drawable",
|
||||
"Drawable",
|
||||
"Active drawable "
|
||||
"of input image",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
g_param_spec_int ("num-drawables",
|
||||
"Num drawables",
|
||||
"Number of drawables",
|
||||
1, G_MAXINT, 1,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_object_array ("drawables",
|
||||
"Drawables",
|
||||
"Selected drawables",
|
||||
PIKA_TYPE_DRAWABLE,
|
||||
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_object ("file",
|
||||
"File",
|
||||
@ -219,7 +224,7 @@ file_data_init (Pika *pika)
|
||||
"1999-2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
@ -277,7 +282,7 @@ file_data_init (Pika *pika)
|
||||
"1999-2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
@ -363,7 +368,7 @@ file_data_init (Pika *pika)
|
||||
"1997-2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
@ -420,7 +425,7 @@ file_data_init (Pika *pika)
|
||||
"1995-2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
@ -433,7 +438,7 @@ file_data_init (Pika *pika)
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_int ("n-drawables",
|
||||
g_param_spec_int ("num-drawables",
|
||||
"Num drawables",
|
||||
"Number of drawables",
|
||||
1, G_MAXINT, 1,
|
||||
@ -491,7 +496,7 @@ file_data_init (Pika *pika)
|
||||
"Jehan", "Jehan", "2019");
|
||||
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_enum ("dummy-param",
|
||||
pika_param_spec_enum ("run-mode",
|
||||
"Dummy Param",
|
||||
"Dummy parameter",
|
||||
PIKA_TYPE_RUN_MODE,
|
||||
|
@ -374,7 +374,7 @@ file_open_thumbnail (Pika *pika,
|
||||
{
|
||||
image = g_value_get_object (pika_value_array_index (return_vals, 1));
|
||||
|
||||
if (pika_value_array_length (return_vals) >= 3 &&
|
||||
if (pika_value_array_length (return_vals) >= 4 &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 2)) &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 3)))
|
||||
{
|
||||
@ -385,11 +385,11 @@ file_open_thumbnail (Pika *pika,
|
||||
MAX (0, g_value_get_int (pika_value_array_index (return_vals, 3)));
|
||||
|
||||
if (pika_value_array_length (return_vals) >= 5 &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 4)))
|
||||
G_VALUE_HOLDS_ENUM (pika_value_array_index (return_vals, 4)))
|
||||
{
|
||||
gint value = g_value_get_int (pika_value_array_index (return_vals, 4));
|
||||
PikaImageType itype = g_value_get_enum (pika_value_array_index (return_vals, 4));
|
||||
|
||||
switch (value)
|
||||
switch (itype)
|
||||
{
|
||||
case PIKA_RGB_IMAGE:
|
||||
*format = pika_babl_format (PIKA_RGB,
|
||||
@ -424,7 +424,7 @@ file_open_thumbnail (Pika *pika,
|
||||
babl_new_palette ("-pika-indexed-format-dummy",
|
||||
&rgb, &rgba);
|
||||
|
||||
if (value == PIKA_INDEXED_IMAGE)
|
||||
if (itype == PIKA_INDEXED_IMAGE)
|
||||
*format = rgb;
|
||||
else
|
||||
*format = rgba;
|
||||
|
@ -918,6 +918,98 @@ pika_gegl_index_to_mask (GeglBuffer *indexed_buffer,
|
||||
});
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_gegl_is_index_used (GeglBuffer *indexed_buffer,
|
||||
const GeglRectangle *indexed_rect,
|
||||
const Babl *indexed_format,
|
||||
gint index)
|
||||
{
|
||||
GeglBufferIterator *iter;
|
||||
gboolean found = FALSE;
|
||||
|
||||
if (! indexed_rect)
|
||||
indexed_rect = gegl_buffer_get_extent (indexed_buffer);
|
||||
|
||||
iter = gegl_buffer_iterator_new (indexed_buffer, indexed_rect, 0,
|
||||
indexed_format,
|
||||
GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
|
||||
|
||||
/* I initially had an implementation using gegl_parallel_distribute_area()
|
||||
* which turned out to be much slower than the simpler iteration on the whole
|
||||
* buffer at once. I think the cost of threading and using GRWLock is just far
|
||||
* too high for such very basic value check.
|
||||
* See gegl_parallel_distribute_area() implementation in commit dbaa8b6a1c.
|
||||
*/
|
||||
while (gegl_buffer_iterator_next (iter))
|
||||
{
|
||||
const guchar *indexed = (const guchar *) iter->items[0].data;
|
||||
gint count = iter->length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (*indexed == index)
|
||||
{
|
||||
/*
|
||||
* Position of one item using this color index:
|
||||
gint x = iter->items[0].roi.x + (iter->length - count - 1) % iter->items[0].roi.width;
|
||||
gint y = iter->items[0].roi.y + (gint) ((iter->length - count - 1) / iter->items[0].roi.width);
|
||||
*/
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
indexed++;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
gegl_buffer_iterator_stop (iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void
|
||||
pika_gegl_shift_index (GeglBuffer *indexed_buffer,
|
||||
const GeglRectangle *indexed_rect,
|
||||
const Babl *indexed_format,
|
||||
gint from_index,
|
||||
gint shift)
|
||||
{
|
||||
gboolean indexed_format_has_alpha;
|
||||
|
||||
if (! indexed_rect)
|
||||
indexed_rect = gegl_buffer_get_extent (indexed_buffer);
|
||||
|
||||
indexed_format_has_alpha = babl_format_has_alpha (indexed_format);
|
||||
|
||||
gegl_parallel_distribute_area (
|
||||
indexed_rect, PIXELS_PER_THREAD,
|
||||
[=] (const GeglRectangle *indexed_area)
|
||||
{
|
||||
GeglBufferIterator *iter;
|
||||
|
||||
iter = gegl_buffer_iterator_new (indexed_buffer, indexed_area, 0,
|
||||
indexed_format,
|
||||
GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
|
||||
|
||||
while (gegl_buffer_iterator_next (iter))
|
||||
{
|
||||
guchar *indexed = (guchar *) iter->items[0].data;
|
||||
gint count = iter->length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (*indexed >= from_index)
|
||||
*indexed += shift;
|
||||
|
||||
indexed += (indexed_format_has_alpha ? 2 : 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void
|
||||
pika_gegl_convert_color_profile_progress (PikaProgress *progress,
|
||||
gdouble value)
|
||||
|
@ -91,6 +91,15 @@ void pika_gegl_index_to_mask (GeglBuffer *indexed_buffer
|
||||
GeglBuffer *mask_buffer,
|
||||
const GeglRectangle *mask_rect,
|
||||
gint index);
|
||||
gboolean pika_gegl_is_index_used (GeglBuffer *indexed_buffer,
|
||||
const GeglRectangle *indexed_rect,
|
||||
const Babl *indexed_format,
|
||||
gint index);
|
||||
void pika_gegl_shift_index (GeglBuffer *indexed_buffer,
|
||||
const GeglRectangle *indexed_rect,
|
||||
const Babl *indexed_format,
|
||||
gint from_index,
|
||||
gint shift);
|
||||
|
||||
void pika_gegl_convert_color_profile (GeglBuffer *src_buffer,
|
||||
const GeglRectangle *src_rect,
|
||||
|
@ -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 (©_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, ©_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)
|
||||
|
@ -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);
|
||||
|
@ -287,10 +287,7 @@ progress_error_dialog (PikaProgress *progress)
|
||||
}
|
||||
else
|
||||
{
|
||||
guint32 window_id = pika_progress_get_window_id (progress);
|
||||
|
||||
if (window_id)
|
||||
pika_window_set_transient_for (GTK_WINDOW (dialog), window_id);
|
||||
pika_window_set_transient_for (GTK_WINDOW (dialog), progress);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,8 @@
|
||||
#include "core/pikacancelable.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/pikaimagefile.h"
|
||||
@ -89,6 +91,7 @@
|
||||
#include "widgets/pikamenufactory.h"
|
||||
#include "widgets/pikapaletteselect.h"
|
||||
#include "widgets/pikapatternselect.h"
|
||||
#include "widgets/pikapickableselect.h"
|
||||
#include "widgets/pikaprogressdialog.h"
|
||||
#include "widgets/pikauimanager.h"
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
@ -136,7 +139,7 @@ static GFile * gui_get_theme_dir (Pika *pika);
|
||||
static GFile * gui_get_icon_theme_dir (Pika *pika);
|
||||
static PikaObject * gui_get_window_strategy (Pika *pika);
|
||||
static PikaDisplay * gui_get_empty_display (Pika *pika);
|
||||
static guint32 gui_display_get_window_id (PikaDisplay *display);
|
||||
static GBytes * gui_display_get_window_id (PikaDisplay *display);
|
||||
static PikaDisplay * gui_display_create (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
@ -156,18 +159,19 @@ static void gui_free_progress (Pika *pika,
|
||||
static gboolean gui_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType object_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args);
|
||||
static gboolean gui_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args);
|
||||
static gboolean gui_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name);
|
||||
static gboolean gui_recent_list_add_file (Pika *pika,
|
||||
GFile *file,
|
||||
@ -378,7 +382,7 @@ gui_get_empty_display (Pika *pika)
|
||||
return display;
|
||||
}
|
||||
|
||||
static guint32
|
||||
static GBytes *
|
||||
gui_display_get_window_id (PikaDisplay *display)
|
||||
{
|
||||
PikaDisplay *disp = PIKA_DISPLAY (display);
|
||||
@ -386,13 +390,11 @@ gui_display_get_window_id (PikaDisplay *display)
|
||||
|
||||
if (shell)
|
||||
{
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
|
||||
|
||||
if (GTK_IS_WINDOW (toplevel))
|
||||
return pika_window_get_native_id (GTK_WINDOW (toplevel));
|
||||
if (shell)
|
||||
return g_bytes_ref (shell->window_handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PikaDisplay *
|
||||
@ -516,16 +518,16 @@ gui_wait (Pika *pika,
|
||||
args = pika_procedure_get_arguments (procedure);
|
||||
pika_value_array_truncate (args, 5);
|
||||
|
||||
g_value_set_enum (pika_value_array_index (args, 0),
|
||||
PIKA_RUN_INTERACTIVE);
|
||||
g_value_set_int (pika_value_array_index (args, 1),
|
||||
output_pipe[0]);
|
||||
g_value_set_int (pika_value_array_index (args, 2),
|
||||
input_pipe[1]);
|
||||
g_value_set_string (pika_value_array_index (args, 3),
|
||||
message);
|
||||
g_value_set_int (pika_value_array_index (args, 4),
|
||||
PIKA_IS_CANCELABLE (waitable));
|
||||
g_value_set_enum (pika_value_array_index (args, 0),
|
||||
PIKA_RUN_INTERACTIVE);
|
||||
g_value_set_int (pika_value_array_index (args, 1),
|
||||
output_pipe[0]);
|
||||
g_value_set_int (pika_value_array_index (args, 2),
|
||||
input_pipe[1]);
|
||||
g_value_set_string (pika_value_array_index (args, 3),
|
||||
message);
|
||||
g_value_set_boolean (pika_value_array_index (args, 4),
|
||||
PIKA_IS_CANCELABLE (waitable));
|
||||
|
||||
pika_procedure_execute_async (procedure, pika,
|
||||
pika_get_user_context (pika),
|
||||
@ -616,65 +618,74 @@ static gboolean
|
||||
gui_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args)
|
||||
{
|
||||
GType dialog_type = G_TYPE_NONE;
|
||||
const gchar *dialog_role = NULL;
|
||||
const gchar *help_id = NULL;
|
||||
|
||||
if (pika_container_get_children_type (container) == PIKA_TYPE_BRUSH)
|
||||
if (contents_type == PIKA_TYPE_BRUSH)
|
||||
{
|
||||
dialog_type = PIKA_TYPE_BRUSH_SELECT;
|
||||
dialog_role = "pika-brush-selection";
|
||||
help_id = PIKA_HELP_BRUSH_DIALOG;
|
||||
}
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_FONT)
|
||||
else if (contents_type == PIKA_TYPE_FONT)
|
||||
{
|
||||
dialog_type = PIKA_TYPE_FONT_SELECT;
|
||||
dialog_role = "pika-font-selection";
|
||||
help_id = PIKA_HELP_FONT_DIALOG;
|
||||
}
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_GRADIENT)
|
||||
else if (contents_type == PIKA_TYPE_GRADIENT)
|
||||
{
|
||||
dialog_type = PIKA_TYPE_GRADIENT_SELECT;
|
||||
dialog_role = "pika-gradient-selection";
|
||||
help_id = PIKA_HELP_GRADIENT_DIALOG;
|
||||
}
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_PALETTE)
|
||||
else if (contents_type == PIKA_TYPE_PALETTE)
|
||||
{
|
||||
dialog_type = PIKA_TYPE_PALETTE_SELECT;
|
||||
dialog_role = "pika-palette-selection";
|
||||
help_id = PIKA_HELP_PALETTE_DIALOG;
|
||||
}
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_PATTERN)
|
||||
else if (contents_type == PIKA_TYPE_PATTERN)
|
||||
{
|
||||
dialog_type = PIKA_TYPE_PATTERN_SELECT;
|
||||
dialog_role = "pika-pattern-selection";
|
||||
help_id = PIKA_HELP_PATTERN_DIALOG;
|
||||
}
|
||||
else if (g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
|
||||
{
|
||||
dialog_type = PIKA_TYPE_PICKABLE_SELECT;
|
||||
dialog_role = "pika-pickable-selection";
|
||||
}
|
||||
else
|
||||
{
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
if (dialog_type != G_TYPE_NONE)
|
||||
{
|
||||
PikaObject *object = NULL;
|
||||
if (! object && ! g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
|
||||
object = pika_context_get_by_type (context, contents_type);
|
||||
|
||||
if (object_name && strlen (object_name))
|
||||
object = pika_container_get_child_by_name (container, object_name);
|
||||
|
||||
if (! object)
|
||||
object = pika_context_get_by_type (context,
|
||||
pika_container_get_children_type (container));
|
||||
|
||||
if (object)
|
||||
if (object || g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
|
||||
{
|
||||
gint n_properties = 0;
|
||||
gchar **names = NULL;
|
||||
GValue *values = NULL;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *view;
|
||||
gboolean use_header_bar;
|
||||
|
||||
g_object_get (gtk_settings_get_default (),
|
||||
"gtk-dialogs-use-header", &use_header_bar,
|
||||
NULL);
|
||||
|
||||
names = pika_properties_append (dialog_type,
|
||||
&n_properties, names, &values,
|
||||
@ -684,10 +695,11 @@ gui_pdb_dialog_new (Pika *pika,
|
||||
"help-id", help_id,
|
||||
"pdb", pika->pdb,
|
||||
"context", context,
|
||||
"select-type", pika_container_get_children_type (container),
|
||||
"select-type", contents_type,
|
||||
"initial-object", object,
|
||||
"callback-name", callback_name,
|
||||
"menu-factory", menus_get_global_menu_factory (pika),
|
||||
"use-header-bar", use_header_bar,
|
||||
NULL);
|
||||
|
||||
names = pika_properties_append_valist (dialog_type,
|
||||
@ -707,27 +719,25 @@ gui_pdb_dialog_new (Pika *pika,
|
||||
pika_docked_set_show_button_bar (PIKA_DOCKED (view), FALSE);
|
||||
|
||||
if (progress)
|
||||
{
|
||||
guint32 window_id = pika_progress_get_window_id (progress);
|
||||
|
||||
if (window_id)
|
||||
pika_window_set_transient_for (GTK_WINDOW (dialog), window_id);
|
||||
}
|
||||
pika_window_set_transient_for (GTK_WINDOW (dialog), progress);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
/* workaround for bug #360106 */
|
||||
{
|
||||
GSource *source = g_timeout_source_new (100);
|
||||
GClosure *closure;
|
||||
{
|
||||
GSource *source = g_timeout_source_new (100);
|
||||
GClosure *closure;
|
||||
|
||||
closure = g_cclosure_new_object (G_CALLBACK (gui_pdb_dialog_present),
|
||||
G_OBJECT (dialog));
|
||||
closure = g_cclosure_new_object (G_CALLBACK (gui_pdb_dialog_present),
|
||||
G_OBJECT (dialog));
|
||||
|
||||
g_source_set_closure (source, closure);
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
}
|
||||
g_source_set_closure (source, closure);
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
if (parent_handle != NULL)
|
||||
pika_window_set_transient_for_handle (GTK_WINDOW (dialog), parent_handle);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -738,73 +748,96 @@ gui_pdb_dialog_new (Pika *pika,
|
||||
|
||||
static gboolean
|
||||
gui_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args)
|
||||
{
|
||||
PikaPdbDialogClass *klass = NULL;
|
||||
PikaPdbDialogClass *klass = NULL;
|
||||
PikaContainer *container = NULL;
|
||||
PikaPdbDialog *dialog;
|
||||
|
||||
if (pika_container_get_children_type (container) == PIKA_TYPE_BRUSH)
|
||||
klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_FONT)
|
||||
klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_GRADIENT)
|
||||
klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_PALETTE)
|
||||
klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_PATTERN)
|
||||
klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT);
|
||||
|
||||
if (klass)
|
||||
if (contents_type == PIKA_TYPE_BRUSH)
|
||||
{
|
||||
PikaPdbDialog *dialog;
|
||||
klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT);
|
||||
container = pika_data_factory_get_container (pika->brush_factory);
|
||||
}
|
||||
else if (contents_type == PIKA_TYPE_FONT)
|
||||
{
|
||||
klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT);
|
||||
container = pika_data_factory_get_container (pika->font_factory);
|
||||
}
|
||||
else if (contents_type == PIKA_TYPE_GRADIENT)
|
||||
{
|
||||
klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT);
|
||||
container = pika_data_factory_get_container (pika->gradient_factory);
|
||||
}
|
||||
else if (contents_type == PIKA_TYPE_PALETTE)
|
||||
{
|
||||
klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT);
|
||||
container = pika_data_factory_get_container (pika->palette_factory);
|
||||
}
|
||||
else if (contents_type == PIKA_TYPE_PATTERN)
|
||||
{
|
||||
klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT);
|
||||
container = pika_data_factory_get_container (pika->pattern_factory);
|
||||
}
|
||||
else if (contents_type == PIKA_TYPE_DRAWABLE)
|
||||
{
|
||||
klass = g_type_class_peek (PIKA_TYPE_PICKABLE_SELECT);
|
||||
}
|
||||
|
||||
dialog = pika_pdb_dialog_get_by_callback (klass, callback_name);
|
||||
g_return_val_if_fail (klass != NULL, FALSE);
|
||||
|
||||
if (dialog && dialog->select_type == pika_container_get_children_type (container))
|
||||
dialog = pika_pdb_dialog_get_by_callback (klass, callback_name);
|
||||
|
||||
if (dialog != NULL &&
|
||||
dialog->select_type == contents_type &&
|
||||
(container == NULL || pika_container_get_child_index (container, object) != -1))
|
||||
{
|
||||
const gchar *prop_name = va_arg (args, const gchar *);
|
||||
|
||||
if (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE))
|
||||
{
|
||||
PikaObject *object;
|
||||
|
||||
object = pika_container_get_child_by_name (container, object_name);
|
||||
|
||||
if (object)
|
||||
{
|
||||
const gchar *prop_name = va_arg (args, const gchar *);
|
||||
|
||||
pika_context_set_by_type (dialog->context, dialog->select_type,
|
||||
object);
|
||||
|
||||
if (prop_name)
|
||||
g_object_set_valist (G_OBJECT (dialog), prop_name, args);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (dialog));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
g_return_val_if_fail (container != NULL, FALSE);
|
||||
pika_context_set_by_type (dialog->context, dialog->select_type, object);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_return_val_if_fail (klass->set_object != NULL, FALSE);
|
||||
klass->set_object (dialog, object);
|
||||
}
|
||||
|
||||
if (prop_name)
|
||||
g_object_set_valist (G_OBJECT (dialog), prop_name, args);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (dialog));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gui_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name)
|
||||
gui_pdb_dialog_close (Pika *pika,
|
||||
GType contents_type,
|
||||
const gchar *callback_name)
|
||||
{
|
||||
PikaPdbDialogClass *klass = NULL;
|
||||
|
||||
if (pika_container_get_children_type (container) == PIKA_TYPE_BRUSH)
|
||||
if (contents_type == PIKA_TYPE_BRUSH)
|
||||
klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_FONT)
|
||||
else if (contents_type == PIKA_TYPE_FONT)
|
||||
klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_GRADIENT)
|
||||
else if (contents_type == PIKA_TYPE_GRADIENT)
|
||||
klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_PALETTE)
|
||||
else if (contents_type == PIKA_TYPE_PALETTE)
|
||||
klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT);
|
||||
else if (pika_container_get_children_type (container) == PIKA_TYPE_PATTERN)
|
||||
else if (contents_type == PIKA_TYPE_PATTERN)
|
||||
klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT);
|
||||
else if (contents_type == PIKA_TYPE_DRAWABLE)
|
||||
klass = g_type_class_peek (PIKA_TYPE_PICKABLE_SELECT);
|
||||
|
||||
if (klass)
|
||||
{
|
||||
@ -812,7 +845,7 @@ gui_pdb_dialog_close (Pika *pika,
|
||||
|
||||
dialog = pika_pdb_dialog_get_by_callback (klass, callback_name);
|
||||
|
||||
if (dialog && dialog->select_type == pika_container_get_children_type (container))
|
||||
if (dialog && dialog->select_type == contents_type)
|
||||
{
|
||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||
return TRUE;
|
||||
|
@ -90,6 +90,12 @@
|
||||
#include "splash.h"
|
||||
#include "themes.h"
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef GDK_WINDOWING_QUARTZ
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@ -543,6 +549,11 @@ gui_restore_after_callback (Pika *pika,
|
||||
PikaGuiConfig *gui_config = PIKA_GUI_CONFIG (pika->config);
|
||||
PikaUIManager *image_ui_manager;
|
||||
PikaDisplay *display;
|
||||
#ifdef G_OS_WIN32
|
||||
STARTUPINFO StartupInfo;
|
||||
|
||||
GetStartupInfo (&StartupInfo);
|
||||
#endif
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("INIT: %s\n", G_STRFUNC);
|
||||
@ -610,11 +621,23 @@ gui_restore_after_callback (Pika *pika,
|
||||
|
||||
shell = pika_display_get_shell (display);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
themes_set_title_bar (pika);
|
||||
#endif
|
||||
|
||||
if (gui_config->restore_session)
|
||||
session_restore (pika, initial_monitor);
|
||||
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* Prevents window from reappearing on start-up if the user
|
||||
* requested it to be minimized via window hints
|
||||
*/
|
||||
if (StartupInfo.wShowWindow != SW_SHOWMINIMIZED &&
|
||||
StartupInfo.wShowWindow != SW_SHOWMINNOACTIVE &&
|
||||
StartupInfo.wShowWindow != SW_MINIMIZE)
|
||||
#endif
|
||||
/* move keyboard focus to the display */
|
||||
gtk_window_present (GTK_WINDOW (toplevel));
|
||||
}
|
||||
@ -925,12 +948,26 @@ gui_check_unique_accelerators (Pika *pika)
|
||||
gchar **disabled_accels;
|
||||
gint len;
|
||||
gint remove;
|
||||
gboolean print_warning = TRUE;
|
||||
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app),
|
||||
actions[i]);
|
||||
/* Just keep the first one (no reason other than we have
|
||||
* to choose), unless it's a secondary shortcut, and the
|
||||
* second is a primary shortcut.
|
||||
*/
|
||||
if (l == 0 && j != 0)
|
||||
if ((l == 0 && j != 0) ||
|
||||
/* If the first action is one of "view-zoom-1-*" and
|
||||
* the shortcut default, we assume it's because of our
|
||||
* trick to transform `Shift+num` shortcuts based on
|
||||
* layout and we happen to be on a layout where it
|
||||
* clashes with other shortcuts. In this case, we
|
||||
* drop the duplicate shortcut on the zoom action. See
|
||||
* special code in
|
||||
* pika_action_group_add_action_with_accel()
|
||||
*/
|
||||
(g_str_has_prefix (actions[i], "view-zoom-1-") &&
|
||||
pika_action_is_default_accel (PIKA_ACTION (action), accels[j])))
|
||||
{
|
||||
disabled_action = actions[i];
|
||||
disabled_accels = accels;
|
||||
@ -942,6 +979,20 @@ gui_check_unique_accelerators (Pika *pika)
|
||||
disabled_accels = accels2;
|
||||
remove = l;
|
||||
}
|
||||
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app),
|
||||
disabled_action);
|
||||
|
||||
if (g_str_has_prefix (disabled_action, "view-zoom-1-") &&
|
||||
pika_action_is_default_accel (PIKA_ACTION (action), disabled_accels[remove]))
|
||||
/* We drop the shortcut **silently** because it will be
|
||||
* a case where we have 2 default accelerators clashing
|
||||
* (because of the conversion code) while not being a
|
||||
* real bug. Clashes with custom accelerators are
|
||||
* handled by shortcuts_action_deserialize().
|
||||
*/
|
||||
print_warning = FALSE;
|
||||
|
||||
/* Remove only the duplicate shortcut but keep others. */
|
||||
len = g_strv_length (disabled_accels);
|
||||
g_free (disabled_accels[remove]);
|
||||
@ -949,12 +1000,11 @@ gui_check_unique_accelerators (Pika *pika)
|
||||
&disabled_accels[remove + 1],
|
||||
sizeof (char *) * (len - remove));
|
||||
|
||||
g_printerr ("Actions \"%s\" and \"%s\" use the same accelerator.\n"
|
||||
" Disabling the accelerator on \"%s\".\n",
|
||||
actions[i], actions[k], disabled_action);
|
||||
if (print_warning)
|
||||
g_printerr ("Actions \"%s\" and \"%s\" use the same accelerator.\n"
|
||||
" Disabling the accelerator on \"%s\".\n",
|
||||
actions[i], actions[k], disabled_action);
|
||||
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app),
|
||||
disabled_action);
|
||||
pika_action_set_accels (PIKA_ACTION (action),
|
||||
(const gchar **) disabled_accels);
|
||||
}
|
||||
|
@ -29,6 +29,12 @@
|
||||
#include <gdk/gdkwayland.h>
|
||||
#endif
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
@ -125,6 +131,11 @@ splash_create (Pika *pika,
|
||||
GdkRectangle workarea;
|
||||
gint max_width;
|
||||
gint max_height;
|
||||
#ifdef G_OS_WIN32
|
||||
STARTUPINFO StartupInfo;
|
||||
|
||||
GetStartupInfo (&StartupInfo);
|
||||
#endif
|
||||
|
||||
g_return_if_fail (splash == NULL);
|
||||
g_return_if_fail (GDK_IS_MONITOR (monitor));
|
||||
@ -255,6 +266,13 @@ splash_create (Pika *pika,
|
||||
|
||||
gtk_widget_show (splash->window);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED ||
|
||||
StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE ||
|
||||
StartupInfo.wShowWindow == SW_MINIMIZE)
|
||||
gtk_window_iconify (GTK_WINDOW (splash->window));
|
||||
#endif
|
||||
|
||||
if (FALSE)
|
||||
splash->timer = g_timer_new ();
|
||||
}
|
||||
|
@ -35,6 +35,10 @@
|
||||
|
||||
#include "core/pika.h"
|
||||
|
||||
#include "display/pikaimagewindow.h"
|
||||
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
|
||||
#include "themes.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
@ -109,6 +113,10 @@ themes_init (Pika *pika)
|
||||
pika);
|
||||
|
||||
themes_theme_change_notify (config, NULL, pika);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
themes_set_title_bar (pika);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -473,6 +481,10 @@ themes_theme_change_notify (PikaGuiConfig *config,
|
||||
g_object_unref (theme_css);
|
||||
|
||||
gtk_style_context_reset_widgets (gdk_screen_get_default ());
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
themes_set_title_bar (pika);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -553,3 +565,22 @@ themes_theme_paths_notify (PikaExtensionManager *manager,
|
||||
g_list_free_full (path, (GDestroyNotify) g_object_unref);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
themes_set_title_bar (Pika *pika)
|
||||
{
|
||||
#ifdef G_OS_WIN32
|
||||
GList *windows = pika_get_image_windows (pika);
|
||||
GList *iter;
|
||||
|
||||
for (iter = windows; iter; iter = g_list_next (iter))
|
||||
{
|
||||
GtkWidget *window = GTK_WIDGET (windows->data);
|
||||
|
||||
pika_window_set_title_bar_theme (pika, window, TRUE);
|
||||
}
|
||||
|
||||
if (windows)
|
||||
g_list_free (windows);
|
||||
#endif
|
||||
}
|
||||
|
@ -34,5 +34,6 @@ GFile * themes_get_theme_file (Pika *pika,
|
||||
const gchar *first_component,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
void themes_set_title_bar (Pika *pika);
|
||||
|
||||
#endif /* __THEMES_H__ */
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikabase/pikaprotocol.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "menus-types.h"
|
||||
@ -56,8 +55,7 @@ static GTokenType shortcuts_action_deserialize (GScanner *scanner,
|
||||
|
||||
enum
|
||||
{
|
||||
PROTOCOL_VERSION = 1,
|
||||
FILE_VERSION,
|
||||
FILE_VERSION = 1,
|
||||
ACTION,
|
||||
};
|
||||
|
||||
@ -68,8 +66,7 @@ shortcuts_rc_parse (GtkApplication *application,
|
||||
GError **error)
|
||||
{
|
||||
GScanner *scanner;
|
||||
gint protocol_version = PIKA_PROTOCOL_VERSION;
|
||||
gint file_version = SHORTCUTS_RC_FILE_VERSION;
|
||||
gint file_version = SHORTCUTS_RC_FILE_VERSION;
|
||||
GTokenType token;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE);
|
||||
@ -81,9 +78,6 @@ shortcuts_rc_parse (GtkApplication *application,
|
||||
if (! scanner)
|
||||
return FALSE;
|
||||
|
||||
g_scanner_scope_add_symbol (scanner, 0,
|
||||
"protocol-version",
|
||||
GINT_TO_POINTER (PROTOCOL_VERSION));
|
||||
g_scanner_scope_add_symbol (scanner, 0,
|
||||
"file-version",
|
||||
GINT_TO_POINTER (FILE_VERSION));
|
||||
@ -92,9 +86,9 @@ shortcuts_rc_parse (GtkApplication *application,
|
||||
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
|
||||
while (protocol_version == PIKA_PROTOCOL_VERSION &&
|
||||
file_version == SHORTCUTS_RC_FILE_VERSION &&
|
||||
g_scanner_peek_next_token (scanner) == token)
|
||||
while (g_scanner_peek_next_token (scanner) == token ||
|
||||
(token == G_TOKEN_SYMBOL &&
|
||||
g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER))
|
||||
{
|
||||
token = g_scanner_get_next_token (scanner);
|
||||
|
||||
@ -107,12 +101,6 @@ shortcuts_rc_parse (GtkApplication *application,
|
||||
case G_TOKEN_SYMBOL:
|
||||
switch (GPOINTER_TO_INT (scanner->value.v_symbol))
|
||||
{
|
||||
case PROTOCOL_VERSION:
|
||||
token = G_TOKEN_INT;
|
||||
if (pika_scanner_parse_int (scanner, &protocol_version))
|
||||
token = G_TOKEN_RIGHT_PAREN;
|
||||
break;
|
||||
|
||||
case FILE_VERSION:
|
||||
token = G_TOKEN_INT;
|
||||
if (pika_scanner_parse_int (scanner, &file_version))
|
||||
@ -127,7 +115,17 @@ shortcuts_rc_parse (GtkApplication *application,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case G_TOKEN_IDENTIFIER:
|
||||
g_printerr ("%s: ignoring unknown symbol '%s'.\n", G_STRFUNC, scanner->value.v_string);
|
||||
while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
|
||||
{
|
||||
if (token == G_TOKEN_RIGHT_PAREN)
|
||||
break;
|
||||
}
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
break;
|
||||
|
||||
case G_TOKEN_RIGHT_PAREN:
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
@ -138,25 +136,16 @@ shortcuts_rc_parse (GtkApplication *application,
|
||||
}
|
||||
}
|
||||
|
||||
if (protocol_version != PIKA_PROTOCOL_VERSION ||
|
||||
file_version != SHORTCUTS_RC_FILE_VERSION ||
|
||||
token != G_TOKEN_LEFT_PAREN)
|
||||
if (file_version != SHORTCUTS_RC_FILE_VERSION)
|
||||
{
|
||||
if (protocol_version != PIKA_PROTOCOL_VERSION)
|
||||
{
|
||||
g_set_error (error,
|
||||
PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_VERSION,
|
||||
_("Skipping '%s': wrong PIKA protocol version."),
|
||||
pika_file_get_utf8_name (file));
|
||||
}
|
||||
else if (file_version != SHORTCUTS_RC_FILE_VERSION)
|
||||
{
|
||||
g_set_error (error,
|
||||
PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_VERSION,
|
||||
_("Skipping '%s': wrong shortcutsrc file format version."),
|
||||
pika_file_get_utf8_name (file));
|
||||
}
|
||||
else if (token != G_TOKEN_ERROR)
|
||||
g_printerr (_("Wrong shortcutsrc (%s) file format version: %d (expected: %d). "
|
||||
"We tried to load shortcuts as well as possible.\n"),
|
||||
pika_file_get_utf8_name (file),
|
||||
file_version, SHORTCUTS_RC_FILE_VERSION);
|
||||
}
|
||||
if (token != G_TOKEN_LEFT_PAREN)
|
||||
{
|
||||
if (token != G_TOKEN_ERROR)
|
||||
{
|
||||
g_scanner_get_next_token (scanner);
|
||||
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
|
||||
@ -194,10 +183,6 @@ shortcuts_rc_write (GtkApplication *application,
|
||||
|
||||
actions = g_action_group_list_actions (G_ACTION_GROUP (application));
|
||||
|
||||
pika_config_writer_open (writer, "protocol-version");
|
||||
pika_config_writer_printf (writer, "%d", PIKA_PROTOCOL_VERSION);
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_open (writer, "file-version");
|
||||
pika_config_writer_printf (writer, "%d", SHORTCUTS_RC_FILE_VERSION);
|
||||
pika_config_writer_close (writer);
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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__ */
|
||||
|
@ -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 *
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
PikaMybrushOptions *options;
|
||||
};
|
||||
|
||||
@ -382,6 +384,8 @@ pika_mypaint_surface_draw_dab (MyPaintSurface *base_surface,
|
||||
colorize = opaque * colorize;
|
||||
|
||||
/* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
|
||||
x += surface->off_x;
|
||||
y += surface->off_y;
|
||||
dabRect = calculate_dab_roi (x, y, radius);
|
||||
gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));
|
||||
|
||||
@ -561,5 +565,40 @@ pika_mypaint_surface_new (GeglBuffer *buffer,
|
||||
surface->paint_mask_y = paint_mask_y;
|
||||
surface->dirty = *GEGL_RECTANGLE (0, 0, 0, 0);
|
||||
|
||||
surface->off_x = 0;
|
||||
surface->off_y = 0;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
void
|
||||
pika_mypaint_surface_set_buffer (PikaMybrushSurface *surface,
|
||||
GeglBuffer *buffer,
|
||||
gint paint_mask_x,
|
||||
gint paint_mask_y)
|
||||
{
|
||||
g_object_unref (surface->buffer);
|
||||
|
||||
surface->buffer = g_object_ref (buffer);
|
||||
|
||||
surface->paint_mask_x = paint_mask_x;
|
||||
surface->paint_mask_y = paint_mask_y;
|
||||
}
|
||||
|
||||
void
|
||||
pika_mypaint_surface_set_offset (PikaMybrushSurface *surface,
|
||||
gint off_x,
|
||||
gint off_y)
|
||||
{
|
||||
surface->off_x = off_x;
|
||||
surface->off_y = off_y;
|
||||
}
|
||||
|
||||
void
|
||||
pika_mypaint_surface_get_offset (PikaMybrushSurface *surface,
|
||||
gint *off_x,
|
||||
gint *off_y)
|
||||
{
|
||||
*off_x = surface->off_x;
|
||||
*off_y = surface->off_y;
|
||||
}
|
||||
|
@ -33,5 +33,18 @@ pika_mypaint_surface_new (GeglBuffer *buffer,
|
||||
gint paint_mask_y,
|
||||
PikaMybrushOptions *options);
|
||||
|
||||
void
|
||||
pika_mypaint_surface_set_buffer (PikaMybrushSurface *surface,
|
||||
GeglBuffer *buffer,
|
||||
gint paint_mask_x,
|
||||
gint paint_mask_y);
|
||||
void
|
||||
pika_mypaint_surface_set_offset (PikaMybrushSurface *surface,
|
||||
gint off_x,
|
||||
gint off_y);
|
||||
void
|
||||
pika_mypaint_surface_get_offset (PikaMybrushSurface *surface,
|
||||
gint *off_x,
|
||||
gint *off_y);
|
||||
|
||||
#endif /* __PIKA_MYBRUSH_SURFACE_H__ */
|
||||
|
@ -193,7 +193,8 @@ pika_paintbrush_real_get_paint_params (PikaPaintbrush *paintbrush,
|
||||
|
||||
*paint_mode = pika_context_get_paint_mode (context);
|
||||
|
||||
if (pika_paint_options_get_gradient_color (paint_options, image,
|
||||
if (pika_paint_options_are_dynamics_enabled (paint_options) &&
|
||||
pika_paint_options_get_gradient_color (paint_options, image,
|
||||
grad_point,
|
||||
paint_core->pixel_dist,
|
||||
paint_color))
|
||||
@ -252,6 +253,7 @@ _pika_paintbrush_motion (PikaPaintCore *paint_core,
|
||||
coords.x -= off_x;
|
||||
coords.y -= off_y;
|
||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||
paint_core->sym = sym;
|
||||
|
||||
/* Some settings are based on the original stroke. */
|
||||
opacity *= pika_dynamics_get_linear_value (dynamics,
|
||||
@ -313,6 +315,8 @@ _pika_paintbrush_motion (PikaPaintCore *paint_core,
|
||||
&paint_buffer_y,
|
||||
&paint_width,
|
||||
&paint_height);
|
||||
coords = *(pika_symmetry_get_coords (sym, i));
|
||||
|
||||
if (! paint_buffer)
|
||||
continue;
|
||||
|
||||
|
@ -24,10 +24,12 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "paint-types.h"
|
||||
@ -47,6 +49,9 @@
|
||||
#include "core/pikaimage-guides.h"
|
||||
#include "core/pikaimage-symmetry.h"
|
||||
#include "core/pikaimage-undo.h"
|
||||
#include "core/pikaimage-undo-push.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikalayermask.h"
|
||||
#include "core/pikapickable.h"
|
||||
#include "core/pikaprojection.h"
|
||||
#include "core/pikasymmetry.h"
|
||||
@ -158,7 +163,10 @@ static void
|
||||
pika_paint_core_init (PikaPaintCore *core)
|
||||
{
|
||||
core->ID = global_core_ID++;
|
||||
core->undo_buffers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
core->undo_buffers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, g_object_unref);
|
||||
core->original_bounds = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -170,6 +178,7 @@ pika_paint_core_finalize (GObject *object)
|
||||
|
||||
g_clear_pointer (&core->undo_desc, g_free);
|
||||
g_hash_table_unref (core->undo_buffers);
|
||||
g_hash_table_unref (core->original_bounds);
|
||||
if (core->applicators)
|
||||
g_hash_table_unref (core->applicators);
|
||||
|
||||
@ -357,10 +366,11 @@ pika_paint_core_start (PikaPaintCore *core,
|
||||
const PikaCoords *coords,
|
||||
GError **error)
|
||||
{
|
||||
PikaImage *image;
|
||||
PikaChannel *mask;
|
||||
gint max_width = 0;
|
||||
gint max_height = 0;
|
||||
PikaImage *image;
|
||||
PikaChannel *mask;
|
||||
gint max_width = 0;
|
||||
gint max_height = 0;
|
||||
GeglRectangle *rect;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PAINT_CORE (core), FALSE);
|
||||
g_return_val_if_fail (g_list_length (drawables) > 0, FALSE);
|
||||
@ -418,8 +428,16 @@ pika_paint_core_start (PikaPaintCore *core,
|
||||
for (GList *iter = drawables; iter; iter = iter->next)
|
||||
{
|
||||
/* Allocate the undo structures */
|
||||
rect = g_new (GeglRectangle, 1);
|
||||
rect->width = pika_item_get_width (PIKA_ITEM (iter->data));
|
||||
rect->height = pika_item_get_height (PIKA_ITEM (iter->data));
|
||||
pika_item_get_offset (PIKA_ITEM (iter->data), &rect->x, &rect->y);
|
||||
|
||||
g_hash_table_insert (core->original_bounds, iter->data,
|
||||
rect);
|
||||
g_hash_table_insert (core->undo_buffers, iter->data,
|
||||
pika_gegl_buffer_dup (pika_drawable_get_buffer (iter->data)));
|
||||
|
||||
max_width = MAX (max_width, pika_item_get_width (iter->data));
|
||||
max_height = MAX (max_height, pika_item_get_height (iter->data));
|
||||
}
|
||||
@ -484,6 +502,9 @@ pika_paint_core_start (PikaPaintCore *core,
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize the lock_blink_state */
|
||||
core->lock_blink_state = PIKA_PAINT_LOCK_NOT_BLINKED;
|
||||
|
||||
/* Freeze the drawable preview so that it isn't constantly updated. */
|
||||
for (GList *iter = drawables; iter; iter = iter->next)
|
||||
pika_viewable_preview_freeze (PIKA_VIEWABLE (iter->data));
|
||||
@ -532,7 +553,9 @@ pika_paint_core_finish (PikaPaintCore *core,
|
||||
{
|
||||
GeglBuffer *undo_buffer;
|
||||
GeglBuffer *buffer;
|
||||
GeglBuffer *drawable_buffer;
|
||||
GeglRectangle rect;
|
||||
GeglRectangle old_rect;
|
||||
|
||||
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
|
||||
NULL, (gpointer*) &undo_buffer))
|
||||
@ -542,16 +565,6 @@ pika_paint_core_finish (PikaPaintCore *core,
|
||||
continue;
|
||||
}
|
||||
|
||||
pika_rectangle_intersect (core->x1, core->y1,
|
||||
core->x2 - core->x1, core->y2 - core->y1,
|
||||
0, 0,
|
||||
pika_item_get_width (PIKA_ITEM (iter->data)),
|
||||
pika_item_get_height (PIKA_ITEM (iter->data)),
|
||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
|
||||
gegl_rectangle_align_to_buffer (&rect, &rect, undo_buffer,
|
||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||
|
||||
if (! undo_group_started)
|
||||
{
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_PAINT,
|
||||
@ -559,19 +572,115 @@ pika_paint_core_finish (PikaPaintCore *core,
|
||||
undo_group_started = TRUE;
|
||||
}
|
||||
|
||||
PIKA_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
|
||||
/* get new and old bounds of drawable */
|
||||
old_rect = *(GeglRectangle*) g_hash_table_lookup (core->original_bounds, iter->data);
|
||||
|
||||
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
|
||||
pika_drawable_get_format (iter->data));
|
||||
pika_item_get_offset (PIKA_ITEM (iter->data), &rect.x, &rect.y);
|
||||
rect.width = pika_item_get_width (PIKA_ITEM (iter->data));
|
||||
rect.height = pika_item_get_height (PIKA_ITEM (iter->data));
|
||||
|
||||
pika_gegl_buffer_copy (undo_buffer,
|
||||
&rect,
|
||||
GEGL_ABYSS_NONE,
|
||||
buffer,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
/* Making copy of entire buffer consumes more memory, so do that only when buffer has resized */
|
||||
if (rect.x == old_rect.x &&
|
||||
rect.y == old_rect.y &&
|
||||
rect.width == old_rect.width &&
|
||||
rect.height == old_rect.height)
|
||||
{
|
||||
pika_rectangle_intersect (core->x1, core->y1, core->x2 - core->x1,
|
||||
core->y2 - core->y1, 0, 0,
|
||||
pika_item_get_width (PIKA_ITEM (iter->data)),
|
||||
pika_item_get_height (PIKA_ITEM (iter->data)),
|
||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
|
||||
pika_drawable_push_undo (iter->data, NULL,
|
||||
buffer, rect.x, rect.y, rect.width, rect.height);
|
||||
gegl_rectangle_align_to_buffer (&rect, &rect, undo_buffer,
|
||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||
|
||||
PIKA_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
|
||||
|
||||
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
|
||||
pika_drawable_get_format (iter->data));
|
||||
|
||||
pika_gegl_buffer_copy (undo_buffer,
|
||||
&rect,
|
||||
GEGL_ABYSS_NONE,
|
||||
buffer,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
|
||||
pika_drawable_push_undo (iter->data, NULL,
|
||||
buffer, rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drawable is expanded only if drawable is layer or layer mask*/
|
||||
g_return_if_fail (PIKA_IS_LAYER (iter->data) || PIKA_IS_LAYER_MASK (iter->data));
|
||||
|
||||
/* create a copy of original buffer from undo data */
|
||||
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
pika_drawable_get_format (iter->data));
|
||||
|
||||
pika_gegl_buffer_copy (undo_buffer,
|
||||
GEGL_RECTANGLE (old_rect.x - rect.x,
|
||||
old_rect.y - rect.y,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
GEGL_ABYSS_NONE,
|
||||
buffer,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
|
||||
/* make a backup copy of drawable to restore */
|
||||
drawable_buffer = g_object_ref (pika_drawable_get_buffer (PIKA_DRAWABLE (iter->data)));
|
||||
|
||||
if (PIKA_IS_LAYER_MASK (drawables->data) || PIKA_LAYER (drawables->data)->mask)
|
||||
{
|
||||
GeglBuffer *other_new;
|
||||
GeglBuffer *other_old;
|
||||
PikaDrawable *other_drawable;
|
||||
|
||||
if (PIKA_IS_LAYER_MASK (drawables->data))
|
||||
other_drawable = PIKA_DRAWABLE ((PIKA_LAYER_MASK (drawables->data))->layer);
|
||||
else
|
||||
other_drawable = PIKA_DRAWABLE (PIKA_LAYER (drawables->data)->mask);
|
||||
|
||||
/* create a copy of original buffer by taking the required area */
|
||||
other_old = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
pika_drawable_get_format (other_drawable));
|
||||
|
||||
pika_gegl_buffer_copy (pika_drawable_get_buffer (other_drawable),
|
||||
GEGL_RECTANGLE (old_rect.x - rect.x,
|
||||
old_rect.y - rect.y,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
GEGL_ABYSS_NONE,
|
||||
other_old,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
|
||||
/* make a backup copy of drawable to restore */
|
||||
other_new = g_object_ref (pika_drawable_get_buffer (other_drawable));
|
||||
|
||||
pika_drawable_set_buffer_full (other_drawable, FALSE, NULL,
|
||||
other_old, &old_rect,
|
||||
FALSE);
|
||||
pika_drawable_set_buffer_full (other_drawable, TRUE, NULL,
|
||||
other_new, &rect,
|
||||
FALSE);
|
||||
|
||||
g_object_unref (other_new);
|
||||
g_object_unref (other_old);
|
||||
}
|
||||
/* Restore drawable to state before painting started */
|
||||
pika_drawable_set_buffer_full (iter->data, FALSE, NULL,
|
||||
buffer, &old_rect,
|
||||
FALSE);
|
||||
/* Change the drawable again but push undo this time */
|
||||
pika_drawable_set_buffer_full (iter->data, TRUE, NULL,
|
||||
drawable_buffer, &rect,
|
||||
FALSE);
|
||||
|
||||
g_object_unref (drawable_buffer);
|
||||
}
|
||||
|
||||
g_object_unref (buffer);
|
||||
g_object_unref (undo_buffer);
|
||||
@ -614,7 +723,8 @@ pika_paint_core_cancel (PikaPaintCore *core,
|
||||
&x, &y, &width, &height))
|
||||
{
|
||||
GeglBuffer *undo_buffer;
|
||||
GeglRectangle rect;
|
||||
GeglRectangle new_rect;
|
||||
GeglRectangle old_rect;
|
||||
|
||||
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
|
||||
NULL, (gpointer*) &undo_buffer))
|
||||
@ -624,21 +734,108 @@ pika_paint_core_cancel (PikaPaintCore *core,
|
||||
continue;
|
||||
}
|
||||
|
||||
gegl_rectangle_align_to_buffer (&rect,
|
||||
GEGL_RECTANGLE (x, y, width, height),
|
||||
pika_drawable_get_buffer (iter->data),
|
||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||
old_rect = *(GeglRectangle*) g_hash_table_lookup (core->original_bounds, iter->data);
|
||||
|
||||
pika_item_get_offset (PIKA_ITEM (iter->data), &new_rect.x, &new_rect.y);
|
||||
new_rect.width = pika_item_get_width (PIKA_ITEM (iter->data));
|
||||
new_rect.height = pika_item_get_height (PIKA_ITEM (iter->data));
|
||||
|
||||
if (new_rect.x == old_rect.x &&
|
||||
new_rect.y == old_rect.y &&
|
||||
new_rect.width == old_rect.width &&
|
||||
new_rect.height == old_rect.height)
|
||||
{
|
||||
GeglRectangle rect;
|
||||
|
||||
gegl_rectangle_align_to_buffer (&rect,
|
||||
GEGL_RECTANGLE (x, y, width, height),
|
||||
pika_drawable_get_buffer (iter->data),
|
||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||
|
||||
pika_gegl_buffer_copy (undo_buffer,
|
||||
&rect,
|
||||
GEGL_ABYSS_NONE,
|
||||
pika_drawable_get_buffer (iter->data),
|
||||
&rect);
|
||||
|
||||
pika_drawable_update (iter->data, x, y, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
GeglBuffer *buffer;
|
||||
GeglRectangle bbox;
|
||||
|
||||
/* drawable is expanded only if drawable is layer or layer mask,
|
||||
* so drawable cannot be anything else */
|
||||
g_return_if_fail (PIKA_IS_LAYER (iter->data) || PIKA_IS_LAYER_MASK (iter->data));
|
||||
|
||||
/* When canceling painting with drawable expansion, ensure that
|
||||
* the drawable display outside the reverted size is not shown. We
|
||||
* cannot use pika_drawable_update() because it won't work while
|
||||
* painting. Directly emit the "update" signal.
|
||||
* */
|
||||
bbox = pika_drawable_get_bounding_box (iter->data);
|
||||
g_signal_emit_by_name (iter->data, "update", bbox.x, bbox.y, bbox.width, bbox.height);
|
||||
|
||||
/* create a copy of original buffer from undo data */
|
||||
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
pika_drawable_get_format (iter->data));
|
||||
|
||||
pika_gegl_buffer_copy (undo_buffer,
|
||||
GEGL_RECTANGLE (old_rect.x - new_rect.x,
|
||||
old_rect.y - new_rect.y,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
GEGL_ABYSS_NONE,
|
||||
buffer,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
|
||||
if (PIKA_IS_LAYER_MASK (drawables->data) || PIKA_LAYER (drawables->data)->mask)
|
||||
{
|
||||
GeglBuffer *other_old;
|
||||
PikaDrawable *other_drawable;
|
||||
|
||||
if (PIKA_IS_LAYER_MASK (drawables->data))
|
||||
other_drawable = PIKA_DRAWABLE ((PIKA_LAYER_MASK (drawables->data))->layer);
|
||||
else
|
||||
other_drawable = PIKA_DRAWABLE (PIKA_LAYER (drawables->data)->mask);
|
||||
|
||||
/* create a copy of original buffer by taking the required area */
|
||||
other_old = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
pika_drawable_get_format (other_drawable));
|
||||
|
||||
pika_gegl_buffer_copy (pika_drawable_get_buffer (other_drawable),
|
||||
GEGL_RECTANGLE (old_rect.x - new_rect.x,
|
||||
old_rect.y - new_rect.y,
|
||||
old_rect.width,
|
||||
old_rect.height),
|
||||
GEGL_ABYSS_NONE,
|
||||
other_old,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
|
||||
pika_drawable_set_buffer_full (other_drawable, FALSE, NULL,
|
||||
other_old, &old_rect,
|
||||
FALSE);
|
||||
|
||||
g_object_unref (other_old);
|
||||
}
|
||||
/* Restore drawable to state before painting started */
|
||||
pika_drawable_set_buffer_full (iter->data, FALSE, NULL,
|
||||
buffer, &old_rect,
|
||||
FALSE);
|
||||
|
||||
pika_drawable_update (iter->data, 0, 0, -1, -1);
|
||||
|
||||
g_object_unref (buffer);
|
||||
}
|
||||
|
||||
pika_gegl_buffer_copy (undo_buffer,
|
||||
&rect,
|
||||
GEGL_ABYSS_NONE,
|
||||
pika_drawable_get_buffer (iter->data),
|
||||
&rect);
|
||||
g_object_unref (undo_buffer);
|
||||
}
|
||||
|
||||
pika_drawable_update (iter->data, x, y, width, height);
|
||||
|
||||
pika_viewable_preview_thaw (PIKA_VIEWABLE (iter->data));
|
||||
}
|
||||
|
||||
@ -651,6 +848,7 @@ pika_paint_core_cleanup (PikaPaintCore *core)
|
||||
g_return_if_fail (PIKA_IS_PAINT_CORE (core));
|
||||
|
||||
g_hash_table_remove_all (core->undo_buffers);
|
||||
g_hash_table_remove_all (core->original_bounds);
|
||||
|
||||
g_clear_object (&core->saved_proj_buffer);
|
||||
g_clear_object (&core->canvas_buffer);
|
||||
@ -692,6 +890,227 @@ pika_paint_core_get_show_all (PikaPaintCore *core)
|
||||
return core->show_all;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
pika_paint_core_expand_drawable (PikaPaintCore *core,
|
||||
PikaDrawable *drawable,
|
||||
PikaPaintOptions *options,
|
||||
gint x1,
|
||||
gint x2,
|
||||
gint y1,
|
||||
gint y2,
|
||||
gint *new_off_x,
|
||||
gint *new_off_y)
|
||||
{
|
||||
gint drawable_width, drawable_height;
|
||||
gint drawable_offset_x, drawable_offset_y;
|
||||
gint image_width, image_height;
|
||||
gint new_width, new_height;
|
||||
gint expand_amount;
|
||||
gboolean show_all;
|
||||
gboolean outside_image;
|
||||
PikaImage *image = pika_item_get_image (PIKA_ITEM (drawable));
|
||||
PikaLayer *layer;
|
||||
|
||||
drawable_width = pika_item_get_width (PIKA_ITEM (drawable));
|
||||
drawable_height = pika_item_get_height (PIKA_ITEM (drawable));
|
||||
pika_item_get_offset (PIKA_ITEM (drawable), &drawable_offset_x, &drawable_offset_y);
|
||||
|
||||
new_width = drawable_width;
|
||||
new_height = drawable_height;
|
||||
*new_off_x = 0;
|
||||
*new_off_y = 0;
|
||||
|
||||
image_width = pika_image_get_width (image);
|
||||
image_height = pika_image_get_height (image);
|
||||
|
||||
expand_amount = options->expand_amount;
|
||||
show_all = pika_paint_core_get_show_all (core);
|
||||
outside_image = x2 < -drawable_offset_x || x1 > image_width - drawable_offset_x ||
|
||||
y2 < -drawable_offset_y || y1 > image_height - drawable_offset_y;
|
||||
|
||||
/* Don't expand if drawable is anything other
|
||||
* than layer or layer mask */
|
||||
if (PIKA_IS_LAYER_MASK (drawable))
|
||||
layer = (PIKA_LAYER_MASK (drawable))->layer;
|
||||
else if (PIKA_IS_LAYER (drawable))
|
||||
layer = PIKA_LAYER (drawable);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
if (!pika_paint_core_get_show_all (core) && outside_image)
|
||||
return FALSE;
|
||||
|
||||
if (!options->expand_use)
|
||||
return FALSE;
|
||||
|
||||
if (x1 < 0)
|
||||
{
|
||||
if (show_all)
|
||||
{
|
||||
new_width += expand_amount - x1;
|
||||
*new_off_x += expand_amount - x1;
|
||||
}
|
||||
else if (drawable_offset_x > 0)
|
||||
{
|
||||
new_width += expand_amount - x1;
|
||||
*new_off_x += expand_amount - x1;
|
||||
if (*new_off_x > drawable_offset_x)
|
||||
{
|
||||
new_width -= *new_off_x - drawable_offset_x;
|
||||
*new_off_x = drawable_offset_x;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (y1 < 0)
|
||||
{
|
||||
if (show_all)
|
||||
{
|
||||
new_height += expand_amount - y1;
|
||||
*new_off_y += expand_amount - y1;
|
||||
}
|
||||
else if (drawable_offset_y > 0)
|
||||
{
|
||||
new_height += expand_amount - y1;
|
||||
*new_off_y += expand_amount - y1;
|
||||
if (*new_off_y > drawable_offset_y)
|
||||
{
|
||||
new_height -= *new_off_y - drawable_offset_y;
|
||||
*new_off_y = drawable_offset_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x2 > drawable_width)
|
||||
{
|
||||
if (show_all)
|
||||
{
|
||||
new_width += x2 - drawable_width + expand_amount;
|
||||
}
|
||||
else if (drawable_width + drawable_offset_x < image_width)
|
||||
{
|
||||
new_width += x2 - drawable_width + expand_amount;
|
||||
if (new_width + drawable_offset_x - *new_off_x > image_width)
|
||||
new_width = image_width + *new_off_x - drawable_offset_x;
|
||||
}
|
||||
}
|
||||
if (y2 > drawable_height)
|
||||
{
|
||||
if (show_all)
|
||||
{
|
||||
new_height += y2 - drawable_height + expand_amount;
|
||||
}
|
||||
else if (drawable_height + drawable_offset_y < image_height)
|
||||
{
|
||||
new_height += y2 - drawable_height + expand_amount;
|
||||
if (new_height + drawable_offset_y - *new_off_y > image_height)
|
||||
new_height = image_height + *new_off_y - drawable_offset_y;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_width != drawable_width || *new_off_x ||
|
||||
new_height != drawable_height || *new_off_y)
|
||||
{
|
||||
PikaRGB color;
|
||||
PikaPattern *pattern;
|
||||
PikaContext *context = PIKA_CONTEXT (options);
|
||||
PikaFillType fill_type = options->expand_fill_type;
|
||||
gboolean context_has_image;
|
||||
PikaFillType mask_fill_type;
|
||||
GeglBuffer *undo_buffer;
|
||||
GeglBuffer *new_buffer;
|
||||
|
||||
if (pika_item_get_lock_position (PIKA_ITEM (layer)))
|
||||
{
|
||||
if (core->lock_blink_state == PIKA_PAINT_LOCK_NOT_BLINKED)
|
||||
core->lock_blink_state = PIKA_PAINT_LOCK_BLINK_PENDING;
|
||||
|
||||
/* Since we are not expanding, set new offset to zero */
|
||||
*new_off_x = 0;
|
||||
*new_off_y = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mask_fill_type = options->expand_mask_fill_type == PIKA_ADD_MASK_BLACK ?
|
||||
PIKA_FILL_TRANSPARENT :
|
||||
PIKA_FILL_WHITE;
|
||||
|
||||
/* The image field of context is null but
|
||||
* is required for Filling with Middle Gray */
|
||||
context_has_image = context->image != NULL;
|
||||
if (!context_has_image)
|
||||
context->image = image;
|
||||
|
||||
/* ensure that every expansion is pushed to undo stack */
|
||||
if (core->x2 == core->x1)
|
||||
core->x2++;
|
||||
if (core->y2 == core->y1)
|
||||
core->y2++;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (layer));
|
||||
|
||||
pika_drawable_disable_resize_undo (PIKA_DRAWABLE (layer));
|
||||
PIKA_LAYER_GET_CLASS (layer)->resize (layer, context, fill_type,
|
||||
new_width, new_height,
|
||||
*new_off_x, *new_off_y);
|
||||
pika_drawable_enable_resize_undo (PIKA_DRAWABLE (layer));
|
||||
|
||||
if (layer->mask)
|
||||
{
|
||||
g_object_freeze_notify (G_OBJECT (layer->mask));
|
||||
|
||||
pika_drawable_disable_resize_undo (PIKA_DRAWABLE (layer->mask));
|
||||
PIKA_ITEM_GET_CLASS (layer->mask)->resize (PIKA_ITEM (layer->mask), context,
|
||||
mask_fill_type, new_width, new_height,
|
||||
*new_off_x, *new_off_y);
|
||||
pika_drawable_enable_resize_undo (PIKA_DRAWABLE (layer->mask));
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (layer->mask));
|
||||
}
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (layer));
|
||||
|
||||
pika_image_flush (image);
|
||||
|
||||
if (PIKA_IS_LAYER_MASK (drawable))
|
||||
{
|
||||
fill_type = mask_fill_type;
|
||||
}
|
||||
else if (fill_type == PIKA_FILL_TRANSPARENT &&
|
||||
! pika_drawable_has_alpha (drawable))
|
||||
{
|
||||
fill_type = PIKA_FILL_BACKGROUND;
|
||||
}
|
||||
|
||||
new_buffer = pika_gegl_buffer_resize (core->canvas_buffer, new_width, new_height,
|
||||
-(*new_off_x), -(*new_off_y), NULL, NULL, 0, 0);
|
||||
g_object_unref (core->canvas_buffer);
|
||||
core->canvas_buffer = new_buffer;
|
||||
|
||||
pika_get_fill_params (context, fill_type, &color, &pattern, NULL);
|
||||
pika_pickable_srgb_to_image_color (PIKA_PICKABLE (drawable),
|
||||
&color, &color);
|
||||
if (! pika_drawable_has_alpha (drawable))
|
||||
pika_rgb_set_alpha (&color, 1.0);
|
||||
|
||||
undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
|
||||
g_object_ref (undo_buffer);
|
||||
|
||||
new_buffer = pika_gegl_buffer_resize (undo_buffer, new_width, new_height,
|
||||
-(*new_off_x), -(*new_off_y), &color,
|
||||
pattern, 0, 0);
|
||||
g_hash_table_insert (core->undo_buffers, drawable, new_buffer);
|
||||
g_object_unref (undo_buffer);
|
||||
|
||||
/* Restore context to its original state */
|
||||
if (!context_has_image)
|
||||
context->image = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_paint_core_set_current_coords (PikaPaintCore *core,
|
||||
const PikaCoords *coords)
|
||||
|
@ -69,12 +69,17 @@ struct _PikaPaintCore
|
||||
GeglBuffer *paint_buffer; /* the buffer to paint pixels to */
|
||||
gint paint_buffer_x;
|
||||
gint paint_buffer_y;
|
||||
GHashTable *original_bounds; /* the original bounds of drawables */
|
||||
|
||||
GeglBuffer *mask_buffer; /* the target drawable's mask */
|
||||
|
||||
GHashTable *applicators;
|
||||
|
||||
GArray *stroke_buffer;
|
||||
|
||||
PikaSymmetry *sym;
|
||||
PikaPaintLockBlinkState
|
||||
lock_blink_state;
|
||||
};
|
||||
|
||||
struct _PikaPaintCoreClass
|
||||
@ -156,6 +161,16 @@ void pika_paint_core_set_show_all (PikaPaintCore *core,
|
||||
gboolean show_all);
|
||||
gboolean pika_paint_core_get_show_all (PikaPaintCore *core);
|
||||
|
||||
gboolean pika_paint_core_expand_drawable (PikaPaintCore *paint_core,
|
||||
PikaDrawable *drawable,
|
||||
PikaPaintOptions *paint_options,
|
||||
gint x1,
|
||||
gint x2,
|
||||
gint y1,
|
||||
gint y2,
|
||||
gint *x,
|
||||
gint *y);
|
||||
|
||||
void pika_paint_core_set_current_coords (PikaPaintCore *core,
|
||||
const PikaCoords *coords);
|
||||
void pika_paint_core_get_current_coords (PikaPaintCore *core,
|
||||
|
@ -83,6 +83,11 @@
|
||||
#define DEFAULT_SMOOTHING_QUALITY 20
|
||||
#define DEFAULT_SMOOTHING_FACTOR 50
|
||||
|
||||
#define DEFAULT_EXPAND_USE FALSE
|
||||
#define DEFAULT_EXPAND_AMOUNT 100.0
|
||||
#define DEFAULT_EXPAND_FILL_TYPE PIKA_FILL_TRANSPARENT
|
||||
#define DEFAULT_EXPAND_MASK_FILL_TYPE PIKA_ADD_MASK_WHITE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
@ -134,7 +139,12 @@ enum
|
||||
|
||||
PROP_USE_SMOOTHING,
|
||||
PROP_SMOOTHING_QUALITY,
|
||||
PROP_SMOOTHING_FACTOR
|
||||
PROP_SMOOTHING_FACTOR,
|
||||
|
||||
PROP_EXPAND_USE,
|
||||
PROP_EXPAND_AMOUNT,
|
||||
PROP_EXPAND_FILL_TYPE,
|
||||
PROP_EXPAND_MASK_FILL_TYPE
|
||||
};
|
||||
|
||||
|
||||
@ -308,6 +318,36 @@ pika_paint_options_class_init (PikaPaintOptionsClass *klass)
|
||||
DEFAULT_USE_JITTER,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_EXPAND_USE,
|
||||
"expand-use",
|
||||
_("Expand Layers"),
|
||||
_("Expand active layer as you paint"),
|
||||
DEFAULT_EXPAND_USE,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_EXPAND_AMOUNT,
|
||||
"expand-amount",
|
||||
_("Amount"),
|
||||
_("Amount of expansion"),
|
||||
1.0, 1000.0, DEFAULT_EXPAND_AMOUNT,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_EXPAND_FILL_TYPE,
|
||||
"expand-fill-type",
|
||||
_("Fill With"),
|
||||
_("Fill layer with"),
|
||||
PIKA_TYPE_FILL_TYPE,
|
||||
DEFAULT_EXPAND_FILL_TYPE,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_EXPAND_MASK_FILL_TYPE,
|
||||
"expand-mask-fill-type",
|
||||
_("Fill Mask With"),
|
||||
_("Fill layer mask with"),
|
||||
PIKA_TYPE_ADD_MASK_TYPE,
|
||||
DEFAULT_EXPAND_MASK_FILL_TYPE,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_DYNAMICS_ENABLED,
|
||||
"dynamics-enabled",
|
||||
_("Enable dynamics"),
|
||||
@ -642,6 +682,19 @@ pika_paint_options_set_property (GObject *object,
|
||||
smoothing_options->smoothing_factor = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_EXPAND_USE:
|
||||
options->expand_use = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_EXPAND_AMOUNT:
|
||||
options->expand_amount = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_EXPAND_FILL_TYPE:
|
||||
options->expand_fill_type = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_EXPAND_MASK_FILL_TYPE:
|
||||
options->expand_mask_fill_type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@ -788,6 +841,19 @@ pika_paint_options_get_property (GObject *object,
|
||||
g_value_set_double (value, smoothing_options->smoothing_factor);
|
||||
break;
|
||||
|
||||
case PROP_EXPAND_USE:
|
||||
g_value_set_boolean (value, options->expand_use);
|
||||
break;
|
||||
case PROP_EXPAND_AMOUNT:
|
||||
g_value_set_double (value, options->expand_amount);
|
||||
break;
|
||||
case PROP_EXPAND_FILL_TYPE:
|
||||
g_value_set_enum (value, options->expand_fill_type);
|
||||
break;
|
||||
case PROP_EXPAND_MASK_FILL_TYPE:
|
||||
g_value_set_enum (value, options->expand_mask_fill_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@ -1221,9 +1287,18 @@ static const gchar *gradient_props[] =
|
||||
"gradient-repeat"
|
||||
};
|
||||
|
||||
static const gchar *expand_props[] =
|
||||
{
|
||||
"expand-use",
|
||||
"expand-amount",
|
||||
"expand-fill-type",
|
||||
"expand-mask-fill-type",
|
||||
};
|
||||
|
||||
static const gint max_n_props = (G_N_ELEMENTS (brush_props) +
|
||||
G_N_ELEMENTS (dynamics_props) +
|
||||
G_N_ELEMENTS (gradient_props));
|
||||
G_N_ELEMENTS (gradient_props) +
|
||||
G_N_ELEMENTS (expand_props));
|
||||
|
||||
gboolean
|
||||
pika_paint_options_is_prop (const gchar *prop_name,
|
||||
@ -1254,6 +1329,13 @@ pika_paint_options_is_prop (const gchar *prop_name,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (prop_mask & PIKA_CONTEXT_PROP_MASK_EXPAND)
|
||||
{
|
||||
for (i = 0; i < G_N_ELEMENTS (expand_props); i++)
|
||||
if (! strcmp (prop_name, expand_props[i]))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1288,6 +1370,12 @@ pika_paint_options_copy_props (PikaPaintOptions *src,
|
||||
names[n_props++] = gradient_props[i];
|
||||
}
|
||||
|
||||
if (prop_mask & PIKA_CONTEXT_PROP_MASK_EXPAND)
|
||||
{
|
||||
for (i = 0; i < G_N_ELEMENTS (expand_props); i++)
|
||||
names[n_props++] = expand_props[i];
|
||||
}
|
||||
|
||||
if (n_props > 0)
|
||||
{
|
||||
g_object_getv (G_OBJECT (src), n_props, names, values);
|
||||
|
@ -109,6 +109,11 @@ struct _PikaPaintOptions
|
||||
|
||||
gboolean hard;
|
||||
|
||||
gboolean expand_use;
|
||||
gdouble expand_amount;
|
||||
PikaFillType expand_fill_type;
|
||||
PikaAddMaskType expand_mask_fill_type;
|
||||
|
||||
PikaJitterOptions *jitter_options;
|
||||
|
||||
gboolean dynamics_enabled;
|
||||
|
@ -406,6 +406,7 @@ pika_smudge_motion (PikaPaintCore *paint_core,
|
||||
coords.x -= off_x;
|
||||
coords.y -= off_y;
|
||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||
paint_core->sym = sym;
|
||||
|
||||
opacity = pika_dynamics_get_linear_value (dynamics,
|
||||
PIKA_DYNAMICS_OUTPUT_OPACITY,
|
||||
|
@ -347,6 +347,7 @@ pika_source_core_motion (PikaSourceCore *source_core,
|
||||
coords.x -= off_x;
|
||||
coords.y -= off_y;
|
||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||
paint_core->sym = sym;
|
||||
|
||||
/* Some settings are based on the original stroke. */
|
||||
opacity = pika_dynamics_get_linear_value (dynamics,
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "pdb-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikabrush.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikadatafactory.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
|
||||
@ -53,20 +55,24 @@ brushes_popup_invoker (PikaProcedure *procedure,
|
||||
gboolean success = TRUE;
|
||||
const gchar *brush_callback;
|
||||
const gchar *popup_title;
|
||||
const gchar *initial_brush_name;
|
||||
PikaBrush *initial_brush;
|
||||
GBytes *parent_window;
|
||||
|
||||
brush_callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
popup_title = g_value_get_string (pika_value_array_index (args, 1));
|
||||
initial_brush_name = g_value_get_string (pika_value_array_index (args, 2));
|
||||
initial_brush = g_value_get_object (pika_value_array_index (args, 2));
|
||||
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (pika->no_interface ||
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
|
||||
! pika_pdb_dialog_new (pika, context, progress,
|
||||
pika_data_factory_get_container (pika->brush_factory),
|
||||
popup_title, brush_callback, initial_brush_name,
|
||||
NULL))
|
||||
pika_container_get_children_type (container),
|
||||
parent_window, popup_title, brush_callback,
|
||||
PIKA_OBJECT (initial_brush), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
@ -89,9 +95,12 @@ brushes_close_popup_invoker (PikaProcedure *procedure,
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
|
||||
! pika_pdb_dialog_close (pika, pika_data_factory_get_container (pika->brush_factory),
|
||||
! pika_pdb_dialog_close (pika,
|
||||
pika_container_get_children_type (container),
|
||||
brush_callback))
|
||||
success = FALSE;
|
||||
}
|
||||
@ -110,18 +119,20 @@ brushes_set_popup_invoker (PikaProcedure *procedure,
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
const gchar *brush_callback;
|
||||
const gchar *brush_name;
|
||||
PikaBrush *brush;
|
||||
|
||||
brush_callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
brush_name = g_value_get_string (pika_value_array_index (args, 1));
|
||||
brush = g_value_get_object (pika_value_array_index (args, 1));
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
|
||||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->brush_factory),
|
||||
brush_callback, brush_name,
|
||||
NULL))
|
||||
! pika_pdb_dialog_set (pika,
|
||||
pika_container_get_children_type (container),
|
||||
brush_callback, PIKA_OBJECT (brush), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
@ -163,12 +174,17 @@ register_brush_select_procs (PikaPDB *pdb)
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("initial-brush-name",
|
||||
"initial brush name",
|
||||
"The name of the brush to set as the initial choice",
|
||||
FALSE, TRUE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_param_spec_brush ("initial-brush",
|
||||
"initial brush",
|
||||
"The brush to set as the initial choice",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_boxed ("parent-window",
|
||||
"parent window",
|
||||
"An optional parent window handle for the popup to be set transient to",
|
||||
G_TYPE_BYTES,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
@ -218,12 +234,11 @@ register_brush_select_procs (PikaPDB *pdb)
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("brush-name",
|
||||
"brush name",
|
||||
"The name of the brush to set as selected",
|
||||
FALSE, FALSE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_param_spec_brush ("brush",
|
||||
"brush",
|
||||
"The brush to set as selected",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
}
|
||||
|
@ -148,20 +148,20 @@ display_get_window_handle_invoker (PikaProcedure *procedure,
|
||||
gboolean success = TRUE;
|
||||
PikaValueArray *return_vals;
|
||||
PikaDisplay *display;
|
||||
gint window = 0;
|
||||
GBytes *handle = NULL;
|
||||
|
||||
display = g_value_get_object (pika_value_array_index (args, 0));
|
||||
|
||||
if (success)
|
||||
{
|
||||
window = (gint32) pika_get_display_window_id (pika, display);
|
||||
handle = pika_get_display_window_id (pika, display);
|
||||
}
|
||||
|
||||
return_vals = pika_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
|
||||
if (success)
|
||||
g_value_set_int (pika_value_array_index (return_vals, 1), window);
|
||||
g_value_take_boxed (pika_value_array_index (return_vals, 1), handle);
|
||||
|
||||
return return_vals;
|
||||
}
|
||||
@ -330,7 +330,8 @@ register_display_procs (PikaPDB *pdb)
|
||||
"pika-display-get-window-handle");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Get a handle to the native window for an image display.",
|
||||
"This procedure returns a handle to the native window for a given image display. For example in the X backend of GDK, a native window handle is an Xlib XID. A value of 0 is returned for an invalid display or if this function is unimplemented for the windowing system that is being used.",
|
||||
"This procedure returns a handle to the native window for a given image display.\n"
|
||||
"It can be different types of data depending on the platform you are running on. For example in the X backend of GDK, a native window handle is an Xlib XID whereas on Wayland, it is a string handle. A value of NULL is returned for an invalid display or if this function is unimplemented for the windowing system that is being used.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Sven Neumann <sven@gimp.org>",
|
||||
@ -343,11 +344,11 @@ register_display_procs (PikaPDB *pdb)
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_return_value (procedure,
|
||||
g_param_spec_int ("window",
|
||||
"window",
|
||||
"The native window handle or 0",
|
||||
G_MININT32, G_MAXINT32, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
g_param_spec_boxed ("handle",
|
||||
"handle",
|
||||
"The native window handle or NULL",
|
||||
G_TYPE_BYTES,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
|
243
app/pdb/drawable-select-cmds.c
Normal file
243
app/pdb/drawable-select-cmds.c
Normal file
@ -0,0 +1,243 @@
|
||||
/* 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-2003 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/>.
|
||||
*/
|
||||
|
||||
/* NOTE: This file is auto-generated by pdbgen.pl. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "stamp-pdbgen.h"
|
||||
|
||||
#include <gegl.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "pdb-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikadatafactory.h"
|
||||
#include "core/pikadrawable.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
|
||||
#include "pikapdb.h"
|
||||
#include "pikaprocedure.h"
|
||||
#include "internal-procs.h"
|
||||
|
||||
|
||||
static PikaValueArray *
|
||||
drawables_popup_invoker (PikaProcedure *procedure,
|
||||
Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
const PikaValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
const gchar *callback;
|
||||
const gchar *popup_title;
|
||||
const gchar *drawable_type;
|
||||
PikaDrawable *initial_drawable;
|
||||
GBytes *parent_window;
|
||||
|
||||
callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
popup_title = g_value_get_string (pika_value_array_index (args, 1));
|
||||
drawable_type = g_value_get_string (pika_value_array_index (args, 2));
|
||||
initial_drawable = g_value_get_object (pika_value_array_index (args, 3));
|
||||
parent_window = g_value_get_boxed (pika_value_array_index (args, 4));
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
|
||||
! pika_pdb_dialog_new (pika, context, progress,
|
||||
g_type_from_name (drawable_type),
|
||||
parent_window, popup_title, callback,
|
||||
PIKA_OBJECT (initial_drawable),
|
||||
NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
return pika_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
drawables_close_popup_invoker (PikaProcedure *procedure,
|
||||
Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
const PikaValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
const gchar *callback;
|
||||
|
||||
callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
|
||||
! pika_pdb_dialog_close (pika, PIKA_TYPE_DRAWABLE, callback))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
return pika_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
drawables_set_popup_invoker (PikaProcedure *procedure,
|
||||
Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
const PikaValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
const gchar *callback;
|
||||
PikaDrawable *drawable;
|
||||
|
||||
callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
drawable = g_value_get_object (pika_value_array_index (args, 1));
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, callback) ||
|
||||
! pika_pdb_dialog_set (pika, PIKA_TYPE_DRAWABLE, callback, PIKA_OBJECT (drawable), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
return pika_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
}
|
||||
|
||||
void
|
||||
register_drawable_select_procs (PikaPDB *pdb)
|
||||
{
|
||||
PikaProcedure *procedure;
|
||||
|
||||
/*
|
||||
* pika-drawables-popup
|
||||
*/
|
||||
procedure = pika_procedure_new (drawables_popup_invoker);
|
||||
pika_object_set_static_name (PIKA_OBJECT (procedure),
|
||||
"pika-drawables-popup");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Invokes the drawable selection dialog.",
|
||||
"Opens a dialog letting a user choose an drawable.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Jehan",
|
||||
"Jehan",
|
||||
"2023");
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("callback",
|
||||
"callback",
|
||||
"The callback PDB proc to call when user chooses an drawable",
|
||||
FALSE, FALSE, TRUE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("popup-title",
|
||||
"popup title",
|
||||
"Title of the drawable selection dialog",
|
||||
FALSE, FALSE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("drawable-type",
|
||||
"drawable type",
|
||||
"The name of the PIKA_TYPE_DRAWABLE subtype",
|
||||
FALSE, FALSE, TRUE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_drawable ("initial-drawable",
|
||||
"initial drawable",
|
||||
"The drawable to set as the initial choice",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_boxed ("parent-window",
|
||||
"parent window",
|
||||
"An optional parent window handle for the popup to be set transient to",
|
||||
G_TYPE_BYTES,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* pika-drawables-close-popup
|
||||
*/
|
||||
procedure = pika_procedure_new (drawables_close_popup_invoker);
|
||||
pika_object_set_static_name (PIKA_OBJECT (procedure),
|
||||
"pika-drawables-close-popup");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Close the drawable selection dialog.",
|
||||
"Closes an open drawable selection dialog.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Jehan",
|
||||
"Jehan",
|
||||
"2023");
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("callback",
|
||||
"callback",
|
||||
"The name of the callback registered for this pop-up",
|
||||
FALSE, FALSE, TRUE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* pika-drawables-set-popup
|
||||
*/
|
||||
procedure = pika_procedure_new (drawables_set_popup_invoker);
|
||||
pika_object_set_static_name (PIKA_OBJECT (procedure),
|
||||
"pika-drawables-set-popup");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Sets the selected drawable in a drawable selection dialog.",
|
||||
"Sets the selected drawable in a drawable selection dialog.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Jehan",
|
||||
"Jehan",
|
||||
"2023");
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("callback",
|
||||
"callback",
|
||||
"The name of the callback registered for this pop-up",
|
||||
FALSE, FALSE, TRUE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_drawable ("drawable",
|
||||
"drawable",
|
||||
"The drawable to set as selected",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
}
|
@ -75,6 +75,57 @@ font_get_by_name_invoker (PikaProcedure *procedure,
|
||||
return return_vals;
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
fonts_get_by_name_invoker (PikaProcedure *procedure,
|
||||
Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
const PikaValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
PikaValueArray *return_vals;
|
||||
const gchar *name;
|
||||
gint num_fonts = 0;
|
||||
PikaFont **fonts = NULL;
|
||||
|
||||
name = g_value_get_string (pika_value_array_index (args, 0));
|
||||
|
||||
if (success)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
list = pika_pdb_get_resources (pika, PIKA_TYPE_FONT, name, PIKA_PDB_DATA_ACCESS_READ, error);
|
||||
|
||||
if (list == NULL)
|
||||
success = FALSE;
|
||||
|
||||
num_fonts = g_list_length (list);
|
||||
|
||||
if (num_fonts > 0)
|
||||
{
|
||||
gint i = 0;
|
||||
|
||||
fonts = g_new (PikaFont *, num_fonts);
|
||||
|
||||
for (GList *iter = list; i < num_fonts; i++, iter = g_list_next (iter))
|
||||
fonts[i] = g_object_ref (iter->data);
|
||||
}
|
||||
g_list_free (list);
|
||||
}
|
||||
|
||||
return_vals = pika_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
|
||||
if (success)
|
||||
{
|
||||
g_value_set_int (pika_value_array_index (return_vals, 1), num_fonts);
|
||||
pika_value_take_object_array (pika_value_array_index (return_vals, 2), PIKA_TYPE_FONT, (GObject **) fonts, num_fonts);
|
||||
}
|
||||
|
||||
return return_vals;
|
||||
}
|
||||
|
||||
void
|
||||
register_font_procs (PikaPDB *pdb)
|
||||
{
|
||||
@ -87,8 +138,9 @@ register_font_procs (PikaPDB *pdb)
|
||||
pika_object_set_static_name (PIKA_OBJECT (procedure),
|
||||
"pika-font-get-by-name");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Returns the font with the given name.",
|
||||
"Returns the font with the given name.",
|
||||
"Returns a font with the given name.",
|
||||
"If several fonts are named identically, the one which is returned by this function should be considered random. This can be used when you know you won't have multiple fonts of this name or that you don't want to choose (non-interactive scripts, etc.).\n"
|
||||
"If you need more control, you should use 'pika-fonts-get-by-name' instead.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Michael Natterer <mitch@gimp.org>",
|
||||
@ -109,4 +161,40 @@ register_font_procs (PikaPDB *pdb)
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* pika-fonts-get-by-name
|
||||
*/
|
||||
procedure = pika_procedure_new (fonts_get_by_name_invoker);
|
||||
pika_object_set_static_name (PIKA_OBJECT (procedure),
|
||||
"pika-fonts-get-by-name");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Returns the fonts with the given name.",
|
||||
"Returns the fonts with the given name. There may be more than one.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Jehan",
|
||||
"Jehan",
|
||||
"2023");
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("name",
|
||||
"name",
|
||||
"The name of the font",
|
||||
FALSE, FALSE, TRUE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_return_value (procedure,
|
||||
g_param_spec_int ("num-fonts",
|
||||
"num fonts",
|
||||
"The number of fonts with the given name",
|
||||
0, G_MAXINT32, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_return_value (procedure,
|
||||
pika_param_spec_object_array ("fonts",
|
||||
"fonts",
|
||||
"The fonts with the given name",
|
||||
PIKA_TYPE_FONT,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
}
|
||||
|
@ -34,8 +34,10 @@
|
||||
#include "pdb-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikadatafactory.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
#include "text/pikafont.h"
|
||||
|
||||
#include "pikapdb.h"
|
||||
#include "pikaprocedure.h"
|
||||
@ -53,21 +55,25 @@ fonts_popup_invoker (PikaProcedure *procedure,
|
||||
gboolean success = TRUE;
|
||||
const gchar *font_callback;
|
||||
const gchar *popup_title;
|
||||
const gchar *initial_font_name;
|
||||
PikaFont *initial_font;
|
||||
GBytes *parent_window;
|
||||
|
||||
font_callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
popup_title = g_value_get_string (pika_value_array_index (args, 1));
|
||||
initial_font_name = g_value_get_string (pika_value_array_index (args, 2));
|
||||
initial_font = g_value_get_object (pika_value_array_index (args, 2));
|
||||
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
|
||||
! pika_data_factory_data_wait (pika->font_factory) ||
|
||||
! pika_pdb_dialog_new (pika, context, progress,
|
||||
pika_data_factory_get_container (pika->font_factory),
|
||||
popup_title, font_callback, initial_font_name,
|
||||
NULL))
|
||||
pika_container_get_children_type (container),
|
||||
parent_window, popup_title, font_callback,
|
||||
PIKA_OBJECT (initial_font), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
@ -90,10 +96,12 @@ fonts_close_popup_invoker (PikaProcedure *procedure,
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
|
||||
! pika_pdb_dialog_close (pika,
|
||||
pika_data_factory_get_container (pika->font_factory),
|
||||
pika_container_get_children_type (container),
|
||||
font_callback))
|
||||
success = FALSE;
|
||||
}
|
||||
@ -112,20 +120,21 @@ fonts_set_popup_invoker (PikaProcedure *procedure,
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
const gchar *font_callback;
|
||||
const gchar *font_name;
|
||||
PikaFont *font;
|
||||
|
||||
font_callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
font_name = g_value_get_string (pika_value_array_index (args, 1));
|
||||
font = g_value_get_object (pika_value_array_index (args, 1));
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
|
||||
! pika_data_factory_data_wait (pika->font_factory) ||
|
||||
! pika_pdb_dialog_set (pika,
|
||||
pika_data_factory_get_container (pika->font_factory),
|
||||
font_callback, font_name,
|
||||
NULL))
|
||||
pika_container_get_children_type (container),
|
||||
font_callback, PIKA_OBJECT (font), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
@ -167,12 +176,17 @@ register_font_select_procs (PikaPDB *pdb)
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("initial-font-name",
|
||||
"initial font name",
|
||||
"The name of the initial font choice.",
|
||||
FALSE, TRUE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_param_spec_font ("initial-font",
|
||||
"initial font",
|
||||
"The name of the initial font choice.",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_boxed ("parent-window",
|
||||
"parent window",
|
||||
"An optional parent window handle for the popup to be set transient to",
|
||||
G_TYPE_BYTES,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
@ -222,12 +236,11 @@ register_font_select_procs (PikaPDB *pdb)
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("font-name",
|
||||
"font name",
|
||||
"The name of the font to set as selected",
|
||||
FALSE, FALSE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_param_spec_font ("font",
|
||||
"font",
|
||||
"The font to set as selected",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "pdb-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikadatafactory.h"
|
||||
#include "core/pikagradient.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
@ -54,14 +55,18 @@ gradients_popup_invoker (PikaProcedure *procedure,
|
||||
gboolean success = TRUE;
|
||||
const gchar *gradient_callback;
|
||||
const gchar *popup_title;
|
||||
const gchar *initial_gradient_name;
|
||||
PikaGradient *initial_gradient;
|
||||
GBytes *parent_window;
|
||||
|
||||
gradient_callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
popup_title = g_value_get_string (pika_value_array_index (args, 1));
|
||||
initial_gradient_name = g_value_get_string (pika_value_array_index (args, 2));
|
||||
initial_gradient = g_value_get_object (pika_value_array_index (args, 2));
|
||||
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
|
||||
|
||||
/* Formerly, this procedure had another parameter:
|
||||
* the sample size of the gradient's data passed in the changed callback.
|
||||
* Now the sample size is determined by core, and in the future,
|
||||
@ -71,9 +76,9 @@ gradients_popup_invoker (PikaProcedure *procedure,
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
|
||||
! pika_pdb_dialog_new (pika, context, progress,
|
||||
pika_data_factory_get_container (pika->gradient_factory),
|
||||
popup_title, gradient_callback, initial_gradient_name,
|
||||
NULL))
|
||||
pika_container_get_children_type (container),
|
||||
parent_window, popup_title, gradient_callback,
|
||||
PIKA_OBJECT (initial_gradient), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
@ -96,9 +101,12 @@ gradients_close_popup_invoker (PikaProcedure *procedure,
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
|
||||
! pika_pdb_dialog_close (pika, pika_data_factory_get_container (pika->gradient_factory),
|
||||
! pika_pdb_dialog_close (pika,
|
||||
pika_container_get_children_type (container),
|
||||
gradient_callback))
|
||||
success = FALSE;
|
||||
}
|
||||
@ -117,18 +125,20 @@ gradients_set_popup_invoker (PikaProcedure *procedure,
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
const gchar *gradient_callback;
|
||||
const gchar *gradient_name;
|
||||
PikaGradient *gradient;
|
||||
|
||||
gradient_callback = g_value_get_string (pika_value_array_index (args, 0));
|
||||
gradient_name = g_value_get_string (pika_value_array_index (args, 1));
|
||||
gradient = g_value_get_object (pika_value_array_index (args, 1));
|
||||
|
||||
if (success)
|
||||
{
|
||||
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
|
||||
|
||||
if (pika->no_interface ||
|
||||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
|
||||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->gradient_factory),
|
||||
gradient_callback, gradient_name,
|
||||
NULL))
|
||||
! pika_pdb_dialog_set (pika,
|
||||
pika_container_get_children_type (container),
|
||||
gradient_callback, PIKA_OBJECT (gradient), NULL))
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
@ -170,12 +180,17 @@ register_gradient_select_procs (PikaPDB *pdb)
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("initial-gradient-name",
|
||||
"initial gradient name",
|
||||
"The name of the initial gradient choice",
|
||||
FALSE, TRUE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_param_spec_gradient ("initial-gradient",
|
||||
"initial gradient",
|
||||
"The initial gradient choice",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_boxed ("parent-window",
|
||||
"parent window",
|
||||
"An optional parent window handle for the popup to be set transient to",
|
||||
G_TYPE_BYTES,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
@ -225,12 +240,11 @@ register_gradient_select_procs (PikaPDB *pdb)
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_string ("gradient-name",
|
||||
"gradient name",
|
||||
"The name of the gradient to set as selected",
|
||||
FALSE, FALSE, FALSE,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_param_spec_gradient ("gradient",
|
||||
"gradient",
|
||||
"The gradient to set as selected",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaitem.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikapalette.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
#include "core/pikapickable.h"
|
||||
#include "core/pikaprogress.h"
|
||||
@ -1575,6 +1576,35 @@ image_set_colormap_invoker (PikaProcedure *procedure,
|
||||
error ? *error : NULL);
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
image_get_palette_invoker (PikaProcedure *procedure,
|
||||
Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
const PikaValueArray *args,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
PikaValueArray *return_vals;
|
||||
PikaImage *image;
|
||||
PikaPalette *colormap = NULL;
|
||||
|
||||
image = g_value_get_object (pika_value_array_index (args, 0));
|
||||
|
||||
if (success)
|
||||
{
|
||||
colormap = pika_image_get_colormap_palette (image);
|
||||
}
|
||||
|
||||
return_vals = pika_procedure_get_return_values (procedure, success,
|
||||
error ? *error : NULL);
|
||||
|
||||
if (success)
|
||||
g_value_set_object (pika_value_array_index (return_vals, 1), colormap);
|
||||
|
||||
return return_vals;
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
image_get_metadata_invoker (PikaProcedure *procedure,
|
||||
Pika *pika,
|
||||
@ -4356,6 +4386,35 @@ register_image_procs (PikaPDB *pdb)
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* pika-image-get-palette
|
||||
*/
|
||||
procedure = pika_procedure_new (image_get_palette_invoker);
|
||||
pika_object_set_static_name (PIKA_OBJECT (procedure),
|
||||
"pika-image-get-palette");
|
||||
pika_procedure_set_static_help (procedure,
|
||||
"Returns the image's colormap",
|
||||
"This procedure returns the image's colormap as a PikaPalette. If the image is not in Indexed color mode, %NULL is returned.",
|
||||
NULL);
|
||||
pika_procedure_set_static_attribution (procedure,
|
||||
"Jehan",
|
||||
"Jehan",
|
||||
"2023");
|
||||
pika_procedure_add_argument (procedure,
|
||||
pika_param_spec_image ("image",
|
||||
"image",
|
||||
"The image",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_return_value (procedure,
|
||||
pika_param_spec_palette ("colormap",
|
||||
"colormap",
|
||||
"The image's colormap.",
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_pdb_register_procedure (pdb, procedure);
|
||||
g_object_unref (procedure);
|
||||
|
||||
/*
|
||||
* pika-image-get-metadata
|
||||
*/
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "internal-procs.h"
|
||||
|
||||
|
||||
/* 775 procedures registered total */
|
||||
/* 779 procedures registered total */
|
||||
|
||||
void
|
||||
internal_procs_init (PikaPDB *pdb)
|
||||
@ -52,6 +52,7 @@ internal_procs_init (PikaPDB *pdb)
|
||||
register_drawable_procs (pdb);
|
||||
register_drawable_color_procs (pdb);
|
||||
register_drawable_edit_procs (pdb);
|
||||
register_drawable_select_procs (pdb);
|
||||
register_dynamics_procs (pdb);
|
||||
register_edit_procs (pdb);
|
||||
register_file_procs (pdb);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user