Compare commits
10 Commits
ebd17a1e10
...
0.0.0+GnuI
Author | SHA1 | Date | |
---|---|---|---|
4b829a4b3c | |||
af7dc8395d | |||
8ac3f8a548 | |||
63b2780499 | |||
d472f6348d | |||
84ea557696 | |||
852cbfc1fb | |||
3bbdd873ef | |||
098531073c | |||
a8611b8b16 |
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
AUTHORS
8
AUTHORS
@ -1,6 +1,6 @@
|
||||
-- This file is generated from authors.xml, do not edit it directly. --
|
||||
|
||||
PIKA was originally written by:
|
||||
GIMP was originally written by:
|
||||
|
||||
Spencer Kimball
|
||||
Peter Mattis
|
||||
@ -12,7 +12,7 @@ The current maintainers are:
|
||||
Jehan
|
||||
|
||||
|
||||
The following people have contributed code to PIKA:
|
||||
The following people have contributed code to GIMP:
|
||||
|
||||
Lauri Alanko
|
||||
Fredrik Alströmer
|
||||
@ -339,7 +339,7 @@ The following people have contributed code to PIKA:
|
||||
Robert Ögren
|
||||
|
||||
|
||||
The following people have contributed art to PIKA:
|
||||
The following people have contributed art to GIMP:
|
||||
|
||||
Lapo Calamandrei
|
||||
Paul Davey
|
||||
@ -359,7 +359,7 @@ The following people have contributed art to PIKA:
|
||||
William Szilveszter
|
||||
|
||||
|
||||
The following people have helped to document PIKA:
|
||||
The following people have helped to document GIMP:
|
||||
|
||||
Ignacio AntI
|
||||
Žygimantas Beručka
|
||||
|
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,
|
||||
|
@ -371,66 +371,86 @@ static const PikaEnumActionEntry view_zoom_actions[] =
|
||||
PIKA_HELP_VIEW_ZOOM_IN }
|
||||
};
|
||||
|
||||
static const PikaRadioActionEntry view_zoom_explicit_actions[] =
|
||||
static const PikaEnumActionEntry view_zoom_explicit_actions[] =
|
||||
{
|
||||
{ "view-zoom-16-1", NULL,
|
||||
NC_("view-zoom-action", "1_6:1 (1600%)"), NULL, { "5", "KP_5", NULL },
|
||||
NC_("view-zoom-action", "Zoom 16:1 (1600%)"),
|
||||
NC_("view-zoom-action", "1_6:1 (1600%)"),
|
||||
{ "5", "KP_5", NULL },
|
||||
NC_("view-zoom-action", "Zoom 16:1"),
|
||||
160000,
|
||||
160000, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_IN },
|
||||
|
||||
{ "view-zoom-8-1", NULL,
|
||||
NC_("view-zoom-action", "_8:1 (800%)"), NULL, { "4", "KP_4", NULL },
|
||||
NC_("view-zoom-action", "Zoom 8:1 (800%)"),
|
||||
NC_("view-zoom-action", "_8:1 (800%)"),
|
||||
{ "4", "KP_4", NULL },
|
||||
NC_("view-zoom-action", "Zoom 8:1"),
|
||||
80000,
|
||||
80000, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_IN },
|
||||
|
||||
{ "view-zoom-4-1", NULL,
|
||||
NC_("view-zoom-action", "_4:1 (400%)"), NULL, { "3", "KP_3", NULL },
|
||||
NC_("view-zoom-action", "Zoom 4:1 (400%)"),
|
||||
NC_("view-zoom-action", "_4:1 (400%)"),
|
||||
{ "3", "KP_3", NULL },
|
||||
NC_("view-zoom-action", "Zoom 4:1"),
|
||||
40000,
|
||||
40000, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_IN },
|
||||
|
||||
{ "view-zoom-2-1", NULL,
|
||||
NC_("view-zoom-action", "_2:1 (200%)"), NULL, { "2", "KP_2", NULL },
|
||||
NC_("view-zoom-action", "Zoom 2:1 (200%)"),
|
||||
NC_("view-zoom-action", "_2:1 (200%)"),
|
||||
{ "2", "KP_2", NULL },
|
||||
NC_("view-zoom-action", "Zoom 2:1"),
|
||||
20000,
|
||||
20000, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_IN },
|
||||
|
||||
{ "view-zoom-1-1", PIKA_ICON_ZOOM_ORIGINAL,
|
||||
NC_("view-zoom-action", "_1:1 (100%)"), NULL, { "1", "KP_1", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:1 (100%)"),
|
||||
NC_("view-zoom-action", "_1:1 (100%)"),
|
||||
{ "1", "KP_1", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:1"),
|
||||
10000,
|
||||
10000, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_100 },
|
||||
|
||||
{ "view-zoom-1-2", NULL,
|
||||
NC_("view-zoom-action", "1:_2 (50%)"), NULL, { "<shift>2", "<shift>KP_2", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:2 (50%)"),
|
||||
NC_("view-zoom-action", "1:_2 (50%)"),
|
||||
{ "<shift>2", "<shift>KP_2", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:2"),
|
||||
5000,
|
||||
5000, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_OUT },
|
||||
|
||||
{ "view-zoom-1-4", NULL,
|
||||
NC_("view-zoom-action", "1:_4 (25%)"), NULL, { "<shift>3", "<shift>KP_3", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:4 (25%)"),
|
||||
NC_("view-zoom-action", "1:_4 (25%)"),
|
||||
{ "<shift>3", "<shift>KP_3", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:4"),
|
||||
2500,
|
||||
2500, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_OUT },
|
||||
|
||||
{ "view-zoom-1-8", NULL,
|
||||
NC_("view-zoom-action", "1:_8 (12.5%)"), NULL, { "<shift>4", "<shift>KP_4", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:8 (12.5%)"),
|
||||
NC_("view-zoom-action", "1:_8 (12.5%)"),
|
||||
{ "<shift>4", "<shift>KP_4", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:8"),
|
||||
1250,
|
||||
1250, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_OUT },
|
||||
|
||||
{ "view-zoom-1-16", NULL,
|
||||
NC_("view-zoom-action", "1:1_6 (6.25%)"), NULL, { "<shift>5", "<shift>KP_5", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:16 (6.25%)"),
|
||||
NC_("view-zoom-action", "1:1_6 (6.25%)"),
|
||||
{ "<shift>5", "<shift>KP_5", NULL },
|
||||
NC_("view-zoom-action", "Zoom 1:16"),
|
||||
625,
|
||||
625, FALSE,
|
||||
PIKA_HELP_VIEW_ZOOM_OUT },
|
||||
|
||||
{ "view-zoom-other", NULL,
|
||||
NC_("view-zoom-action", "Othe_r zoom factor..."), NULL, { NULL },
|
||||
NC_("view-zoom-action", "Set a custom zoom factor"),
|
||||
0,
|
||||
NC_("view-zoom-action", "Othe_r zoom factor..."),
|
||||
{ NULL },
|
||||
NC_("view-zoom-action", "Set a custom zoom factor"),
|
||||
0, TRUE,
|
||||
PIKA_HELP_VIEW_ZOOM_OTHER }
|
||||
};
|
||||
|
||||
@ -652,8 +672,6 @@ static const PikaEnumActionEntry view_scroll_vertical_actions[] =
|
||||
void
|
||||
view_actions_setup (PikaActionGroup *group)
|
||||
{
|
||||
PikaAction *action;
|
||||
|
||||
pika_action_group_add_actions (group, "view-action",
|
||||
view_actions,
|
||||
G_N_ELEMENTS (view_actions));
|
||||
@ -667,12 +685,10 @@ view_actions_setup (PikaActionGroup *group)
|
||||
G_N_ELEMENTS (view_zoom_actions),
|
||||
view_zoom_cmd_callback);
|
||||
|
||||
pika_action_group_add_radio_actions (group, "view-zoom-action",
|
||||
view_zoom_explicit_actions,
|
||||
G_N_ELEMENTS (view_zoom_explicit_actions),
|
||||
NULL,
|
||||
10000,
|
||||
view_zoom_explicit_cmd_callback);
|
||||
pika_action_group_add_enum_actions (group, "view-zoom-action",
|
||||
view_zoom_explicit_actions,
|
||||
G_N_ELEMENTS (view_zoom_explicit_actions),
|
||||
view_zoom_explicit_cmd_callback);
|
||||
|
||||
pika_action_group_add_toggle_actions (group, "view-action",
|
||||
view_flip_actions,
|
||||
@ -714,15 +730,6 @@ view_actions_setup (PikaActionGroup *group)
|
||||
G_N_ELEMENTS (view_scroll_vertical_actions),
|
||||
view_scroll_vertical_cmd_callback);
|
||||
|
||||
/* connect "activate" of view-zoom-other manually so it can be
|
||||
* selected even if it's the active item of the radio group
|
||||
*/
|
||||
action = pika_action_group_get_action (group, "view-zoom-other");
|
||||
|
||||
g_signal_connect (action, "activate",
|
||||
G_CALLBACK (view_zoom_other_cmd_callback),
|
||||
group->user_data);
|
||||
|
||||
g_signal_connect_object (group->pika->config, "notify::check-type",
|
||||
G_CALLBACK (view_actions_check_type_notify),
|
||||
group, 0);
|
||||
@ -987,55 +994,20 @@ static void
|
||||
view_actions_set_zoom (PikaActionGroup *group,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
const gchar *action = NULL;
|
||||
PikaImageWindow *window;
|
||||
PikaMenuModel *model;
|
||||
gchar *str;
|
||||
gchar *label;
|
||||
guint scale;
|
||||
|
||||
g_object_get (shell->zoom,
|
||||
"percentage", &str,
|
||||
NULL);
|
||||
|
||||
scale = ROUND (pika_zoom_model_get_factor (shell->zoom) * 1000);
|
||||
|
||||
switch (scale)
|
||||
{
|
||||
case 16000: action = "view-zoom-16-1"; break;
|
||||
case 8000: action = "view-zoom-8-1"; break;
|
||||
case 4000: action = "view-zoom-4-1"; break;
|
||||
case 2000: action = "view-zoom-2-1"; break;
|
||||
case 1000: action = "view-zoom-1-1"; break;
|
||||
case 500: action = "view-zoom-1-2"; break;
|
||||
case 250: action = "view-zoom-1-4"; break;
|
||||
case 125: action = "view-zoom-1-8"; break;
|
||||
case 63:
|
||||
case 62: action = "view-zoom-1-16"; break;
|
||||
}
|
||||
|
||||
if (! action)
|
||||
{
|
||||
action = "view-zoom-other";
|
||||
|
||||
label = g_strdup_printf (_("Othe_r (%s)..."), str);
|
||||
pika_action_group_set_action_label (group, action, label);
|
||||
g_free (label);
|
||||
|
||||
shell->other_scale = pika_zoom_model_get_factor (shell->zoom);
|
||||
}
|
||||
|
||||
pika_action_group_set_action_active (group, action, TRUE);
|
||||
|
||||
window = pika_display_shell_get_window (shell);
|
||||
model = pika_image_window_get_menubar_model (window);
|
||||
label = g_strdup_printf (_("_Zoom (%s)"), str);
|
||||
pika_menu_model_set_title (model, "/View/Zoom", label);
|
||||
g_free (label);
|
||||
|
||||
/* flag as dirty */
|
||||
shell->other_scale = - fabs (shell->other_scale);
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
|
@ -288,22 +288,7 @@ view_zoom_explicit_cmd_callback (PikaAction *action,
|
||||
(gdouble) factor / 10000,
|
||||
PIKA_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS);
|
||||
}
|
||||
}
|
||||
|
||||
/* not a PikaActionCallback */
|
||||
void
|
||||
view_zoom_other_cmd_callback (PikaAction *action,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
return_if_no_shell (shell, data);
|
||||
|
||||
/* check if we are activated by the user or from
|
||||
* view_actions_set_zoom(), also this is really a GtkToggleAction
|
||||
* NOT a PikaToggleAction
|
||||
*/
|
||||
if (pika_toggle_action_get_active (PIKA_TOGGLE_ACTION (action)) &&
|
||||
shell->other_scale != pika_zoom_model_get_factor (shell->zoom))
|
||||
else
|
||||
{
|
||||
pika_display_shell_scale_dialog (shell);
|
||||
}
|
||||
|
@ -53,10 +53,6 @@ void view_zoom_explicit_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
|
||||
/* not a PikaActionCallback */
|
||||
void view_zoom_other_cmd_callback (PikaAction *action,
|
||||
gpointer data);
|
||||
|
||||
void view_show_all_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
|
@ -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
|
||||
@ -80,6 +80,7 @@ enum
|
||||
PROP_ICON_THEME_PATH,
|
||||
PROP_ICON_THEME,
|
||||
PROP_PREFER_SYMBOLIC_ICONS,
|
||||
PROP_FONT_RELATIVE_SIZE,
|
||||
PROP_USE_HELP,
|
||||
PROP_SHOW_HELP_BUTTON,
|
||||
PROP_HELP_LOCALES,
|
||||
@ -362,6 +363,13 @@ pika_gui_config_class_init (PikaGuiConfigClass *klass)
|
||||
TRUE,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_FONT_RELATIVE_SIZE,
|
||||
"font-relative-size",
|
||||
"Tweak font-size from the theme",
|
||||
FONT_SIZE_BLURB,
|
||||
0.5, 2.0, 1.0,
|
||||
PIKA_PARAM_STATIC_STRINGS);
|
||||
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_HELP,
|
||||
"use-help",
|
||||
"Use help",
|
||||
@ -699,6 +707,9 @@ pika_gui_config_set_property (GObject *object,
|
||||
case PROP_PREFER_SYMBOLIC_ICONS:
|
||||
gui_config->prefer_symbolic_icons = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_FONT_RELATIVE_SIZE:
|
||||
gui_config->font_relative_size = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_USE_HELP:
|
||||
gui_config->use_help = g_value_get_boolean (value);
|
||||
break;
|
||||
@ -876,6 +887,9 @@ pika_gui_config_get_property (GObject *object,
|
||||
case PROP_PREFER_SYMBOLIC_ICONS:
|
||||
g_value_set_boolean (value, gui_config->prefer_symbolic_icons);
|
||||
break;
|
||||
case PROP_FONT_RELATIVE_SIZE:
|
||||
g_value_set_double (value, gui_config->font_relative_size);
|
||||
break;
|
||||
case PROP_USE_HELP:
|
||||
g_value_set_boolean (value, gui_config->use_help);
|
||||
break;
|
||||
|
@ -72,6 +72,7 @@ struct _PikaGuiConfig
|
||||
gchar *icon_theme_path;
|
||||
gchar *icon_theme;
|
||||
gboolean prefer_symbolic_icons;
|
||||
gdouble font_relative_size;
|
||||
gboolean override_icon_size;
|
||||
PikaIconSize custom_icon_size;
|
||||
gboolean use_help;
|
||||
|
@ -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."
|
||||
|
||||
@ -561,6 +564,9 @@ _("When enabled, symbolic icons will be preferred if available.")
|
||||
#define ICON_THEME_PATH_BLURB \
|
||||
"Sets the icon theme search path."
|
||||
|
||||
#define FONT_SIZE_BLURB \
|
||||
_("Tweak font size of the graphical interface.")
|
||||
|
||||
#define IMAGE_CONVERT_PROFILE_INTENT_BLURB \
|
||||
_("Sets the default rendering intent for the 'Convert to Color Profile' dialog.")
|
||||
|
||||
|
@ -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);
|
||||
|
@ -734,7 +734,7 @@ pika_file_is_executable (GFile *file)
|
||||
|
||||
if (info)
|
||||
{
|
||||
GFileType file_type = g_file_info_get_file_type (info);
|
||||
GFileType file_type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
|
||||
const gchar *filename = g_file_info_get_name (info);
|
||||
|
||||
if (file_type == G_FILE_TYPE_REGULAR &&
|
||||
|
@ -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))
|
||||
|
@ -386,13 +386,13 @@ pika_data_loader_factory_load_directory (PikaDataFactory *factory,
|
||||
GFileType file_type;
|
||||
GFile *child;
|
||||
|
||||
if (g_file_info_get_is_hidden (info))
|
||||
if (g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN))
|
||||
{
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
file_type = g_file_info_get_file_type (info);
|
||||
file_type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
|
||||
child = g_file_enumerator_get_child (enumerator, info);
|
||||
|
||||
if (file_type == G_FILE_TYPE_DIRECTORY)
|
||||
|
@ -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);
|
||||
|
@ -1022,7 +1022,7 @@ pika_extension_manager_search_directory (PikaExtensionManager *manager,
|
||||
{
|
||||
GFile *subdir;
|
||||
|
||||
if (g_file_info_get_is_hidden (info))
|
||||
if (g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN))
|
||||
{
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
|
@ -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"
|
||||
@ -456,7 +457,7 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, NULL);
|
||||
|
||||
regular = (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR);
|
||||
regular = (g_file_info_get_attribute_uint32 (file_info, G_FILE_ATTRIBUTE_STANDARD_TYPE) == G_FILE_TYPE_REGULAR);
|
||||
readable = g_file_info_get_attribute_boolean (file_info,
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
|
||||
|
||||
@ -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)
|
||||
@ -719,7 +738,7 @@ pika_imagefile_icon_callback (GObject *source_object,
|
||||
|
||||
if (file_info)
|
||||
{
|
||||
private->icon = g_object_ref (g_file_info_get_icon (file_info));
|
||||
private->icon = g_object_ref (G_ICON (g_file_info_get_attribute_object (file_info, G_FILE_ATTRIBUTE_STANDARD_ICON)));
|
||||
g_object_unref (file_info);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
@ -1736,7 +1750,7 @@ pika_palette_load_detect_format (GFile *file,
|
||||
|
||||
if (info)
|
||||
{
|
||||
goffset size = g_file_info_get_size (info);
|
||||
goffset size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
|
||||
|
||||
if (size == 768)
|
||||
format = PIKA_PALETTE_FILE_FORMAT_ACT;
|
||||
|
@ -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
|
||||
|
@ -2,7 +2,7 @@
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -34,43 +34,36 @@
|
||||
|
||||
#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"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/* The first authors are the creators and maintainers, don't shuffle
|
||||
* them
|
||||
*/
|
||||
#define START_INDEX (G_N_ELEMENTS (creators) - 1 /*NULL*/ + \
|
||||
G_N_ELEMENTS (maintainers) - 1 /*NULL*/)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *dialog;
|
||||
|
||||
Pika *pika;
|
||||
|
||||
GtkWidget *update_frame;
|
||||
PikaCoreConfig *config;
|
||||
|
||||
GtkWidget *anim_area;
|
||||
PangoLayout *layout;
|
||||
GtkWidget *anim_area;
|
||||
PangoLayout *layout;
|
||||
|
||||
gint n_authors;
|
||||
gint shuffle[G_N_ELEMENTS (authors) - 1]; /* NULL terminated */
|
||||
guint timer;
|
||||
|
||||
guint timer;
|
||||
|
||||
gint index;
|
||||
gint animstep;
|
||||
gint state;
|
||||
gboolean visible;
|
||||
gint index;
|
||||
gint animstep;
|
||||
gint state;
|
||||
gboolean visible;
|
||||
} PikaAboutDialog;
|
||||
|
||||
|
||||
@ -103,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;
|
||||
|
||||
@ -116,7 +110,7 @@ about_dialog_create (PikaCoreConfig *config)
|
||||
gchar *copyright;
|
||||
gchar *version;
|
||||
|
||||
dialog.n_authors = G_N_ELEMENTS (authors) - 1;
|
||||
dialog.pika = pika;
|
||||
dialog.config = config;
|
||||
|
||||
pixbuf = about_dialog_load_logo ();
|
||||
@ -145,12 +139,6 @@ about_dialog_create (PikaCoreConfig *config)
|
||||
"logo", pixbuf,
|
||||
"website", "https://heckin.technology/AlderconeStudio/PIKApp/",
|
||||
"website-label", _("Visit the PIKA website"),
|
||||
"authors", authors,
|
||||
"artists", artists,
|
||||
"documenters", documenters,
|
||||
/* Translators: insert your names here,
|
||||
separated by newline */
|
||||
"translator-credits", _("translator-credits"),
|
||||
NULL);
|
||||
|
||||
if (pixbuf)
|
||||
@ -210,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
|
||||
@ -278,229 +270,11 @@ static void
|
||||
about_dialog_add_update (PikaAboutDialog *dialog,
|
||||
PikaCoreConfig *config)
|
||||
{
|
||||
GtkWidget *container;
|
||||
GList *children;
|
||||
GtkWidget *vbox;
|
||||
|
||||
GtkWidget *frame;
|
||||
GtkWidget *box;
|
||||
GtkWidget *box2;
|
||||
GtkWidget *label;
|
||||
GtkWidget *button;
|
||||
GtkWidget *button_image;
|
||||
GtkWidget *button_label;
|
||||
GDateTime *datetime;
|
||||
gchar *date;
|
||||
gchar *text;
|
||||
|
||||
if (dialog->update_frame)
|
||||
{
|
||||
gtk_widget_destroy (dialog->update_frame);
|
||||
dialog->update_frame = NULL;
|
||||
}
|
||||
|
||||
/* Get the dialog vbox. */
|
||||
container = gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog));
|
||||
children = gtk_container_get_children (GTK_CONTAINER (container));
|
||||
g_return_if_fail (GTK_IS_BOX (children->data));
|
||||
vbox = children->data;
|
||||
g_list_free (children);
|
||||
|
||||
/* The update frame. */
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 2);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (frame), box);
|
||||
|
||||
/* Button in the frame. */
|
||||
button = gtk_button_new ();
|
||||
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
|
||||
gtk_widget_show (button);
|
||||
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (button), box2);
|
||||
gtk_widget_show (box2);
|
||||
|
||||
button_image = gtk_image_new_from_icon_name (NULL, GTK_ICON_SIZE_DIALOG);
|
||||
gtk_box_pack_start (GTK_BOX (box2), button_image, FALSE, FALSE, 0);
|
||||
gtk_widget_show (button_image);
|
||||
|
||||
button_label = gtk_label_new (NULL);
|
||||
gtk_box_pack_start (GTK_BOX (box2), button_label, FALSE, FALSE, 0);
|
||||
gtk_container_child_set (GTK_CONTAINER (box2), button_label, "expand", TRUE, NULL);
|
||||
gtk_widget_show (button_label);
|
||||
|
||||
if (config->last_known_release != NULL)
|
||||
{
|
||||
/* There is a newer version. */
|
||||
const gchar *download_url = NULL;
|
||||
gchar *comment = NULL;
|
||||
|
||||
/* We want the frame to stand out. */
|
||||
label = gtk_label_new (NULL);
|
||||
text = g_strdup_printf ("<tt><b><big>%s</big></b></tt>",
|
||||
_("Update available!"));
|
||||
gtk_label_set_markup (GTK_LABEL (label), text);
|
||||
g_free (text);
|
||||
gtk_widget_show (label);
|
||||
gtk_frame_set_label_widget (GTK_FRAME (frame), label);
|
||||
gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
|
||||
gtk_box_reorder_child (GTK_BOX (vbox), frame, 3);
|
||||
|
||||
/* Button is an update link. */
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (button_image),
|
||||
"software-update-available",
|
||||
GTK_ICON_SIZE_DIALOG);
|
||||
#ifdef PIKA_UNSTABLE
|
||||
download_url = "https://heckin.technology/AlderconeStudio/PIKApp/downloads/devel/";
|
||||
#else
|
||||
download_url = "https://heckin.technology/AlderconeStudio/PIKApp/downloads/";
|
||||
#endif
|
||||
g_signal_connect (button, "clicked",
|
||||
(GCallback) about_dialog_download_clicked,
|
||||
(gpointer) download_url);
|
||||
|
||||
/* The preferred localized date representation without the time. */
|
||||
datetime = g_date_time_new_from_unix_local (config->last_release_timestamp);
|
||||
date = g_date_time_format (datetime, "%x");
|
||||
g_date_time_unref (datetime);
|
||||
|
||||
if (config->last_revision > 0)
|
||||
{
|
||||
/* This is actually a new revision of current version. */
|
||||
text = g_strdup_printf (_("Download PIKA %s revision %d (released on %s)\n"),
|
||||
config->last_known_release,
|
||||
config->last_revision,
|
||||
date);
|
||||
|
||||
/* Finally an optional release comment. */
|
||||
if (config->last_release_comment)
|
||||
{
|
||||
/* Translators: <> tags are Pango markup. Please keep these
|
||||
* markups in your translation. */
|
||||
comment = g_strdup_printf (_("<u>Release comment</u>: <i>%s</i>"), config->last_release_comment);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = g_strdup_printf (_("Download PIKA %s (released on %s)\n"),
|
||||
config->last_known_release, date);
|
||||
}
|
||||
gtk_label_set_text (GTK_LABEL (button_label), text);
|
||||
g_free (text);
|
||||
g_free (date);
|
||||
|
||||
if (comment)
|
||||
{
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_max_width_chars (GTK_LABEL (label), 80);
|
||||
gtk_label_set_markup (GTK_LABEL (label), comment);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
g_free (comment);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
|
||||
gtk_widget_show (label);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Button is a "Check for updates" action. */
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (button_image),
|
||||
"view-refresh",
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_label_set_text (GTK_LABEL (button_label), _("Check for updates"));
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
(GCallback) pika_update_check, config);
|
||||
|
||||
}
|
||||
|
||||
gtk_box_reorder_child (GTK_BOX (vbox), frame, 4);
|
||||
|
||||
/* Last check date box. */
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
if (config->last_known_release != NULL)
|
||||
gtk_widget_set_margin_top (box2, 20);
|
||||
gtk_container_add (GTK_CONTAINER (box), box2);
|
||||
gtk_widget_show (box2);
|
||||
|
||||
/* Show a small "Check for updates" button only if the big one has
|
||||
* been replaced by a download button.
|
||||
*/
|
||||
if (config->last_known_release != NULL)
|
||||
{
|
||||
button = gtk_button_new_from_icon_name ("view-refresh", GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_set_tooltip_text (button, _("Check for updates"));
|
||||
gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 0);
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
(GCallback) pika_update_check, config);
|
||||
gtk_widget_show (button);
|
||||
}
|
||||
|
||||
if (config->check_update_timestamp > 0)
|
||||
{
|
||||
gchar *subtext;
|
||||
gchar *time;
|
||||
|
||||
datetime = g_date_time_new_from_unix_local (config->check_update_timestamp);
|
||||
date = g_date_time_format (datetime, "%x");
|
||||
time = g_date_time_format (datetime, "%X");
|
||||
/* Translators: first string is the date in the locale's date
|
||||
* representation (e.g., 12/31/99), second is the time in the
|
||||
* locale's time representation (e.g., 23:13:48).
|
||||
*/
|
||||
subtext = g_strdup_printf (_("Last checked on %s at %s"), date, time);
|
||||
g_date_time_unref (datetime);
|
||||
g_free (date);
|
||||
g_free (time);
|
||||
|
||||
text = g_strdup_printf ("<i>%s</i>", subtext);
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label), text);
|
||||
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
|
||||
gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
|
||||
gtk_container_child_set (GTK_CONTAINER (box2), label, "expand", TRUE, NULL);
|
||||
gtk_widget_show (label);
|
||||
g_free (text);
|
||||
g_free (subtext);
|
||||
}
|
||||
|
||||
gtk_widget_show (box);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
g_set_weak_pointer (&dialog->update_frame, frame);
|
||||
|
||||
/* Reconstruct the dialog when release info changes. */
|
||||
g_signal_connect (config, "notify::last-known-release",
|
||||
(GCallback) about_dialog_last_release_changed,
|
||||
dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
about_dialog_reshuffle (PikaAboutDialog *dialog)
|
||||
{
|
||||
GRand *gr = g_rand_new ();
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < dialog->n_authors; i++)
|
||||
dialog->shuffle[i] = i;
|
||||
|
||||
for (i = START_INDEX; i < dialog->n_authors; i++)
|
||||
{
|
||||
gint j = g_rand_int_range (gr, START_INDEX, dialog->n_authors);
|
||||
|
||||
if (i != j)
|
||||
{
|
||||
gint t;
|
||||
|
||||
t = dialog->shuffle[j];
|
||||
dialog->shuffle[j] = dialog->shuffle[i];
|
||||
dialog->shuffle[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
g_rand_free (gr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -660,88 +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"));
|
||||
dialog->state += 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (! (dialog->index < dialog->n_authors))
|
||||
dialog->index = 0;
|
||||
|
||||
text = insert_spacers (authors[dialog->shuffle[dialog->index]]);
|
||||
dialog->index += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_return_val_if_reached (TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
g_return_val_if_fail (text != NULL, TRUE);
|
||||
|
||||
pango_layout_set_text (dialog->layout, text, -1);
|
||||
pango_layout_set_attributes (dialog->layout, NULL);
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
if (dialog->animstep < 16)
|
||||
{
|
||||
decorate_text (dialog, 2, ((gfloat) dialog->animstep) / 15.0);
|
||||
}
|
||||
else if (dialog->animstep == 16)
|
||||
{
|
||||
timeout = 800;
|
||||
}
|
||||
else if (dialog->animstep == 17)
|
||||
{
|
||||
timeout = 30;
|
||||
}
|
||||
else if (dialog->animstep < 33)
|
||||
{
|
||||
decorate_text (dialog, 1,
|
||||
1.0 - ((gfloat) (dialog->animstep - 17)) / 15.0);
|
||||
}
|
||||
else if (dialog->animstep == 33)
|
||||
{
|
||||
dialog->visible = FALSE;
|
||||
timeout = 300;
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog->visible = FALSE;
|
||||
dialog->animstep = -1;
|
||||
timeout = 30;
|
||||
}
|
||||
|
||||
dialog->animstep++;
|
||||
|
||||
gtk_widget_queue_draw (dialog->anim_area);
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
dialog->timer = g_timeout_add (timeout, about_dialog_timer, dialog);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* else keep the current timeout */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -159,6 +159,11 @@ static void prefs_gui_config_notify_icon_size (GObject *config,
|
||||
GtkRange *range);
|
||||
static void prefs_icon_size_value_changed (GtkRange *range,
|
||||
PikaGuiConfig *config);
|
||||
static void prefs_gui_config_notify_font_size (GObject *config,
|
||||
GParamSpec *pspec,
|
||||
GtkRange *range);
|
||||
static void prefs_font_size_value_changed (GtkRange *range,
|
||||
PikaGuiConfig *config);
|
||||
|
||||
|
||||
/* private variables */
|
||||
@ -975,6 +980,38 @@ prefs_gui_config_notify_icon_size (GObject *config,
|
||||
config);
|
||||
}
|
||||
|
||||
static void
|
||||
prefs_font_size_value_changed (GtkRange *range,
|
||||
PikaGuiConfig *config)
|
||||
{
|
||||
gdouble value = gtk_range_get_value (range);
|
||||
|
||||
g_signal_handlers_block_by_func (config,
|
||||
G_CALLBACK (prefs_gui_config_notify_font_size),
|
||||
range);
|
||||
g_object_set (G_OBJECT (config),
|
||||
"font-relative-size", value / 100.0,
|
||||
NULL);
|
||||
g_signal_handlers_unblock_by_func (config,
|
||||
G_CALLBACK (prefs_gui_config_notify_font_size),
|
||||
range);
|
||||
}
|
||||
|
||||
static void
|
||||
prefs_gui_config_notify_font_size (GObject *config,
|
||||
GParamSpec *pspec,
|
||||
GtkRange *range)
|
||||
{
|
||||
g_signal_handlers_block_by_func (range,
|
||||
G_CALLBACK (prefs_font_size_value_changed),
|
||||
config);
|
||||
gtk_range_set_value (range,
|
||||
PIKA_GUI_CONFIG (config)->font_relative_size * 100.0);
|
||||
g_signal_handlers_unblock_by_func (range,
|
||||
G_CALLBACK (prefs_font_size_value_changed),
|
||||
config);
|
||||
}
|
||||
|
||||
static void
|
||||
prefs_format_string_select_callback (GtkListBox *listbox,
|
||||
GtkListBoxRow *row,
|
||||
@ -1819,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"),
|
||||
@ -2116,6 +2156,31 @@ prefs_dialog_new (Pika *pika,
|
||||
gtk_box_pack_start (GTK_BOX (vbox3), scale, FALSE, FALSE, 0);
|
||||
gtk_widget_show (scale);
|
||||
|
||||
/* Font sizes. */
|
||||
vbox3 = prefs_frame_new (_("Font Scaling"), GTK_CONTAINER (vbox2), FALSE);
|
||||
pika_help_set_help_data (vbox3,
|
||||
_("Font scaling will not work with themes using absolute sizes."),
|
||||
NULL);
|
||||
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL,
|
||||
50, 200, 10);
|
||||
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_BOTTOM);
|
||||
gtk_scale_add_mark (GTK_SCALE (scale), 50.0, GTK_POS_BOTTOM,
|
||||
_("50%"));
|
||||
gtk_scale_add_mark (GTK_SCALE (scale), 100.0, GTK_POS_BOTTOM,
|
||||
_("100%"));
|
||||
gtk_scale_add_mark (GTK_SCALE (scale), 200.0, GTK_POS_BOTTOM,
|
||||
_("200%"));
|
||||
gtk_range_set_value (GTK_RANGE (scale),
|
||||
(gdouble) PIKA_GUI_CONFIG (object)->font_relative_size * 100.0);
|
||||
g_signal_connect (G_OBJECT (scale), "value-changed",
|
||||
G_CALLBACK (prefs_font_size_value_changed),
|
||||
PIKA_GUI_CONFIG (object));
|
||||
g_signal_connect (G_OBJECT (object), "notify::font-relative-size",
|
||||
G_CALLBACK (prefs_gui_config_notify_font_size),
|
||||
scale);
|
||||
gtk_box_pack_start (GTK_BOX (vbox3), scale, FALSE, FALSE, 0);
|
||||
gtk_widget_show (scale);
|
||||
|
||||
/* Reload Current Theme button */
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
|
||||
|
@ -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
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "core/pika.h"
|
||||
#include "core/pikaviewable.h"
|
||||
|
||||
#include "widgets/pikaaction.h"
|
||||
#include "widgets/pikahelp-ids.h"
|
||||
#include "widgets/pikaviewabledialog.h"
|
||||
|
||||
@ -54,6 +55,9 @@ typedef struct
|
||||
GtkAdjustment *scale_adj;
|
||||
GtkAdjustment *num_adj;
|
||||
GtkAdjustment *denom_adj;
|
||||
|
||||
gdouble prev_scale;
|
||||
gdouble *other_scale;
|
||||
} ScaleDialogData;
|
||||
|
||||
|
||||
@ -81,6 +85,8 @@ static void update_zoom_values (GtkAdjustment *adj,
|
||||
void
|
||||
pika_display_shell_scale_dialog (PikaDisplayShell *shell)
|
||||
{
|
||||
/* scale factor entered in Zoom->Other*/
|
||||
static gdouble other_scale = 0.0;
|
||||
ScaleDialogData *data;
|
||||
PikaImage *image;
|
||||
GtkWidget *toplevel;
|
||||
@ -98,19 +104,21 @@ pika_display_shell_scale_dialog (PikaDisplayShell *shell)
|
||||
return;
|
||||
}
|
||||
|
||||
if (SCALE_EQUALS (shell->other_scale, 0.0))
|
||||
data = g_slice_new (ScaleDialogData);
|
||||
data->prev_scale = other_scale;
|
||||
data->other_scale = &other_scale;
|
||||
|
||||
if (SCALE_EQUALS (other_scale, 0.0))
|
||||
{
|
||||
/* other_scale not yet initialized */
|
||||
shell->other_scale = pika_zoom_model_get_factor (shell->zoom);
|
||||
other_scale = pika_zoom_model_get_factor (shell->zoom);
|
||||
}
|
||||
|
||||
image = pika_display_get_image (shell->display);
|
||||
|
||||
data = g_slice_new (ScaleDialogData);
|
||||
|
||||
data->shell = shell;
|
||||
data->model = g_object_new (PIKA_TYPE_ZOOM_MODEL,
|
||||
"value", fabs (shell->other_scale),
|
||||
"value", fabs (other_scale),
|
||||
NULL);
|
||||
|
||||
g_set_weak_pointer
|
||||
@ -189,7 +197,7 @@ pika_display_shell_scale_dialog (PikaDisplayShell *shell)
|
||||
_("Zoom:"), 0.0, 0.5,
|
||||
hbox, 1);
|
||||
|
||||
data->scale_adj = gtk_adjustment_new (fabs (shell->other_scale) * 100,
|
||||
data->scale_adj = gtk_adjustment_new (other_scale * 100,
|
||||
100.0 / 256.0, 25600.0,
|
||||
10, 50, 0);
|
||||
spin = pika_spin_button_new (data->scale_adj, 1.0, 2);
|
||||
@ -219,7 +227,10 @@ pika_display_shell_scale_dialog_response (GtkWidget *widget,
|
||||
{
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
{
|
||||
gdouble scale;
|
||||
GAction *action;
|
||||
gchar *label;
|
||||
gchar *zoom_str;
|
||||
gdouble scale;
|
||||
|
||||
scale = gtk_adjustment_get_value (dialog->scale_adj);
|
||||
|
||||
@ -227,14 +238,32 @@ pika_display_shell_scale_dialog_response (GtkWidget *widget,
|
||||
PIKA_ZOOM_TO,
|
||||
scale / 100.0,
|
||||
PIKA_ZOOM_FOCUS_BEST_GUESS);
|
||||
|
||||
g_object_get (dialog->shell->zoom,
|
||||
"percentage", &zoom_str,
|
||||
NULL);
|
||||
|
||||
/* Change the "view-zoom-other" label. */
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (dialog->shell->display->pika->app),
|
||||
"view-zoom-other");
|
||||
|
||||
label = g_strdup_printf (_("Othe_r (%s)..."), zoom_str);
|
||||
pika_action_set_short_label (PIKA_ACTION (action), label);
|
||||
g_free (label);
|
||||
|
||||
label = g_strdup_printf (_("Custom Zoom (%s)..."), zoom_str);
|
||||
pika_action_set_label (PIKA_ACTION (action), label);
|
||||
g_free (label);
|
||||
|
||||
g_free (zoom_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* need to emit "scaled" to get the menu updated */
|
||||
pika_display_shell_scaled (dialog->shell);
|
||||
}
|
||||
|
||||
dialog->shell->other_scale = - fabs (dialog->shell->other_scale);
|
||||
*(dialog->other_scale) = dialog->prev_scale;
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog->shell->scale_dialog);
|
||||
}
|
||||
@ -271,6 +300,8 @@ update_zoom_values (GtkAdjustment *adj,
|
||||
|
||||
gtk_adjustment_set_value (dialog->num_adj, num);
|
||||
gtk_adjustment_set_value (dialog->denom_adj, denom);
|
||||
|
||||
*(dialog->other_scale) = scale / 100.0;
|
||||
}
|
||||
else /* fraction adjustments */
|
||||
{
|
||||
@ -278,6 +309,8 @@ update_zoom_values (GtkAdjustment *adj,
|
||||
gtk_adjustment_get_value (dialog->denom_adj));
|
||||
|
||||
gtk_adjustment_set_value (dialog->scale_adj, scale * 100);
|
||||
|
||||
*(dialog->other_scale) = scale;
|
||||
}
|
||||
|
||||
g_signal_handlers_unblock_by_func (dialog->scale_adj,
|
||||
|
@ -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;
|
||||
|
||||
@ -87,8 +89,6 @@ struct _PikaDisplayShell
|
||||
gint last_offset_x; /* offsets used when reverting zoom */
|
||||
gint last_offset_y;
|
||||
|
||||
gdouble other_scale; /* scale factor entered in Zoom->Other*/
|
||||
|
||||
gint disp_width; /* width of drawing area */
|
||||
gint disp_height; /* height of drawing area */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
@ -4210,11 +4224,12 @@ void
|
||||
pika_tool_rectangle_frame_item (PikaToolRectangle *rectangle,
|
||||
PikaItem *item)
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
gint offset_x;
|
||||
gint offset_y;
|
||||
gint width;
|
||||
gint height;
|
||||
PikaDisplayShell *shell;
|
||||
gint offset_x;
|
||||
gint offset_y;
|
||||
gint width;
|
||||
gint height;
|
||||
PikaRectangleFunction old_function;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TOOL_RECTANGLE (rectangle));
|
||||
g_return_if_fail (PIKA_IS_ITEM (item));
|
||||
@ -4230,6 +4245,7 @@ pika_tool_rectangle_frame_item (PikaToolRectangle *rectangle,
|
||||
|
||||
pika_item_get_offset (item, &offset_x, &offset_y);
|
||||
|
||||
old_function = rectangle->private->function;
|
||||
pika_tool_rectangle_set_function (rectangle, PIKA_TOOL_RECTANGLE_CREATING);
|
||||
|
||||
g_object_set (rectangle,
|
||||
@ -4243,6 +4259,7 @@ pika_tool_rectangle_frame_item (PikaToolRectangle *rectangle,
|
||||
* if this function is ever moved out of the text tool code.
|
||||
*/
|
||||
pika_tool_rectangle_set_constraint (rectangle, PIKA_RECTANGLE_CONSTRAIN_NONE);
|
||||
pika_tool_rectangle_set_function (rectangle, old_function);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -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,
|
||||
|
@ -134,7 +134,7 @@ file_open_image (Pika *pika,
|
||||
if (! info)
|
||||
return NULL;
|
||||
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) != G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Not a regular file"));
|
||||
@ -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;
|
||||
|
@ -138,7 +138,7 @@ file_save (Pika *pika,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) != G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Not a regular file"));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ icon_themes_init (Pika *pika)
|
||||
while ((info = g_file_enumerator_next_file (enumerator,
|
||||
NULL, NULL)))
|
||||
{
|
||||
if (! g_file_info_get_is_hidden (info) &&
|
||||
g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
|
||||
if (! g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) &&
|
||||
g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
GFile *file;
|
||||
GFile *index_theme;
|
||||
|
@ -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 ();
|
||||
}
|
||||
@ -599,7 +617,7 @@ splash_image_load_from_file (GFile *file,
|
||||
{
|
||||
const gchar *content_type;
|
||||
|
||||
content_type = g_file_info_get_content_type (info);
|
||||
content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
|
||||
if (content_type)
|
||||
{
|
||||
gchar *mime_type;
|
||||
|
@ -35,6 +35,10 @@
|
||||
|
||||
#include "core/pika.h"
|
||||
|
||||
#include "display/pikaimagewindow.h"
|
||||
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
|
||||
#include "themes.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
@ -104,8 +108,15 @@ themes_init (Pika *pika)
|
||||
g_signal_connect (config, "notify::custom-icon-size",
|
||||
G_CALLBACK (themes_theme_change_notify),
|
||||
pika);
|
||||
g_signal_connect (config, "notify::font-relative-size",
|
||||
G_CALLBACK (themes_theme_change_notify),
|
||||
pika);
|
||||
|
||||
themes_theme_change_notify (config, NULL, pika);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
themes_set_title_bar (pika);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -377,6 +388,12 @@ themes_apply_theme (Pika *pika,
|
||||
button_icon_size);
|
||||
}
|
||||
|
||||
if (! error && config->font_relative_size != 1.0)
|
||||
g_output_stream_printf (output, NULL, NULL, &error,
|
||||
"\n"
|
||||
"* { font-size: %frem; }",
|
||||
config->font_relative_size);
|
||||
|
||||
if (! error)
|
||||
{
|
||||
g_output_stream_printf (
|
||||
@ -464,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
|
||||
@ -515,8 +536,8 @@ themes_theme_paths_notify (PikaExtensionManager *manager,
|
||||
while ((info = g_file_enumerator_next_file (enumerator,
|
||||
NULL, NULL)))
|
||||
{
|
||||
if (! g_file_info_get_is_hidden (info) &&
|
||||
g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
|
||||
if (! g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) &&
|
||||
g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
GFile *file;
|
||||
const gchar *name;
|
||||
@ -544,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);
|
||||
@ -273,9 +258,20 @@ shortcuts_action_deserialize (GScanner *scanner,
|
||||
builder = g_strv_builder_new ();
|
||||
while (pika_scanner_parse_string (scanner, &accel))
|
||||
{
|
||||
gchar **dup_actions;
|
||||
gboolean add_accel = TRUE;
|
||||
gchar **dup_actions;
|
||||
gboolean add_accel = TRUE;
|
||||
guint accelerator_key = 0;
|
||||
GdkModifierType accelerator_mods = 0;
|
||||
|
||||
gtk_accelerator_parse (accel, &accelerator_key, &accelerator_mods);
|
||||
if (accelerator_key == 0 && accelerator_mods == 0)
|
||||
{
|
||||
g_printerr ("INFO: invalid accelerator '%s' on '%s'.\n"
|
||||
" Removing this accelerator.\n",
|
||||
accel, action_name);
|
||||
g_free (accel);
|
||||
continue;
|
||||
}
|
||||
dup_actions = gtk_application_get_actions_for_accel (application, accel);
|
||||
|
||||
for (gint i = 0; dup_actions[i] != NULL; i++)
|
||||
|
@ -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);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user