Initial checkin of Pika from heckimp

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

148
app/tools/meson.build Normal file
View File

@ -0,0 +1,148 @@
stamp_tools_enums = custom_target('stamp-tools-enums.h',
input : [
files(
'tools-enums.h'
),
],
output: [ 'stamp-tools-enums.h', ],
command: [
mkenums_wrap, perl,
meson.project_source_root(), meson.current_source_dir(),
meson.current_build_dir(),
'tools-',
'#include <gio/gio.h>\n' +
'#include "libpikabase/pikabase.h"\n' +
'#include "core/core-enums.h"\n',
'#include "pika-intl.h"'
],
build_by_default: true
)
libapptools_sources = [
'pika-tools.c',
'pika-tool-options-manager.c',
'pikaairbrushtool.c',
'pikaalignoptions.c',
'pikaaligntool.c',
'pikabrightnesscontrasttool.c',
'pikabrushtool.c',
'pikabucketfilloptions.c',
'pikabucketfilltool.c',
'pikabycolorselecttool.c',
'pikacageoptions.c',
'pikacagetool.c',
'pikacloneoptions-gui.c',
'pikaclonetool.c',
'pikacoloroptions.c',
'pikacolorpickeroptions.c',
'pikacolorpickertool.c',
'pikacolortool.c',
'pikaconvolvetool.c',
'pikacropoptions.c',
'pikacroptool.c',
'pikacurvestool.c',
'pikadodgeburntool.c',
'pikadrawtool.c',
'pikaeditselectiontool.c',
'pikaellipseselecttool.c',
'pikaerasertool.c',
'pikafilteroptions.c',
'pikafiltertool-settings.c',
'pikafiltertool-widgets.c',
'pikafiltertool.c',
'pikaflipoptions.c',
'pikafliptool.c',
'pikaforegroundselectoptions.c',
'pikaforegroundselecttool.c',
'pikaforegroundselecttoolundo.c',
'pikafreeselecttool.c',
'pikafuzzyselecttool.c',
'pikagegltool.c',
'pikagenerictransformtool.c',
'pikagradientoptions.c',
'pikagradienttool-editor.c',
'pikagradienttool.c',
'pikaguidetool.c',
'pikahandletransformoptions.c',
'pikahandletransformtool.c',
'pikahealtool.c',
'pikahistogramoptions.c',
'pikainkoptions-gui.c',
'pikainktool.c',
'pikaiscissorsoptions.c',
'pikaiscissorstool.c',
'pikalevelstool.c',
'pikamagnifyoptions.c',
'pikamagnifytool.c',
'pikameasureoptions.c',
'pikameasuretool.c',
'pikamoveoptions.c',
'pikamovetool.c',
'pikamybrushoptions-gui.c',
'pikamybrushtool.c',
'pikanpointdeformationoptions.c',
'pikanpointdeformationtool.c',
'pikaoffsettool.c',
'pikaoperationtool.c',
'pikapaintbrushtool.c',
'pikapaintoptions-gui.c',
'pikapaintselectoptions.c',
'pikapaintselecttool.c',
'pikapainttool-paint.c',
'pikapainttool.c',
'pikapenciltool.c',
'pikaperspectiveclonetool.c',
'pikaperspectivetool.c',
'pikapolygonselecttool.c',
'pikarectangleoptions.c',
'pikarectangleselectoptions.c',
'pikarectangleselecttool.c',
'pikaregionselectoptions.c',
'pikaregionselecttool.c',
'pikarotatetool.c',
'pikasamplepointtool.c',
'pikascaletool.c',
'pikaseamlesscloneoptions.c',
'pikaseamlessclonetool.c',
'pikaselectionoptions.c',
'pikaselectiontool.c',
'pikasheartool.c',
'pikasmudgetool.c',
'pikasourcetool.c',
'pikatextoptions.c',
'pikatexttool-editor.c',
'pikatexttool.c',
'pikathresholdtool.c',
'pikatilehandleriscissors.c',
'pikatool-progress.c',
'pikatool.c',
'pikatoolcontrol.c',
'pikatooloptions-gui.c',
'pikatools-utils.c',
'pikatransform3doptions.c',
'pikatransform3dtool.c',
'pikatransformgridoptions.c',
'pikatransformgridtool.c',
'pikatransformgridtoolundo.c',
'pikatransformoptions.c',
'pikatransformtool.c',
'pikaunifiedtransformtool.c',
'pikavectoroptions.c',
'pikavectortool.c',
'pikawarpoptions.c',
'pikawarptool.c',
'tool_manager.c',
'tools-enums.c',
stamp_tools_enums,
appcoremarshal[1],
]
libapptools = static_library('apptools',
libapptools_sources,
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Pika-Tools"',
dependencies: [
gegl, gtk3,
],
)

View File

@ -0,0 +1,462 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pika-tool-options-manager.c
* Copyright (C) 2018 Michael Natterer <mitch@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikaconfig/pikaconfig.h"
#include "tools-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikatoolinfo.h"
#include "paint/pikapaintoptions.h"
#include "widgets/pikawidgets-utils.h"
#include "pika-tool-options-manager.h"
typedef struct _PikaToolOptionsManager PikaToolOptionsManager;
struct _PikaToolOptionsManager
{
Pika *pika;
PikaPaintOptions *global_paint_options;
PikaContextPropMask global_props;
PikaToolInfo *active_tool;
};
/* local function prototypes */
static PikaContextPropMask
tool_options_manager_get_global_props
(PikaCoreConfig *config);
static void tool_options_manager_global_notify (PikaCoreConfig *config,
const GParamSpec *pspec,
PikaToolOptionsManager *manager);
static void tool_options_manager_paint_options_notify
(PikaPaintOptions *src,
const GParamSpec *pspec,
PikaPaintOptions *dest);
static void tool_options_manager_copy_paint_props
(PikaPaintOptions *src,
PikaPaintOptions *dest,
PikaContextPropMask prop_mask);
static void tool_options_manager_tool_changed (PikaContext *user_context,
PikaToolInfo *tool_info,
PikaToolOptionsManager *manager);
static GQuark manager_quark = 0;
/* public functions */
void
pika_tool_options_manager_init (Pika *pika)
{
PikaToolOptionsManager *manager;
PikaContext *user_context;
GList *list;
g_return_if_fail (PIKA_IS_PIKA (pika));
g_return_if_fail (manager_quark == 0);
manager_quark = g_quark_from_static_string ("pika-tool-options-manager");
manager = g_slice_new0 (PikaToolOptionsManager);
g_object_set_qdata (G_OBJECT (pika), manager_quark, manager);
manager->pika = pika;
manager->global_paint_options =
g_object_new (PIKA_TYPE_PAINT_OPTIONS,
"pika", pika,
"name", "tool-options-manager-global-paint-options",
NULL);
manager->global_props = tool_options_manager_get_global_props (pika->config);
user_context = pika_get_user_context (pika);
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = list->data;
/* the global props that are actually used by the tool are
* always shared with the user context by undefining them...
*/
pika_context_define_properties (PIKA_CONTEXT (tool_info->tool_options),
manager->global_props &
tool_info->context_props,
FALSE);
/* ...and setting the user context as parent
*/
pika_context_set_parent (PIKA_CONTEXT (tool_info->tool_options),
user_context);
/* make sure paint tools also share their brush, dynamics,
* gradient properties if the resp. context properties are
* global
*/
if (PIKA_IS_PAINT_OPTIONS (tool_info->tool_options))
{
g_signal_connect (tool_info->tool_options, "notify",
G_CALLBACK (tool_options_manager_paint_options_notify),
manager->global_paint_options);
g_signal_connect (manager->global_paint_options, "notify",
G_CALLBACK (tool_options_manager_paint_options_notify),
tool_info->tool_options);
tool_options_manager_copy_paint_props (manager->global_paint_options,
PIKA_PAINT_OPTIONS (tool_info->tool_options),
tool_info->context_props &
manager->global_props);
}
}
g_signal_connect (pika->config, "notify::global-brush",
G_CALLBACK (tool_options_manager_global_notify),
manager);
g_signal_connect (pika->config, "notify::global-dynamics",
G_CALLBACK (tool_options_manager_global_notify),
manager);
g_signal_connect (pika->config, "notify::global-pattern",
G_CALLBACK (tool_options_manager_global_notify),
manager);
g_signal_connect (pika->config, "notify::global-palette",
G_CALLBACK (tool_options_manager_global_notify),
manager);
g_signal_connect (pika->config, "notify::global-gradient",
G_CALLBACK (tool_options_manager_global_notify),
manager);
g_signal_connect (pika->config, "notify::global-font",
G_CALLBACK (tool_options_manager_global_notify),
manager);
g_signal_connect (user_context, "tool-changed",
G_CALLBACK (tool_options_manager_tool_changed),
manager);
tool_options_manager_tool_changed (user_context,
pika_context_get_tool (user_context),
manager);
}
void
pika_tool_options_manager_exit (Pika *pika)
{
PikaToolOptionsManager *manager;
PikaContext *user_context;
GList *list;
g_return_if_fail (PIKA_IS_PIKA (pika));
manager = g_object_get_qdata (G_OBJECT (pika), manager_quark);
g_return_if_fail (manager != NULL);
user_context = pika_get_user_context (pika);
g_signal_handlers_disconnect_by_func (user_context,
tool_options_manager_tool_changed,
manager);
g_signal_handlers_disconnect_by_func (pika->config,
tool_options_manager_global_notify,
manager);
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = list->data;
pika_context_set_parent (PIKA_CONTEXT (tool_info->tool_options), NULL);
if (PIKA_IS_PAINT_OPTIONS (tool_info->tool_options))
{
g_signal_handlers_disconnect_by_func (tool_info->tool_options,
tool_options_manager_paint_options_notify,
manager->global_paint_options);
g_signal_handlers_disconnect_by_func (manager->global_paint_options,
tool_options_manager_paint_options_notify,
tool_info->tool_options);
}
}
g_clear_object (&manager->global_paint_options);
g_slice_free (PikaToolOptionsManager, manager);
g_object_set_qdata (G_OBJECT (pika), manager_quark, NULL);
}
/* private functions */
static PikaContextPropMask
tool_options_manager_get_global_props (PikaCoreConfig *config)
{
PikaContextPropMask global_props = 0;
/* FG and BG are always shared between all tools */
global_props |= PIKA_CONTEXT_PROP_MASK_FOREGROUND;
global_props |= PIKA_CONTEXT_PROP_MASK_BACKGROUND;
if (config->global_brush)
global_props |= PIKA_CONTEXT_PROP_MASK_BRUSH;
if (config->global_dynamics)
global_props |= PIKA_CONTEXT_PROP_MASK_DYNAMICS;
if (config->global_pattern)
global_props |= PIKA_CONTEXT_PROP_MASK_PATTERN;
if (config->global_palette)
global_props |= PIKA_CONTEXT_PROP_MASK_PALETTE;
if (config->global_gradient)
global_props |= PIKA_CONTEXT_PROP_MASK_GRADIENT;
if (config->global_font)
global_props |= PIKA_CONTEXT_PROP_MASK_FONT;
return global_props;
}
static void
tool_options_manager_global_notify (PikaCoreConfig *config,
const GParamSpec *pspec,
PikaToolOptionsManager *manager)
{
PikaContextPropMask global_props;
PikaContextPropMask enabled_global_props;
PikaContextPropMask disabled_global_props;
GList *list;
global_props = tool_options_manager_get_global_props (config);
enabled_global_props = global_props & ~manager->global_props;
disabled_global_props = manager->global_props & ~global_props;
/* copy the newly enabled global props to all tool options, and
* disconnect the newly disabled ones from the user context
*/
for (list = pika_get_tool_info_iter (manager->pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = list->data;
/* don't change the active tool, it is always fully connected
* to the user_context anyway because we set its
* defined/undefined context props in tool_changed()
*/
if (tool_info == manager->active_tool)
continue;
/* defining the newly disabled ones disconnects them from the
* parent user context
*/
pika_context_define_properties (PIKA_CONTEXT (tool_info->tool_options),
tool_info->context_props &
disabled_global_props,
TRUE);
/* undefining the newly enabled ones copies the value from the
* parent user context
*/
pika_context_define_properties (PIKA_CONTEXT (tool_info->tool_options),
tool_info->context_props &
enabled_global_props,
FALSE);
if (PIKA_IS_PAINT_OPTIONS (tool_info->tool_options))
tool_options_manager_copy_paint_props (manager->global_paint_options,
PIKA_PAINT_OPTIONS (tool_info->tool_options),
tool_info->context_props &
enabled_global_props);
}
manager->global_props = global_props;
}
static void
tool_options_manager_paint_options_notify (PikaPaintOptions *src,
const GParamSpec *pspec,
PikaPaintOptions *dest)
{
Pika *pika = PIKA_CONTEXT (src)->pika;
PikaCoreConfig *config = pika->config;
PikaToolOptionsManager *manager;
PikaToolInfo *tool_info;
PikaContextPropMask prop_mask = 0;
gboolean active = FALSE;
manager = g_object_get_qdata (G_OBJECT (pika), manager_quark);
/* one of the options is the global one, the other is the tool's,
* get the tool_info from the tool's options
*/
if (manager->global_paint_options == src)
tool_info = pika_context_get_tool (PIKA_CONTEXT (dest));
else
tool_info = pika_context_get_tool (PIKA_CONTEXT (src));
if (tool_info == manager->active_tool)
active = TRUE;
if ((active || config->global_brush) &&
tool_info->context_props & PIKA_CONTEXT_PROP_MASK_BRUSH)
{
prop_mask |= PIKA_CONTEXT_PROP_MASK_BRUSH;
}
if ((active || config->global_dynamics) &&
tool_info->context_props & PIKA_CONTEXT_PROP_MASK_DYNAMICS)
{
prop_mask |= PIKA_CONTEXT_PROP_MASK_DYNAMICS;
}
if ((active || config->global_gradient) &&
tool_info->context_props & PIKA_CONTEXT_PROP_MASK_GRADIENT)
{
prop_mask |= PIKA_CONTEXT_PROP_MASK_GRADIENT;
}
if (pika_paint_options_is_prop (pspec->name, prop_mask))
{
GValue value = G_VALUE_INIT;
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (src), pspec->name, &value);
g_signal_handlers_block_by_func (dest,
tool_options_manager_paint_options_notify,
src);
g_object_set_property (G_OBJECT (dest), pspec->name, &value);
g_signal_handlers_unblock_by_func (dest,
tool_options_manager_paint_options_notify,
src);
g_value_unset (&value);
}
}
static void
tool_options_manager_copy_paint_props (PikaPaintOptions *src,
PikaPaintOptions *dest,
PikaContextPropMask prop_mask)
{
g_signal_handlers_block_by_func (dest,
tool_options_manager_paint_options_notify,
src);
pika_paint_options_copy_props (src, dest, prop_mask);
g_signal_handlers_unblock_by_func (dest,
tool_options_manager_paint_options_notify,
src);
}
static void
tool_options_manager_tool_changed (PikaContext *user_context,
PikaToolInfo *tool_info,
PikaToolOptionsManager *manager)
{
if (tool_info == manager->active_tool)
return;
/* FIXME: pika_busy HACK
* the tool manager will stop the emission, so simply return
*/
if (manager->pika->busy)
return;
if (manager->active_tool)
{
PikaToolInfo *active = manager->active_tool;
/* disconnect the old active tool from all context properties
* it uses, but are not currently global
*/
pika_context_define_properties (PIKA_CONTEXT (active->tool_options),
active->context_props &
~manager->global_props,
TRUE);
}
manager->active_tool = tool_info;
if (manager->active_tool)
{
PikaToolInfo *active = manager->active_tool;
/* make sure the tool options GUI always exists, this call
* creates it if needed, so tools always have their option GUI
* available even if the tool options dockable is not open, see
* for example issue #3435
*/
pika_tools_get_tool_options_gui (active->tool_options);
/* copy the new tool's context properties that are not
* currently global to the user context, so they get used by
* everything
*/
pika_context_copy_properties (PIKA_CONTEXT (active->tool_options),
pika_get_user_context (manager->pika),
active->context_props &
~manager->global_props);
if (PIKA_IS_PAINT_OPTIONS (active->tool_options))
tool_options_manager_copy_paint_props (PIKA_PAINT_OPTIONS (active->tool_options),
manager->global_paint_options,
active->context_props &
~manager->global_props);
/* then, undefine these properties so the tool syncs with the
* user context automatically
*/
pika_context_define_properties (PIKA_CONTEXT (active->tool_options),
active->context_props &
~manager->global_props,
FALSE);
}
}

View File

@ -0,0 +1,33 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pika-tool-options-manager.h
* Copyright (C) 2018 Michael Natterer <mitch@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_TOOL_OPTIONS_MANAGER_H__
#define __PIKA_TOOL_OPTIONS_MANAGER_H__
void pika_tool_options_manager_init (Pika *pika);
void pika_tool_options_manager_exit (Pika *pika);
#endif /* __PIKA_TOOL_OPTIONS_MANAGER_H__ */

838
app/tools/pika-tools.c Normal file
View File

@ -0,0 +1,838 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikawidgets-utils.h"
#include "core/pika.h"
#include "core/pika-contexts.h"
#include "core/pika-internal-data.h"
#include "core/pikacontext.h"
#include "core/pikalist.h"
#include "core/pikatoolgroup.h"
#include "core/pikatoolinfo.h"
#include "core/pikatooloptions.h"
#include "pika-tool-options-manager.h"
#include "pika-tools.h"
#include "pikatooloptions-gui.h"
#include "tool_manager.h"
#include "pikaairbrushtool.h"
#include "pikaaligntool.h"
#include "pikabrightnesscontrasttool.h"
#include "pikabucketfilltool.h"
#include "pikabycolorselecttool.h"
#include "pikacagetool.h"
#include "pikaclonetool.h"
#include "pikacolorpickertool.h"
#include "pikaconvolvetool.h"
#include "pikacroptool.h"
#include "pikacurvestool.h"
#include "pikadodgeburntool.h"
#include "pikaellipseselecttool.h"
#include "pikaerasertool.h"
#include "pikafliptool.h"
#include "pikafreeselecttool.h"
#include "pikaforegroundselecttool.h"
#include "pikafuzzyselecttool.h"
#include "pikagegltool.h"
#include "pikagradienttool.h"
#include "pikahandletransformtool.h"
#include "pikahealtool.h"
#include "pikainktool.h"
#include "pikaiscissorstool.h"
#include "pikalevelstool.h"
#include "pikaoperationtool.h"
#include "pikamagnifytool.h"
#include "pikameasuretool.h"
#include "pikamovetool.h"
#include "pikamybrushtool.h"
#include "pikanpointdeformationtool.h"
#include "pikaoffsettool.h"
#include "pikapaintbrushtool.h"
#include "pikapaintselecttool.h"
#include "pikapenciltool.h"
#include "pikaperspectiveclonetool.h"
#include "pikaperspectivetool.h"
#include "pikathresholdtool.h"
#include "pikarectangleselecttool.h"
#include "pikarotatetool.h"
#include "pikaseamlessclonetool.h"
#include "pikascaletool.h"
#include "pikasheartool.h"
#include "pikasmudgetool.h"
#include "pikatexttool.h"
#include "pikatransform3dtool.h"
#include "pikaunifiedtransformtool.h"
#include "pikavectortool.h"
#include "pikawarptool.h"
#include "pika-intl.h"
#define TOOL_RC_FILE_VERSION 1
/* local function prototypes */
static void pika_tools_register (GType tool_type,
GType tool_options_type,
PikaToolOptionsGUIFunc options_gui_func,
PikaContextPropMask context_props,
const gchar *identifier,
const gchar *label,
const gchar *tooltip,
const gchar *menu_label,
const gchar *menu_accel,
const gchar *help_domain,
const gchar *help_data,
const gchar *icon_name,
gpointer data);
static void pika_tools_copy_structure (Pika *pika,
PikaContainer *src_container,
PikaContainer *dest_container,
GHashTable *tools);
/* private variables */
static GBinding *toolbox_groups_binding = NULL;
static gboolean tool_options_deleted = FALSE;
/* public functions */
void
pika_tools_init (Pika *pika)
{
PikaToolRegisterFunc register_funcs[] =
{
/* selection tools */
pika_rectangle_select_tool_register,
pika_ellipse_select_tool_register,
pika_free_select_tool_register,
pika_fuzzy_select_tool_register,
pika_by_color_select_tool_register,
pika_iscissors_tool_register,
pika_foreground_select_tool_register,
pika_paint_select_tool_register,
/* path tool */
pika_vector_tool_register,
/* non-modifying tools */
pika_color_picker_tool_register,
pika_magnify_tool_register,
pika_measure_tool_register,
/* transform tools */
pika_move_tool_register,
pika_align_tool_register,
pika_crop_tool_register,
pika_unified_transform_tool_register,
pika_rotate_tool_register,
pika_scale_tool_register,
pika_shear_tool_register,
pika_handle_transform_tool_register,
pika_perspective_tool_register,
pika_transform_3d_tool_register,
pika_flip_tool_register,
pika_cage_tool_register,
pika_warp_tool_register,
pika_n_point_deformation_tool_register,
/* paint tools */
pika_seamless_clone_tool_register,
pika_text_tool_register,
pika_bucket_fill_tool_register,
pika_gradient_tool_register,
pika_pencil_tool_register,
pika_paintbrush_tool_register,
pika_eraser_tool_register,
pika_airbrush_tool_register,
pika_ink_tool_register,
pika_mybrush_tool_register,
pika_clone_tool_register,
pika_heal_tool_register,
pika_perspective_clone_tool_register,
pika_convolve_tool_register,
pika_smudge_tool_register,
pika_dodge_burn_tool_register,
/* filter tools */
pika_brightness_contrast_tool_register,
pika_threshold_tool_register,
pika_levels_tool_register,
pika_curves_tool_register,
pika_offset_tool_register,
pika_gegl_tool_register,
pika_operation_tool_register
};
gint i;
g_return_if_fail (PIKA_IS_PIKA (pika));
pika_tool_options_create_folder ();
pika_container_freeze (pika->tool_info_list);
for (i = 0; i < G_N_ELEMENTS (register_funcs); i++)
{
register_funcs[i] (pika_tools_register, pika);
}
pika_container_thaw (pika->tool_info_list);
pika_tool_options_manager_init (pika);
tool_manager_init (pika);
toolbox_groups_binding = g_object_bind_property (
pika->config, "toolbox-groups",
pika->tool_item_ui_list, "flat",
G_BINDING_INVERT_BOOLEAN |
G_BINDING_SYNC_CREATE);
}
void
pika_tools_exit (Pika *pika)
{
GList *list;
g_return_if_fail (PIKA_IS_PIKA (pika));
g_clear_object (&toolbox_groups_binding);
tool_manager_exit (pika);
pika_tool_options_manager_exit (pika);
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = list->data;
pika_tools_set_tool_options_gui (tool_info->tool_options, NULL);
}
}
void
pika_tools_restore (Pika *pika)
{
PikaObject *object;
GList *list;
GError *error = NULL;
g_return_if_fail (PIKA_IS_PIKA (pika));
/* restore tool order */
pika_tools_reset (pika, pika->tool_item_list, TRUE);
/* make the generic operation tool invisible by default */
object = pika_container_get_child_by_name (pika->tool_info_list,
"pika-operation-tool");
if (object)
g_object_set (object, "visible", FALSE, NULL);
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = PIKA_TOOL_INFO (list->data);
/* get default values from prefs (see bug #120832) */
pika_config_reset (PIKA_CONFIG (tool_info->tool_options));
}
if (! pika_contexts_load (pika, &error))
{
pika_message_literal (pika, NULL, PIKA_MESSAGE_WARNING, error->message);
g_clear_error (&error);
}
if (! pika_internal_data_load (pika, &error))
{
pika_message_literal (pika, NULL, PIKA_MESSAGE_WARNING, error->message);
g_clear_error (&error);
}
/* make sure there is always a tool active, so broken config files
* can't leave us with no initial tool
*/
if (! pika_context_get_tool (pika_get_user_context (pika)))
{
pika_context_set_tool (pika_get_user_context (pika),
pika_get_tool_info_iter (pika)->data);
}
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = PIKA_TOOL_INFO (list->data);
PikaToolOptionsGUIFunc options_gui_func;
/* copy all context properties except those the tool actually
* uses, because the subsequent deserialize() on the tool
* options will only set the properties that were set to
* non-default values at the time of saving, and we want to
* keep these default values as if they have been saved.
* (see bug #541586).
*/
pika_context_copy_properties (pika_get_user_context (pika),
PIKA_CONTEXT (tool_info->tool_options),
PIKA_CONTEXT_PROP_MASK_ALL &~
(tool_info->context_props |
PIKA_CONTEXT_PROP_MASK_TOOL |
PIKA_CONTEXT_PROP_MASK_PAINT_INFO));
pika_tool_options_deserialize (tool_info->tool_options, NULL);
options_gui_func = g_object_get_data (G_OBJECT (tool_info),
"pika-tool-options-gui-func");
if (! options_gui_func)
options_gui_func = pika_tool_options_empty_gui;
pika_tools_set_tool_options_gui_func (tool_info->tool_options,
options_gui_func);
}
}
void
pika_tools_save (Pika *pika,
gboolean save_tool_options,
gboolean always_save)
{
PikaConfigWriter *writer;
GFile *file;
g_return_if_fail (PIKA_IS_PIKA (pika));
if (save_tool_options && (! tool_options_deleted || always_save))
{
GList *list;
GError *error = NULL;
if (! pika_contexts_save (pika, &error))
{
pika_message_literal (pika, NULL, PIKA_MESSAGE_WARNING,
error->message);
g_clear_error (&error);
}
if (! pika_internal_data_save (pika, &error))
{
pika_message_literal (pika, NULL, PIKA_MESSAGE_WARNING,
error->message);
g_clear_error (&error);
}
pika_tool_options_create_folder ();
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = PIKA_TOOL_INFO (list->data);
pika_tool_options_serialize (tool_info->tool_options, NULL);
}
}
file = pika_directory_file ("toolrc", NULL);
if (pika->be_verbose)
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
writer = pika_config_writer_new_from_file (file, TRUE, "PIKA toolrc", NULL);
if (writer)
{
pika_tools_serialize (pika, pika->tool_item_list, writer);
pika_config_writer_finish (writer, "end of toolrc", NULL);
}
g_object_unref (file);
}
gboolean
pika_tools_clear (Pika *pika,
GError **error)
{
GList *list;
gboolean success = TRUE;
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
for (list = pika_get_tool_info_iter (pika);
list && success;
list = g_list_next (list))
{
PikaToolInfo *tool_info = PIKA_TOOL_INFO (list->data);
success = pika_tool_options_delete (tool_info->tool_options, NULL);
}
if (success)
success = pika_contexts_clear (pika, error);
if (success)
success = pika_internal_data_clear (pika, error);
if (success)
tool_options_deleted = TRUE;
return success;
}
gboolean
pika_tools_serialize (Pika *pika,
PikaContainer *container,
PikaConfigWriter *writer)
{
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
pika_config_writer_open (writer, "file-version");
pika_config_writer_printf (writer, "%d", TOOL_RC_FILE_VERSION);
pika_config_writer_close (writer);
pika_config_writer_linefeed (writer);
return pika_config_serialize (PIKA_CONFIG (container), writer, NULL);
}
gboolean
pika_tools_deserialize (Pika *pika,
PikaContainer *container,
GScanner *scanner)
{
enum
{
FILE_VERSION = 1
};
PikaContainer *src_container;
GTokenType token;
guint scope_id;
guint old_scope_id;
gint file_version = 0;
gboolean result = FALSE;
scope_id = g_type_qname (PIKA_TYPE_TOOL_GROUP);
old_scope_id = g_scanner_set_scope (scanner, scope_id);
g_scanner_scope_add_symbol (scanner, scope_id,
"file-version",
GINT_TO_POINTER (FILE_VERSION));
token = G_TOKEN_LEFT_PAREN;
while (g_scanner_peek_next_token (scanner) == token &&
(token != G_TOKEN_LEFT_PAREN ||
! file_version))
{
token = g_scanner_get_next_token (scanner);
switch (token)
{
case G_TOKEN_LEFT_PAREN:
token = G_TOKEN_SYMBOL;
break;
case G_TOKEN_SYMBOL:
switch (GPOINTER_TO_INT (scanner->value.v_symbol))
{
case FILE_VERSION:
token = G_TOKEN_INT;
if (pika_scanner_parse_int (scanner, &file_version))
token = G_TOKEN_RIGHT_PAREN;
break;
}
break;
case G_TOKEN_RIGHT_PAREN:
token = G_TOKEN_LEFT_PAREN;
break;
default:
break;
}
}
g_scanner_set_scope (scanner, old_scope_id);
if (token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
_("fatal parse error"), TRUE);
return FALSE;
}
else if (file_version != TOOL_RC_FILE_VERSION)
{
g_scanner_error (scanner, "wrong toolrc file format version");
return FALSE;
}
pika_container_freeze (container);
/* make sure the various PikaToolItem types are registered */
g_type_class_unref (g_type_class_ref (PIKA_TYPE_TOOL_GROUP));
g_type_class_unref (g_type_class_ref (PIKA_TYPE_TOOL_INFO));
pika_container_clear (container);
src_container = g_object_new (PIKA_TYPE_LIST,
"children-type", PIKA_TYPE_TOOL_ITEM,
"append", TRUE,
NULL);
if (pika_config_deserialize (PIKA_CONFIG (src_container),
scanner, 0, NULL))
{
GHashTable *tools;
GList *list;
result = TRUE;
tools = g_hash_table_new (g_direct_hash, g_direct_equal);
pika_tools_copy_structure (pika, src_container, container, tools);
for (list = pika_get_tool_info_iter (pika);
list;
list = g_list_next (list))
{
PikaToolInfo *tool_info = list->data;
if (! tool_info->hidden && ! g_hash_table_contains (tools, tool_info))
{
if (tool_info->experimental)
{
/* if an experimental tool is not in the file, just add it to
* the tool-item list.
*/
pika_container_add (container, PIKA_OBJECT (tool_info));
}
else
{
/* otherwise, it means we added a new stable tool. this must
* be the user toolrc file; rejct it, so that we fall back to
* the default toolrc file, which should contain the missing
* tool.
*/
g_scanner_error (scanner, "missing tools in toolrc file");
result = FALSE;
break;
}
}
}
g_hash_table_unref (tools);
}
g_object_unref (src_container);
pika_container_thaw (container);
return result;
}
void
pika_tools_reset (Pika *pika,
PikaContainer *container,
gboolean user_toolrc)
{
GList *files = NULL;
GList *list;
g_return_if_fail (PIKA_IS_PIKA (pika));
g_return_if_fail (PIKA_IS_CONTAINER (container));
if (user_toolrc)
files = g_list_prepend (files, pika_directory_file ("toolrc", NULL));
files = g_list_prepend (files, pika_sysconf_directory_file ("toolrc", NULL));
files = g_list_reverse (files);
pika_container_freeze (container);
pika_container_clear (container);
for (list = files; list; list = g_list_next (list))
{
GScanner *scanner;
GFile *file = list->data;
GError *error = NULL;
if (pika->be_verbose)
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
scanner = pika_scanner_new_file (file, &error);
if (scanner && pika_tools_deserialize (pika, container, scanner))
{
pika_scanner_unref (scanner);
break;
}
else
{
if (error->code != G_IO_ERROR_NOT_FOUND)
{
pika_message_literal (pika, NULL,
PIKA_MESSAGE_WARNING, error->message);
}
g_clear_error (&error);
pika_container_clear (container);
}
g_clear_pointer (&scanner, pika_scanner_unref);
}
g_list_free_full (files, g_object_unref);
if (pika_container_is_empty (container))
{
if (pika->be_verbose)
g_print ("Using default tool order\n");
pika_tools_copy_structure (pika, pika->tool_info_list, container, NULL);
}
pika_container_thaw (container);
}
/* private functions */
static void
pika_tools_register (GType tool_type,
GType tool_options_type,
PikaToolOptionsGUIFunc options_gui_func,
PikaContextPropMask context_props,
const gchar *identifier,
const gchar *label,
const gchar *tooltip,
const gchar *menu_label,
const gchar *menu_accel,
const gchar *help_domain,
const gchar *help_data,
const gchar *icon_name,
gpointer data)
{
Pika *pika = (Pika *) data;
PikaToolInfo *tool_info;
const gchar *paint_core_name;
gboolean visible;
g_return_if_fail (PIKA_IS_PIKA (pika));
g_return_if_fail (g_type_is_a (tool_type, PIKA_TYPE_TOOL));
g_return_if_fail (tool_options_type == G_TYPE_NONE ||
g_type_is_a (tool_options_type, PIKA_TYPE_TOOL_OPTIONS));
if (tool_options_type == G_TYPE_NONE)
tool_options_type = PIKA_TYPE_TOOL_OPTIONS;
if (tool_type == PIKA_TYPE_PENCIL_TOOL)
{
paint_core_name = "pika-pencil";
}
else if (tool_type == PIKA_TYPE_PAINTBRUSH_TOOL)
{
paint_core_name = "pika-paintbrush";
}
else if (tool_type == PIKA_TYPE_ERASER_TOOL)
{
paint_core_name = "pika-eraser";
}
else if (tool_type == PIKA_TYPE_AIRBRUSH_TOOL)
{
paint_core_name = "pika-airbrush";
}
else if (tool_type == PIKA_TYPE_CLONE_TOOL)
{
paint_core_name = "pika-clone";
}
else if (tool_type == PIKA_TYPE_HEAL_TOOL)
{
paint_core_name = "pika-heal";
}
else if (tool_type == PIKA_TYPE_PERSPECTIVE_CLONE_TOOL)
{
paint_core_name = "pika-perspective-clone";
}
else if (tool_type == PIKA_TYPE_CONVOLVE_TOOL)
{
paint_core_name = "pika-convolve";
}
else if (tool_type == PIKA_TYPE_SMUDGE_TOOL)
{
paint_core_name = "pika-smudge";
}
else if (tool_type == PIKA_TYPE_DODGE_BURN_TOOL)
{
paint_core_name = "pika-dodge-burn";
}
else if (tool_type == PIKA_TYPE_INK_TOOL)
{
paint_core_name = "pika-ink";
}
else if (tool_type == PIKA_TYPE_MYBRUSH_TOOL)
{
paint_core_name = "pika-mybrush";
}
else
{
paint_core_name = "pika-paintbrush";
}
tool_info = pika_tool_info_new (pika,
tool_type,
tool_options_type,
context_props,
identifier,
label,
tooltip,
menu_label,
menu_accel,
help_domain,
help_data,
paint_core_name,
icon_name);
visible = (! g_type_is_a (tool_type, PIKA_TYPE_FILTER_TOOL));
pika_tool_item_set_visible (PIKA_TOOL_ITEM (tool_info), visible);
/* hack to hide the operation tool entirely */
if (tool_type == PIKA_TYPE_OPERATION_TOOL)
tool_info->hidden = TRUE;
/* hack to not require experimental tools to be present in toolrc */
if (tool_type == PIKA_TYPE_N_POINT_DEFORMATION_TOOL ||
tool_type == PIKA_TYPE_SEAMLESS_CLONE_TOOL ||
tool_type == PIKA_TYPE_PAINT_SELECT_TOOL)
{
tool_info->experimental = TRUE;
}
g_object_set_data (G_OBJECT (tool_info), "pika-tool-options-gui-func",
options_gui_func);
pika_container_add (pika->tool_info_list, PIKA_OBJECT (tool_info));
g_object_unref (tool_info);
if (tool_type == PIKA_TYPE_PAINTBRUSH_TOOL)
pika_tool_info_set_standard (pika, tool_info);
}
static void
pika_tools_copy_structure (Pika *pika,
PikaContainer *src_container,
PikaContainer *dest_container,
GHashTable *tools)
{
GList *list;
for (list = PIKA_LIST (src_container)->queue->head;
list;
list = g_list_next (list))
{
PikaToolItem *src_tool_item = list->data;
PikaToolItem *dest_tool_item = NULL;
if (PIKA_IS_TOOL_GROUP (src_tool_item))
{
dest_tool_item = PIKA_TOOL_ITEM (pika_tool_group_new ());
pika_tools_copy_structure (
pika,
pika_viewable_get_children (PIKA_VIEWABLE (src_tool_item)),
pika_viewable_get_children (PIKA_VIEWABLE (dest_tool_item)),
tools);
pika_tool_group_set_active_tool (
PIKA_TOOL_GROUP (dest_tool_item),
pika_tool_group_get_active_tool (PIKA_TOOL_GROUP (src_tool_item)));
}
else
{
dest_tool_item = PIKA_TOOL_ITEM (
pika_get_tool_info (pika, pika_object_get_name (src_tool_item)));
if (dest_tool_item)
{
if (! PIKA_TOOL_INFO (dest_tool_item)->hidden)
{
g_object_ref (dest_tool_item);
if (tools)
g_hash_table_add (tools, dest_tool_item);
}
else
{
dest_tool_item = NULL;
}
}
}
if (dest_tool_item)
{
pika_tool_item_set_visible (
dest_tool_item,
pika_tool_item_get_visible (src_tool_item));
pika_container_add (dest_container,
PIKA_OBJECT (dest_tool_item));
g_object_unref (dest_tool_item);
}
}
}

49
app/tools/pika-tools.h Normal file
View File

@ -0,0 +1,49 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_TOOLS_H__
#define __PIKA_TOOLS_H__
void pika_tools_init (Pika *pika);
void pika_tools_exit (Pika *pika);
void pika_tools_restore (Pika *pika);
void pika_tools_save (Pika *pika,
gboolean save_tool_options,
gboolean always_save);
gboolean pika_tools_clear (Pika *pika,
GError **error);
gboolean pika_tools_serialize (Pika *pika,
PikaContainer *container,
PikaConfigWriter *writer);
gboolean pika_tools_deserialize (Pika *pika,
PikaContainer *container,
GScanner *scanner);
void pika_tools_reset (Pika *pika,
PikaContainer *container,
gboolean user_toolrc);
#endif /* __PIKA_TOOLS_H__ */

View File

@ -0,0 +1,151 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "paint/pikaairbrush.h"
#include "paint/pikaairbrushoptions.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikapropwidgets.h"
#include "pikaairbrushtool.h"
#include "pikapaintoptions-gui.h"
#include "pikapainttool-paint.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static void pika_airbrush_tool_constructed (GObject *object);
static void pika_airbrush_tool_airbrush_stamp (PikaAirbrush *airbrush,
PikaAirbrushTool *airbrush_tool);
static void pika_airbrush_tool_stamp (PikaAirbrushTool *airbrush_tool,
gpointer data);
static GtkWidget * pika_airbrush_options_gui (PikaToolOptions *tool_options);
G_DEFINE_TYPE (PikaAirbrushTool, pika_airbrush_tool, PIKA_TYPE_PAINTBRUSH_TOOL)
#define parent_class pika_airbrush_tool_parent_class
void
pika_airbrush_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_AIRBRUSH_TOOL,
PIKA_TYPE_AIRBRUSH_OPTIONS,
pika_airbrush_options_gui,
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
PIKA_CONTEXT_PROP_MASK_GRADIENT,
"pika-airbrush-tool",
_("Airbrush"),
_("Airbrush Tool: Paint using a brush, with variable pressure"),
N_("_Airbrush"), "A",
NULL, PIKA_HELP_TOOL_AIRBRUSH,
PIKA_ICON_TOOL_AIRBRUSH,
data);
}
static void
pika_airbrush_tool_class_init (PikaAirbrushToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_airbrush_tool_constructed;
}
static void
pika_airbrush_tool_init (PikaAirbrushTool *airbrush)
{
PikaTool *tool = PIKA_TOOL (airbrush);
pika_tool_control_set_tool_cursor (tool->control, PIKA_TOOL_CURSOR_AIRBRUSH);
}
static void
pika_airbrush_tool_constructed (GObject *object)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
g_signal_connect_object (paint_tool->core, "stamp",
G_CALLBACK (pika_airbrush_tool_airbrush_stamp),
object, 0);
}
static void
pika_airbrush_tool_airbrush_stamp (PikaAirbrush *airbrush,
PikaAirbrushTool *airbrush_tool)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (airbrush_tool);
pika_paint_tool_paint_push (
paint_tool,
(PikaPaintToolPaintFunc) pika_airbrush_tool_stamp,
NULL);
}
static void
pika_airbrush_tool_stamp (PikaAirbrushTool *airbrush_tool,
gpointer data)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (airbrush_tool);
pika_airbrush_stamp (PIKA_AIRBRUSH (paint_tool->core));
}
/* tool options stuff */
static GtkWidget *
pika_airbrush_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *button;
GtkWidget *scale;
button = pika_prop_check_button_new (config, "motion-only", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
scale = pika_prop_spin_scale_new (config, "rate",
1.0, 10.0, 1);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
scale = pika_prop_spin_scale_new (config, "flow",
1.0, 10.0, 1);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
return vbox;
}

View File

@ -0,0 +1,57 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_AIRBRUSH_TOOL_H__
#define __PIKA_AIRBRUSH_TOOL_H__
#include "pikapaintbrushtool.h"
#define PIKA_TYPE_AIRBRUSH_TOOL (pika_airbrush_tool_get_type ())
#define PIKA_AIRBRUSH_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_AIRBRUSH_TOOL, PikaAirbrushTool))
#define PIKA_AIRBRUSH_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_AIRBRUSH_TOOL, PikaAirbrushToolClass))
#define PIKA_IS_AIRBRUSH_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_AIRBRUSH_TOOL))
#define PIKA_IS_AIRBRUSH_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_AIRBRUSH_TOOL))
#define PIKA_AIRBRUSH_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_AIRBRUSH_TOOL, PikaAirbrushToolClass))
typedef struct _PikaAirbrushTool PikaAirbrushTool;
typedef struct _PikaAirbrushToolClass PikaAirbrushToolClass;
struct _PikaAirbrushTool
{
PikaPaintbrushTool parent_instance;
};
struct _PikaAirbrushToolClass
{
PikaPaintbrushToolClass parent_class;
};
void pika_airbrush_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_airbrush_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_AIRBRUSH_TOOL_H__ */

View File

@ -0,0 +1,888 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikaguide.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikachannel.h"
#include "vectors/pikavectors.h"
#include "widgets/pikapivotselector.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-utils.h"
#include "pikaalignoptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
#define ALIGN_VER_N_BUTTONS 3
#define ALIGN_HOR_N_BUTTONS 3
#define DISTR_VER_N_BUTTONS 2
#define DISTR_HOR_N_BUTTONS 2
enum
{
ALIGN_BUTTON_CLICKED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_ALIGN_REFERENCE,
PROP_ALIGN_LAYERS,
PROP_ALIGN_VECTORS,
PROP_ALIGN_CONTENTS,
PROP_PIVOT_X,
PROP_PIVOT_Y,
};
struct _PikaAlignOptionsPrivate
{
gboolean align_layers;
gboolean align_vectors;
gboolean align_contents;
gdouble pivot_x;
gdouble pivot_y;
GList *selected_guides;
GObject *reference;
GtkWidget *selected_guides_label;
GtkWidget *reference_combo;
GtkWidget *reference_box;
GtkWidget *reference_label;
GtkWidget *pivot_selector;
GtkWidget *align_ver_button[ALIGN_VER_N_BUTTONS];
GtkWidget *align_hor_button[ALIGN_HOR_N_BUTTONS];
GtkWidget *distr_ver_button[DISTR_VER_N_BUTTONS];
GtkWidget *distr_hor_button[DISTR_HOR_N_BUTTONS];
};
static void pika_align_options_finalize (GObject *object);
static void pika_align_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_align_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_align_options_image_changed (PikaContext *context,
PikaImage *image,
PikaAlignOptions *options);
static void pika_align_options_update_area (PikaAlignOptions *options);
static void pika_align_options_guide_removed (PikaImage *image,
PikaGuide *guide,
PikaAlignOptions *options);
static void pika_align_options_reference_removed (GObject *object,
PikaAlignOptions *options);
static void pika_align_options_pivot_changed (PikaPivotSelector *selector,
PikaAlignOptions *options);
G_DEFINE_TYPE_WITH_PRIVATE (PikaAlignOptions, pika_align_options, PIKA_TYPE_TOOL_OPTIONS)
#define parent_class pika_selection_options_parent_class
static guint align_options_signals[LAST_SIGNAL] = { 0 };
static void
pika_align_options_class_init (PikaAlignOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_align_options_finalize;
object_class->set_property = pika_align_options_set_property;
object_class->get_property = pika_align_options_get_property;
klass->align_button_clicked = NULL;
align_options_signals[ALIGN_BUTTON_CLICKED] =
g_signal_new ("align-button-clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaAlignOptionsClass,
align_button_clicked),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_ALIGNMENT_TYPE);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_ALIGN_REFERENCE,
"align-reference",
_("Relative to"),
_("Reference object targets will be aligned on"),
PIKA_TYPE_ALIGN_REFERENCE_TYPE,
PIKA_ALIGN_REFERENCE_IMAGE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_LAYERS,
"align-layers",
_("Selected layers"),
_("Selected layers will be aligned or distributed by the tool"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_VECTORS,
"align-vectors",
_("Selected paths"),
_("Selected paths will be aligned or distributed by the tool"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_CONTENTS,
"align-contents",
_("Use extents of layer contents"),
_("Instead of aligning or distributing on layer borders, use its content bounding box"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_PIVOT_X,
"pivot-x",
"X position of the point to align in objects",
NULL,
0.0, 1.0, 0.5,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_PIVOT_Y,
"pivot-y",
"Y position of the point to align in objects",
NULL,
0.0, 1.0, 0.5,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_align_options_init (PikaAlignOptions *options)
{
options->priv = pika_align_options_get_instance_private (options);
options->priv->selected_guides = NULL;
}
static void
pika_align_options_finalize (GObject *object)
{
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (object);
if (PIKA_CONTEXT (options)->pika)
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
NULL, options);
}
static void
pika_align_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (object);
switch (property_id)
{
case PROP_ALIGN_REFERENCE:
options->align_reference = g_value_get_enum (value);
pika_align_options_update_area (options);
break;
case PROP_ALIGN_LAYERS:
options->priv->align_layers = g_value_get_boolean (value);
pika_align_options_update_area (options);
break;
case PROP_ALIGN_VECTORS:
options->priv->align_vectors = g_value_get_boolean (value);
pika_align_options_update_area (options);
break;
case PROP_ALIGN_CONTENTS:
options->priv->align_contents = g_value_get_boolean (value);
break;
case PROP_PIVOT_X:
options->priv->pivot_x = g_value_get_double (value);
break;
case PROP_PIVOT_Y:
options->priv->pivot_y = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_align_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (object);
switch (property_id)
{
case PROP_ALIGN_REFERENCE:
g_value_set_enum (value, options->align_reference);
break;
case PROP_ALIGN_LAYERS:
g_value_set_boolean (value, options->priv->align_layers);
break;
case PROP_ALIGN_VECTORS:
g_value_set_boolean (value, options->priv->align_vectors);
break;
case PROP_ALIGN_CONTENTS:
g_value_set_boolean (value, options->priv->align_contents);
break;
case PROP_PIVOT_X:
g_value_set_double (value, options->priv->pivot_x);
break;
case PROP_PIVOT_Y:
g_value_set_double (value, options->priv->pivot_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_align_options_button_clicked (GtkButton *button,
PikaAlignOptions *options)
{
PikaAlignmentType action;
action = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
"align-action"));
g_signal_emit (options, align_options_signals[ALIGN_BUTTON_CLICKED], 0,
action);
}
static GtkWidget *
pika_align_options_button_new (PikaAlignOptions *options,
PikaAlignmentType action,
GtkWidget *parent,
const gchar *tooltip)
{
GtkWidget *button;
GtkWidget *image;
const gchar *icon_name = NULL;
switch (action)
{
case PIKA_ALIGN_LEFT:
icon_name = PIKA_ICON_GRAVITY_WEST;
break;
case PIKA_ALIGN_HCENTER:
icon_name = PIKA_ICON_CENTER_HORIZONTAL;
break;
case PIKA_ALIGN_RIGHT:
icon_name = PIKA_ICON_GRAVITY_EAST;
break;
case PIKA_ALIGN_TOP:
icon_name = PIKA_ICON_GRAVITY_NORTH;
break;
case PIKA_ALIGN_VCENTER:
icon_name = PIKA_ICON_CENTER_VERTICAL;
break;
case PIKA_ALIGN_BOTTOM:
icon_name = PIKA_ICON_GRAVITY_SOUTH;
break;
case PIKA_ARRANGE_HFILL:
icon_name = PIKA_ICON_FILL_HORIZONTAL;
break;
case PIKA_ARRANGE_VFILL:
icon_name = PIKA_ICON_FILL_VERTICAL;
break;
case PIKA_DISTRIBUTE_EVEN_HORIZONTAL_GAP:
icon_name = PIKA_ICON_EVEN_HORIZONTAL_GAP;
break;
case PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP:
icon_name = PIKA_ICON_EVEN_VERTICAL_GAP;
break;
default:
g_return_val_if_reached (NULL);
break;
}
button = gtk_button_new ();
gtk_widget_set_sensitive (button, FALSE);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
gtk_box_pack_start (GTK_BOX (parent), button, FALSE, FALSE, 0);
gtk_widget_show (button);
pika_help_set_help_data (button, tooltip, NULL);
g_object_set_data (G_OBJECT (button), "align-action",
GINT_TO_POINTER (action));
g_signal_connect (button, "clicked",
G_CALLBACK (pika_align_options_button_clicked),
options);
return button;
}
GtkWidget *
pika_align_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
PikaAlignOptions *options = PIKA_ALIGN_OPTIONS (tool_options);
GtkWidget *vbox = pika_tool_options_gui (tool_options);
GtkWidget *widget;
GtkWidget *section_vbox;
GtkWidget *items_grid;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *combo;
gchar *text;
gint n = 0;
/* Selected objects */
frame = pika_frame_new (_("Targets"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), section_vbox);
gtk_widget_show (section_vbox);
items_grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (section_vbox), items_grid);
gtk_widget_show (items_grid);
widget = pika_prop_check_button_new (config, "align-contents", NULL);
widget = pika_prop_expanding_frame_new (config, "align-layers",
NULL, widget, NULL);
gtk_grid_attach (GTK_GRID (items_grid), widget, 0, 0, 1, 1);
widget = pika_prop_check_button_new (config, "align-vectors", NULL);
gtk_grid_attach (GTK_GRID (items_grid), widget, 0, 1, 1, 1);
options->priv->pivot_selector = pika_pivot_selector_new (0.0, 0.0, 1.0, 1.0);
gtk_widget_set_tooltip_text (options->priv->pivot_selector,
_("Set anchor point of targets"));
pika_pivot_selector_set_position (PIKA_PIVOT_SELECTOR (options->priv->pivot_selector),
options->priv->pivot_x, options->priv->pivot_y);
gtk_grid_attach (GTK_GRID (items_grid), options->priv->pivot_selector, 1, 0, 1, 2);
gtk_widget_show (options->priv->pivot_selector);
g_signal_connect (options->priv->pivot_selector, "changed",
G_CALLBACK (pika_align_options_pivot_changed),
options);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
widget = gtk_image_new_from_icon_name (PIKA_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
/* TRANSLATORS: the %s strings are modifiers such as Shift, Alt or Cmd. */
text = g_strdup_printf (_("%s-pick target guides (%s-%s to add more)"),
pika_get_mod_string (GDK_MOD1_MASK),
pika_get_mod_string (pika_get_extend_selection_mask ()),
pika_get_mod_string (GDK_MOD1_MASK));
widget = gtk_label_new (text);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
g_free (text);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (section_vbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
options->priv->selected_guides_label = widget;
/* Align frame */
frame = pika_frame_new (_("Align"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), section_vbox);
gtk_widget_show (section_vbox);
/* Align frame: reference */
combo = pika_prop_enum_combo_box_new (config, "align-reference", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Relative to"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (section_vbox), combo, FALSE, FALSE, 0);
options->priv->reference_combo = combo;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
options->priv->reference_box = hbox;
widget = gtk_image_new_from_icon_name (PIKA_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (_("Select the reference object"));
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (section_vbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
options->priv->reference_label = widget;
/* Align frame: buttons */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->align_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_LEFT, hbox,
_("Align anchor points of targets on left edge of reference"));
options->priv->align_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_HCENTER, hbox,
_("Align anchor points of targets on vertical middle of reference"));
options->priv->align_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_RIGHT, hbox,
_("Align anchor points of targets on right edge of reference"));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->align_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_TOP, hbox,
_("Align anchor points of targets on top edge of reference"));
options->priv->align_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_VCENTER, hbox,
_("Align anchor points of targets on horizontal middle of reference"));
options->priv->align_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ALIGN_BOTTOM, hbox,
_("Align anchor points of targets on bottom of reference"));
/* Distribute frame */
frame = pika_frame_new (_("Distribute"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
section_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (frame), section_vbox);
gtk_widget_show (section_vbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->distr_ver_button[n++] =
pika_align_options_button_new (options, PIKA_ARRANGE_HFILL, hbox,
_("Distribute anchor points of targets evenly in the horizontal"));
options->priv->distr_ver_button[n++] =
pika_align_options_button_new (options, PIKA_DISTRIBUTE_EVEN_HORIZONTAL_GAP, hbox,
_("Distribute horizontally with even horizontal gaps"));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (section_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
n = 0;
options->priv->distr_hor_button[n++] =
pika_align_options_button_new (options, PIKA_ARRANGE_VFILL, hbox,
_("Distribute anchor points of targets evenly in the vertical"));
options->priv->distr_hor_button[n++] =
pika_align_options_button_new (options, PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP, hbox,
_("Distribute vertically with even vertical gaps"));
g_signal_connect (pika_get_user_context (PIKA_CONTEXT (options)->pika),
"image-changed",
G_CALLBACK (pika_align_options_image_changed),
tool_options);
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika)),
options);
return vbox;
}
GList *
pika_align_options_get_objects (PikaAlignOptions *options)
{
PikaImage *image;
GList *objects = NULL;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
if (image)
{
if (options->priv->align_layers)
{
GList *layers;
layers = pika_image_get_selected_layers (image);
layers = g_list_copy (layers);
objects = g_list_concat (objects, layers);
}
if (options->priv->align_vectors)
{
GList *vectors;
vectors = pika_image_get_selected_vectors (image);
vectors = g_list_copy (vectors);
objects = g_list_concat (objects, vectors);
}
if (options->priv->selected_guides)
{
GList *guides;
guides = g_list_copy (options->priv->selected_guides);
objects = g_list_concat (objects, guides);
}
}
return objects;
}
void
pika_align_options_get_pivot (PikaAlignOptions *options,
gdouble *x,
gdouble *y)
{
pika_pivot_selector_get_position (PIKA_PIVOT_SELECTOR (options->priv->pivot_selector),
x, y);
}
void
pika_align_options_pick_reference (PikaAlignOptions *options,
GObject *object)
{
if (options->priv->reference)
g_signal_handlers_disconnect_by_func (options->priv->reference,
G_CALLBACK (pika_align_options_reference_removed),
options);
g_clear_object (&options->priv->reference);
if (object)
{
options->priv->reference = g_object_ref (object);
/* Both PikaItem and PikaGuide/PikaAuxItem have a "removed" signal with
* similar signature. */
g_signal_connect_object (options->priv->reference,
"removed",
G_CALLBACK (pika_align_options_reference_removed),
options, 0);
}
pika_align_options_update_area (options);
}
GObject *
pika_align_options_get_reference (PikaAlignOptions *options,
gboolean blink_if_none)
{
GObject *reference = NULL;
PikaImage *image;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
if (image)
{
switch (options->align_reference)
{
case PIKA_ALIGN_REFERENCE_IMAGE:
reference = G_OBJECT (image);
break;
case PIKA_ALIGN_REFERENCE_SELECTION:
reference = G_OBJECT (pika_image_get_mask (image));
break;
case PIKA_ALIGN_REFERENCE_PICK:
reference = G_OBJECT (options->priv->reference);
break;
}
if (reference == NULL && blink_if_none)
{
if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
pika_widget_blink (options->priv->reference_box);
else
pika_widget_blink (options->priv->reference_combo);
}
}
return reference;
}
gboolean
pika_align_options_align_contents (PikaAlignOptions *options)
{
return options->priv->align_contents;
}
void
pika_align_options_pick_guide (PikaAlignOptions *options,
PikaGuide *guide,
gboolean extend)
{
if (! extend)
g_clear_pointer (&options->priv->selected_guides, g_list_free);
if (guide)
{
GList *list;
if ((list = g_list_find (options->priv->selected_guides, guide)))
options->priv->selected_guides = g_list_delete_link (options->priv->selected_guides, list);
else
options->priv->selected_guides = g_list_prepend (options->priv->selected_guides, guide);
}
pika_align_options_update_area (options);
}
/* Private functions */
static void
pika_align_options_image_changed (PikaContext *context,
PikaImage *image,
PikaAlignOptions *options)
{
PikaImage *prev_image;
prev_image = g_object_get_data (G_OBJECT (options), "pika-align-options-image");
if (image != prev_image)
{
/* We cannot keep track of selected guides across image changes. */
g_clear_pointer (&options->priv->selected_guides, g_list_free);
pika_align_options_pick_reference (options, NULL);
if (prev_image)
{
g_signal_handlers_disconnect_by_func (prev_image,
G_CALLBACK (pika_align_options_update_area),
options);
g_signal_handlers_disconnect_by_func (prev_image,
G_CALLBACK (pika_align_options_guide_removed),
options);
}
if (image)
{
g_signal_connect_object (image, "selected-channels-changed",
G_CALLBACK (pika_align_options_update_area),
options, G_CONNECT_SWAPPED);
g_signal_connect_object (image, "selected-layers-changed",
G_CALLBACK (pika_align_options_update_area),
options, G_CONNECT_SWAPPED);
g_signal_connect_object (image, "guide-removed",
G_CALLBACK (pika_align_options_guide_removed),
options, 0);
}
g_object_set_data (G_OBJECT (options), "pika-align-options-image", image);
pika_align_options_update_area (options);
}
}
static void
pika_align_options_update_area (PikaAlignOptions *options)
{
PikaImage *image;
GList *layers = NULL;
GList *vectors = NULL;
gboolean enable_ver_align = FALSE;
gboolean enable_hor_align = FALSE;
gboolean enable_ver_distr = FALSE;
gboolean enable_hor_distr = FALSE;
gint n_items = 0;
gchar *text;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
/* GUI not created yet. */
if (! options->priv->reference_combo)
return;
if (image)
{
layers = pika_image_get_selected_layers (image);
vectors = pika_image_get_selected_vectors (image);
if (options->priv->align_layers)
n_items += g_list_length (layers);
if (options->priv->align_vectors)
n_items += g_list_length (vectors);
n_items += g_list_length (options->priv->selected_guides);
}
if (n_items > 0)
{
GObject *reference;
reference = pika_align_options_get_reference (options, FALSE);
enable_ver_align = (reference != NULL &&
(! PIKA_IS_GUIDE (reference) ||
pika_guide_get_orientation (PIKA_GUIDE (reference)) == PIKA_ORIENTATION_VERTICAL));
enable_hor_align = (reference != NULL &&
(! PIKA_IS_GUIDE (reference) ||
pika_guide_get_orientation (PIKA_GUIDE (reference)) == PIKA_ORIENTATION_HORIZONTAL));
enable_ver_distr = enable_hor_distr = (n_items > 2);
}
for (gint i = 0; i < ALIGN_VER_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->align_ver_button[i], enable_ver_align);
for (gint i = 0; i < ALIGN_HOR_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->align_hor_button[i], enable_hor_align);
for (gint i = 0; i < DISTR_VER_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->distr_ver_button[i], enable_ver_distr);
for (gint i = 0; i < DISTR_HOR_N_BUTTONS; i++)
gtk_widget_set_sensitive (options->priv->distr_hor_button[i], enable_hor_distr);
/* Update the guide picking widgets. */
if (options->priv->selected_guides)
{
gchar *tmp_txt;
tmp_txt = g_strdup_printf (ngettext ("1 guide will be aligned or distributed",
"%d guides will be aligned or distributed",
g_list_length (options->priv->selected_guides)),
g_list_length (options->priv->selected_guides));
text = g_strdup_printf ("<i>%s</i>", tmp_txt);
g_free (tmp_txt);
gtk_widget_show (options->priv->selected_guides_label);
}
else
{
text = NULL;
gtk_widget_hide (options->priv->selected_guides_label);
}
gtk_label_set_markup (GTK_LABEL (options->priv->selected_guides_label), text);
g_free (text);
/* Update the reference widgets. */
text = NULL;
if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
{
if (options->priv->reference)
{
gchar *tmp_txt;
if (PIKA_IS_LAYER (options->priv->reference))
tmp_txt = g_strdup_printf (_("Reference layer: %s"),
pika_object_get_name (options->priv->reference));
else if (PIKA_IS_CHANNEL (options->priv->reference))
tmp_txt = g_strdup_printf (_("Reference channel: %s"),
pika_object_get_name (options->priv->reference));
else if (PIKA_IS_VECTORS (options->priv->reference))
tmp_txt = g_strdup_printf (_("Reference path: %s"),
pika_object_get_name (options->priv->reference));
else if (PIKA_IS_GUIDE (options->priv->reference))
tmp_txt = g_strdup (_("Reference guide"));
else
g_return_if_reached ();
text = g_strdup_printf ("<i>%s</i>", tmp_txt);
g_free (tmp_txt);
}
gtk_widget_show (options->priv->reference_box);
}
else
{
gtk_widget_hide (options->priv->reference_box);
}
gtk_label_set_markup (GTK_LABEL (options->priv->reference_label), text);
g_free (text);
}
static void
pika_align_options_guide_removed (PikaImage *image,
PikaGuide *guide,
PikaAlignOptions *options)
{
GList *list;
if ((list = g_list_find (options->priv->selected_guides, guide)))
options->priv->selected_guides = g_list_delete_link (options->priv->selected_guides, list);
if (G_OBJECT (guide) == options->priv->reference)
pika_align_options_pick_reference (options, NULL);
pika_align_options_update_area (options);
}
static void
pika_align_options_reference_removed (GObject *object,
PikaAlignOptions *options)
{
if (G_OBJECT (object) == options->priv->reference)
pika_align_options_pick_reference (options, NULL);
}
static void
pika_align_options_pivot_changed (PikaPivotSelector *selector,
PikaAlignOptions *options)
{
gdouble x;
gdouble y;
pika_pivot_selector_get_position (selector, &x, &y);
g_object_set (options,
"pivot-x", x,
"pivot-y", y,
NULL);
}

View File

@ -0,0 +1,79 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_ALIGN_OPTIONS_H__
#define __PIKA_ALIGN_OPTIONS_H__
#include "core/pikatooloptions.h"
#define PIKA_TYPE_ALIGN_OPTIONS (pika_align_options_get_type ())
#define PIKA_ALIGN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ALIGN_OPTIONS, PikaAlignOptions))
#define PIKA_ALIGN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ALIGN_OPTIONS, PikaAlignOptionsClass))
#define PIKA_IS_ALIGN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ALIGN_OPTIONS))
#define PIKA_IS_ALIGN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ALIGN_OPTIONS))
#define PIKA_ALIGN_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ALIGN_OPTIONS, PikaAlignOptionsClass))
typedef struct _PikaAlignOptions PikaAlignOptions;
typedef struct _PikaAlignOptionsPrivate PikaAlignOptionsPrivate;
typedef struct _PikaAlignOptionsClass PikaAlignOptionsClass;
struct _PikaAlignOptions
{
PikaToolOptions parent_instance;
PikaAlignReferenceType align_reference;
PikaAlignOptionsPrivate *priv;
};
struct _PikaAlignOptionsClass
{
PikaToolOptionsClass parent_class;
void (* align_button_clicked) (PikaAlignOptions *options,
PikaAlignmentType align_type);
};
GType pika_align_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_align_options_gui (PikaToolOptions *tool_options);
GList * pika_align_options_get_objects (PikaAlignOptions *options);
void pika_align_options_get_pivot (PikaAlignOptions *options,
gdouble *x,
gdouble *y);
void pika_align_options_pick_reference (PikaAlignOptions *options,
GObject *object);
GObject * pika_align_options_get_reference (PikaAlignOptions *options,
gboolean blink_if_none);
gboolean pika_align_options_align_contents (PikaAlignOptions *options);
void pika_align_options_pick_guide (PikaAlignOptions *options,
PikaGuide *guide,
gboolean extend);
#endif /* __PIKA_ALIGN_OPTIONS_H__ */

859
app/tools/pikaaligntool.c Normal file
View File

@ -0,0 +1,859 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "config/pikadisplayconfig.h"
#include "core/pika.h"
#include "core/pikaguide.h"
#include "core/pikaimage.h"
#include "core/pikaimage-arrange.h"
#include "core/pikaimage-pick-item.h"
#include "core/pikaimage-undo.h"
#include "core/pikalayer.h"
#include "core/pikapickable.h"
#include "core/pikapickable-auto-shrink.h"
#include "vectors/pikavectors.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"
#include "display/pikacanvasitem.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikadisplayshell-appearance.h"
#include "pikaalignoptions.h"
#include "pikaaligntool.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
#define EPSILON 3 /* move distance after which we do a box-select */
/* local function prototypes */
static void pika_align_tool_constructed (GObject *object);
static void pika_align_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display);
static void pika_align_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display);
static void pika_align_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display);
static void pika_align_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display);
static gboolean pika_align_tool_key_press (PikaTool *tool,
GdkEventKey *kevent,
PikaDisplay *display);
static void pika_align_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_align_tool_status_update (PikaTool *tool,
PikaDisplay *display,
GdkModifierType state,
gboolean proximity);
static void pika_align_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
const gchar * pika_align_tool_can_undo (PikaTool *tool,
PikaDisplay *display);
static gboolean pika_align_tool_undo (PikaTool *tool,
PikaDisplay *display);
static void pika_align_tool_draw (PikaDrawTool *draw_tool);
static void pika_align_tool_redraw (PikaAlignTool *align_tool);
static void pika_align_tool_align (PikaAlignTool *align_tool,
PikaAlignmentType align_type);
static gint pika_align_tool_undo_idle (gpointer data);
static void pika_align_tool_display_changed (PikaContext *context,
PikaDisplay *display,
PikaAlignTool *align_tool);
G_DEFINE_TYPE (PikaAlignTool, pika_align_tool, PIKA_TYPE_DRAW_TOOL)
#define parent_class pika_align_tool_parent_class
void
pika_align_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_ALIGN_TOOL,
PIKA_TYPE_ALIGN_OPTIONS,
pika_align_options_gui,
0,
"pika-align-tool",
_("Align and Distribute"),
_("Alignment Tool: Align or arrange layers and other objects"),
N_("_Align and Distribute"), "Q",
NULL, PIKA_HELP_TOOL_ALIGN,
PIKA_ICON_TOOL_ALIGN,
data);
}
static void
pika_align_tool_class_init (PikaAlignToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaDrawToolClass *draw_tool_class = PIKA_DRAW_TOOL_CLASS (klass);
object_class->constructed = pika_align_tool_constructed;
tool_class->control = pika_align_tool_control;
tool_class->button_press = pika_align_tool_button_press;
tool_class->button_release = pika_align_tool_button_release;
tool_class->motion = pika_align_tool_motion;
tool_class->key_press = pika_align_tool_key_press;
tool_class->oper_update = pika_align_tool_oper_update;
tool_class->cursor_update = pika_align_tool_cursor_update;
tool_class->can_undo = pika_align_tool_can_undo;
tool_class->undo = pika_align_tool_undo;
draw_tool_class->draw = pika_align_tool_draw;
}
static void
pika_align_tool_init (PikaAlignTool *align_tool)
{
PikaTool *tool = PIKA_TOOL (align_tool);
pika_tool_control_set_snap_to (tool->control, FALSE);
pika_tool_control_set_precision (tool->control,
PIKA_CURSOR_PRECISION_PIXEL_BORDER);
pika_tool_control_set_tool_cursor (tool->control, PIKA_TOOL_CURSOR_MOVE);
align_tool->function = ALIGN_TOOL_REF_IDLE;
}
static void
pika_align_tool_constructed (GObject *object)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (object);
PikaAlignOptions *options;
G_OBJECT_CLASS (parent_class)->constructed (object);
options = PIKA_ALIGN_TOOL_GET_OPTIONS (align_tool);
g_signal_connect_object (options, "align-button-clicked",
G_CALLBACK (pika_align_tool_align),
align_tool, G_CONNECT_SWAPPED);
g_signal_connect_object (options, "notify::align-reference",
G_CALLBACK (pika_align_tool_redraw),
align_tool, G_CONNECT_SWAPPED);
g_signal_connect_object (options, "notify::align-contents",
G_CALLBACK (pika_align_tool_redraw),
align_tool, G_CONNECT_SWAPPED);
g_signal_connect_object (pika_get_user_context (PIKA_CONTEXT (options)->pika),
"display-changed",
G_CALLBACK (pika_align_tool_display_changed),
align_tool, 0);
}
static void
pika_align_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display)
{
switch (action)
{
case PIKA_TOOL_ACTION_PAUSE:
case PIKA_TOOL_ACTION_RESUME:
break;
case PIKA_TOOL_ACTION_HALT:
break;
case PIKA_TOOL_ACTION_COMMIT:
break;
}
PIKA_TOOL_CLASS (parent_class)->control (tool, action, display);
}
static void
pika_align_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (tool);
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
/* If the tool was being used in another image... reset it */
if (display != tool->display)
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, display);
tool->display = display;
pika_tool_control_activate (tool->control);
align_tool->x2 = align_tool->x1 = coords->x;
align_tool->y2 = align_tool->y1 = coords->y;
if (! pika_draw_tool_is_active (PIKA_DRAW_TOOL (tool)))
pika_draw_tool_start (PIKA_DRAW_TOOL (tool), display);
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
}
/* some rather complex logic here. If the user clicks without modifiers,
* then we start a new list, and use the first object in it as reference.
* If the user clicks using Shift, or draws a rubber-band box, then
* we add objects to the list, but do not specify which one should
* be used as reference.
*/
static void
pika_align_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (tool);
PikaAlignOptions *options = PIKA_ALIGN_TOOL_GET_OPTIONS (tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
GdkModifierType extend_mask;
extend_mask = pika_get_extend_selection_mask ();
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
pika_tool_control_halt (tool->control);
if (release_type == PIKA_BUTTON_RELEASE_CANCEL)
{
align_tool->x2 = align_tool->x1;
align_tool->y2 = align_tool->y1;
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
return;
}
if (state & GDK_MOD1_MASK)
{
PikaGuide *guide = NULL;
if (pika_display_shell_get_show_guides (shell))
{
gint snap_distance = display->config->snap_distance;
guide = pika_image_pick_guide (image,
coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance));
}
pika_align_options_pick_guide (options, guide, (gboolean) state & extend_mask);
}
else
{
GObject *object = NULL;
/* Check if a layer is fully included in the rubber-band rectangle.
* Don't verify for too small rectangles.
*/
/* FIXME: look for vectors too */
if (hypot (coords->x - align_tool->x1,
coords->y - align_tool->y1) > EPSILON)
{
gint X0 = MIN (coords->x, align_tool->x1);
gint X1 = MAX (coords->x, align_tool->x1);
gint Y0 = MIN (coords->y, align_tool->y1);
gint Y1 = MAX (coords->y, align_tool->y1);
GList *all_layers;
GList *list;
all_layers = pika_image_get_layer_list (image);
for (list = all_layers; list; list = g_list_next (list))
{
PikaLayer *layer = list->data;
gint x0, y0, x1, y1;
if (! pika_item_get_visible (PIKA_ITEM (layer)))
continue;
pika_item_get_offset (PIKA_ITEM (layer), &x0, &y0);
x1 = x0 + pika_item_get_width (PIKA_ITEM (layer));
y1 = y0 + pika_item_get_height (PIKA_ITEM (layer));
if (x0 < X0 || y0 < Y0 || x1 > X1 || y1 > Y1)
continue;
object = G_OBJECT (layer);
break;
}
g_list_free (all_layers);
}
if (object == NULL)
{
PikaVectors *vectors;
PikaGuide *guide;
PikaLayer *layer;
GObject *previously_picked;
gint snap_distance = display->config->snap_distance;
previously_picked = pika_align_options_get_reference (options, FALSE);
if ((vectors = pika_image_pick_vectors (image,
coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance))))
{
object = G_OBJECT (vectors);
}
else if (pika_display_shell_get_show_guides (shell) &&
(guide = pika_image_pick_guide (image,
coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance))))
{
object = G_OBJECT (guide);
}
else if ((layer = pika_image_pick_layer (image, coords->x, coords->y,
previously_picked && PIKA_IS_LAYER (previously_picked)? PIKA_LAYER (previously_picked) : NULL)))
{
object = G_OBJECT (layer);
}
}
if (object)
pika_align_options_pick_reference (options, object);
}
align_tool->x2 = align_tool->x1;
align_tool->y2 = align_tool->y1;
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
}
static void
pika_align_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (tool);
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
align_tool->x2 = coords->x;
align_tool->y2 = coords->y;
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
}
static gboolean
pika_align_tool_key_press (PikaTool *tool,
GdkEventKey *kevent,
PikaDisplay *display)
{
if (display == tool->display)
{
switch (kevent->keyval)
{
case GDK_KEY_Escape:
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, display);
return TRUE;
default:
break;
}
}
return FALSE;
}
static void
pika_align_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (tool);
PikaAlignOptions *options = PIKA_ALIGN_TOOL_GET_OPTIONS (align_tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
gint snap_distance = display->config->snap_distance;
state &= pika_get_all_modifiers_mask ();
align_tool->function = ALIGN_TOOL_NO_ACTION;
if (pika_image_pick_vectors (image,
coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance)))
{
if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
align_tool->function = ALIGN_TOOL_REF_PICK_PATH;
}
else if (pika_display_shell_get_show_guides (shell) &&
pika_image_pick_guide (image,
coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance)))
{
if (state == (pika_get_extend_selection_mask () | GDK_MOD1_MASK))
align_tool->function = ALIGN_TOOL_ALIGN_ADD_GUIDE;
else if (state == GDK_MOD1_MASK)
align_tool->function = ALIGN_TOOL_ALIGN_PICK_GUIDE;
else if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
align_tool->function = ALIGN_TOOL_REF_PICK_GUIDE;
}
else if (pika_image_pick_layer_by_bounds (image, coords->x, coords->y))
{
if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
align_tool->function = ALIGN_TOOL_REF_PICK_LAYER;
}
else
{
if (state & GDK_MOD1_MASK)
align_tool->function = ALIGN_TOOL_ALIGN_IDLE;
else if (options->align_reference == PIKA_ALIGN_REFERENCE_PICK)
align_tool->function = ALIGN_TOOL_REF_IDLE;
}
pika_align_tool_status_update (tool, display, state, proximity);
if (! pika_draw_tool_is_active (PIKA_DRAW_TOOL (tool)))
pika_draw_tool_start (PIKA_DRAW_TOOL (tool), display);
}
static void
pika_align_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (tool);
PikaToolCursorType tool_cursor = PIKA_TOOL_CURSOR_NONE;
PikaCursorModifier modifier = PIKA_CURSOR_MODIFIER_NONE;
switch (align_tool->function)
{
case ALIGN_TOOL_REF_IDLE:
case ALIGN_TOOL_ALIGN_IDLE:
tool_cursor = PIKA_TOOL_CURSOR_RECT_SELECT;
break;
case ALIGN_TOOL_REF_PICK_LAYER:
tool_cursor = PIKA_TOOL_CURSOR_HAND;
break;
case ALIGN_TOOL_ALIGN_ADD_GUIDE:
modifier = PIKA_CURSOR_MODIFIER_PLUS;
case ALIGN_TOOL_REF_PICK_GUIDE:
case ALIGN_TOOL_ALIGN_PICK_GUIDE:
tool_cursor = PIKA_TOOL_CURSOR_MOVE;
break;
case ALIGN_TOOL_REF_PICK_PATH:
tool_cursor = PIKA_TOOL_CURSOR_PATHS;
break;
case ALIGN_TOOL_REF_DRAG_BOX:
case ALIGN_TOOL_NO_ACTION:
break;
}
pika_tool_control_set_cursor (tool->control, PIKA_CURSOR_MOUSE);
pika_tool_control_set_tool_cursor (tool->control, tool_cursor);
pika_tool_control_set_cursor_modifier (tool->control, modifier);
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
const gchar *
pika_align_tool_can_undo (PikaTool *tool,
PikaDisplay *display)
{
return _("Arrange Objects");
}
static gboolean
pika_align_tool_undo (PikaTool *tool,
PikaDisplay *display)
{
g_idle_add ((GSourceFunc) pika_align_tool_undo_idle, (gpointer) tool);
return FALSE;
}
static void
pika_align_tool_status_update (PikaTool *tool,
PikaDisplay *display,
GdkModifierType state,
gboolean proximity)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (tool);
gchar *status = NULL;
GdkModifierType extend_mask;
extend_mask = pika_get_extend_selection_mask ();
pika_tool_pop_status (tool, display);
if (proximity)
{
switch (align_tool->function)
{
case ALIGN_TOOL_REF_IDLE:
status = g_strdup (_("Click on a layer, path or guide, "
"or Click-Drag to pick a reference"));
break;
case ALIGN_TOOL_REF_PICK_LAYER:
status = g_strdup (_("Click to pick this layer as reference"));
break;
case ALIGN_TOOL_REF_PICK_GUIDE:
status = pika_suggest_modifiers (_("Click to pick this guide as reference"),
GDK_MOD1_MASK & ~state,
NULL, NULL, NULL);
break;
case ALIGN_TOOL_REF_PICK_PATH:
status = g_strdup (_("Click to pick this path as reference"));
break;
case ALIGN_TOOL_REF_DRAG_BOX:
break;
case ALIGN_TOOL_ALIGN_IDLE:
status = g_strdup (_("Click on a guide to add it to objects to align, "
"click anywhere else to unselect all guides"));
break;
case ALIGN_TOOL_ALIGN_PICK_GUIDE:
status = pika_suggest_modifiers (_("Click to select this guide for alignment"),
extend_mask & ~state,
NULL, NULL, NULL);
break;
case ALIGN_TOOL_ALIGN_ADD_GUIDE:
status = g_strdup (_("Click to add this guide to the list of objects to align"));
break;
case ALIGN_TOOL_NO_ACTION:
break;
}
}
if (status)
{
pika_tool_push_status (tool, display, "%s", status);
g_free (status);
}
}
static void
pika_align_tool_draw (PikaDrawTool *draw_tool)
{
PikaAlignTool *align_tool = PIKA_ALIGN_TOOL (draw_tool);
PikaAlignOptions *options = PIKA_ALIGN_TOOL_GET_OPTIONS (align_tool);
GObject *reference;
GList *objects;
GList *iter;
gint x, y, w, h;
/* draw rubber-band rectangle */
x = MIN (align_tool->x2, align_tool->x1);
y = MIN (align_tool->y2, align_tool->y1);
w = MAX (align_tool->x2, align_tool->x1) - x;
h = MAX (align_tool->y2, align_tool->y1) - y;
if (w != 0 && h != 0)
pika_draw_tool_add_rectangle (draw_tool, FALSE, x, y, w, h);
/* Draw handles on the reference object. */
reference = pika_align_options_get_reference (options, FALSE);
if (PIKA_IS_ITEM (reference))
{
PikaItem *item = PIKA_ITEM (reference);
gint off_x, off_y;
pika_item_bounds (item, &x, &y, &w, &h);
pika_item_get_offset (item, &off_x, &off_y);
x += off_x;
y += off_y;
if (pika_align_options_align_contents (options))
{
gint shrunk_x;
gint shrunk_y;
if (pika_pickable_auto_shrink (PIKA_PICKABLE (reference),
0, 0,
pika_item_get_width (PIKA_ITEM (reference)),
pika_item_get_height (PIKA_ITEM (reference)),
&shrunk_x, &shrunk_y, &w, &h) == PIKA_AUTO_SHRINK_SHRINK)
{
x += shrunk_x;
y += shrunk_y;
}
}
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
x, y,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_NORTH_WEST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
x + w, y,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_NORTH_EAST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
x, y + h,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_SOUTH_WEST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
x + w, y + h,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_SOUTH_EAST);
}
else if (PIKA_IS_GUIDE (reference))
{
PikaGuide *guide = PIKA_GUIDE (reference);
PikaImage *image = pika_display_get_image (draw_tool->display);
gint x, y;
gint w, h;
switch (pika_guide_get_orientation (guide))
{
case PIKA_ORIENTATION_VERTICAL:
x = pika_guide_get_position (guide);
h = pika_image_get_height (image);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
x, h,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_SOUTH);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
x, 0,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_NORTH);
break;
case PIKA_ORIENTATION_HORIZONTAL:
y = pika_guide_get_position (guide);
w = pika_image_get_width (image);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
w, y,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_EAST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
0, y,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_WEST);
break;
default:
break;
}
}
else if (PIKA_IS_IMAGE (reference))
{
PikaImage *image = PIKA_IMAGE (reference);
gint width = pika_image_get_width (image);
gint height = pika_image_get_height (image);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
0, 0,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_NORTH_WEST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
width, 0,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_NORTH_EAST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
0, height,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_SOUTH_WEST);
pika_draw_tool_add_handle (draw_tool, PIKA_HANDLE_FILLED_SQUARE,
width, height,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_TOOL_HANDLE_SIZE_SMALL,
PIKA_HANDLE_ANCHOR_SOUTH_EAST);
}
/* Highlight picked guides, similarly to how they are highlighted in Move
* tool.
*/
objects = pika_align_options_get_objects (options);
for (iter = objects; iter; iter = iter->next)
{
if (PIKA_IS_GUIDE (iter->data))
{
PikaGuide *guide = iter->data;
PikaCanvasItem *item;
PikaGuideStyle style;
style = pika_guide_get_style (guide);
item = pika_draw_tool_add_guide (draw_tool,
pika_guide_get_orientation (guide),
pika_guide_get_position (guide),
style);
pika_canvas_item_set_highlight (item, TRUE);
}
}
}
static void
pika_align_tool_redraw (PikaAlignTool *align_tool)
{
PikaDrawTool *draw_tool = PIKA_DRAW_TOOL (align_tool);
pika_draw_tool_pause (draw_tool);
if (! pika_draw_tool_is_active (draw_tool) && draw_tool->display)
pika_draw_tool_start (draw_tool, draw_tool->display);
pika_draw_tool_resume (draw_tool);
}
static void
pika_align_tool_align (PikaAlignTool *align_tool,
PikaAlignmentType align_type)
{
PikaAlignOptions *options = PIKA_ALIGN_TOOL_GET_OPTIONS (align_tool);
PikaImage *image;
GObject *reference_object = NULL;
GList *objects;
GList *list;
gdouble align_x = 0.0;
gdouble align_y = 0.0;
/* if nothing is selected, just return */
objects = pika_align_options_get_objects (options);
if (! objects)
return;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
list = objects;
if (align_type < PIKA_ARRANGE_HFILL)
{
reference_object = pika_align_options_get_reference (options, TRUE);
if (! reference_object)
return;
}
pika_draw_tool_pause (PIKA_DRAW_TOOL (align_tool));
pika_align_options_get_pivot (options, &align_x, &align_y);
pika_image_arrange_objects (image, list,
align_x, align_y,
reference_object,
align_type,
pika_align_options_align_contents (options));
pika_draw_tool_resume (PIKA_DRAW_TOOL (align_tool));
pika_image_flush (image);
g_list_free (objects);
}
static gint
pika_align_tool_undo_idle (gpointer data)
{
PikaDrawTool *draw_tool = PIKA_DRAW_TOOL (data);
PikaDisplay *display = draw_tool->display;
/* This makes sure that we properly undraw then redraw the various handles and
* highlighted guides after undoing.
*/
pika_draw_tool_stop (draw_tool);
pika_draw_tool_start (draw_tool, display);
return FALSE; /* remove idle */
}
static void
pika_align_tool_display_changed (PikaContext *context,
PikaDisplay *display,
PikaAlignTool *align_tool)
{
PikaTool *tool = PIKA_TOOL (align_tool);
PikaDrawTool *draw_tool = PIKA_DRAW_TOOL (align_tool);
pika_draw_tool_pause (draw_tool);
if (display != tool->display)
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, display);
tool->display = display;
if (! pika_draw_tool_is_active (draw_tool) && display)
pika_draw_tool_start (draw_tool, display);
pika_draw_tool_resume (draw_tool);
}

83
app/tools/pikaaligntool.h Normal file
View File

@ -0,0 +1,83 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_ALIGN_TOOL_H__
#define __PIKA_ALIGN_TOOL_H__
#include "pikadrawtool.h"
/* tool function/operation/state/mode */
typedef enum
{
ALIGN_TOOL_NO_ACTION,
ALIGN_TOOL_REF_IDLE,
ALIGN_TOOL_REF_PICK_LAYER,
ALIGN_TOOL_REF_PICK_GUIDE,
ALIGN_TOOL_REF_PICK_PATH,
ALIGN_TOOL_REF_DRAG_BOX,
ALIGN_TOOL_ALIGN_IDLE,
ALIGN_TOOL_ALIGN_PICK_GUIDE,
ALIGN_TOOL_ALIGN_ADD_GUIDE,
} PikaAlignToolFunction;
#define PIKA_TYPE_ALIGN_TOOL (pika_align_tool_get_type ())
#define PIKA_ALIGN_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ALIGN_TOOL, PikaAlignTool))
#define PIKA_ALIGN_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ALIGN_TOOL, PikaAlignToolClass))
#define PIKA_IS_ALIGN_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ALIGN_TOOL))
#define PIKA_IS_ALIGN_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ALIGN_TOOL))
#define PIKA_ALIGN_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ALIGN_TOOL, PikaAlignToolClass))
#define PIKA_ALIGN_TOOL_GET_OPTIONS(t) (PIKA_ALIGN_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaAlignTool PikaAlignTool;
typedef struct _PikaAlignToolClass PikaAlignToolClass;
struct _PikaAlignTool
{
PikaDrawTool parent_instance;
PikaAlignToolFunction function;
GList *selected_objects;
gint x1, y1, x2, y2; /* rubber-band rectangle */
gboolean set_reference;
};
struct _PikaAlignToolClass
{
PikaDrawToolClass parent_class;
};
void pika_align_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_align_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_ALIGN_TOOL_H__ */

View File

@ -0,0 +1,323 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "operations/pikabrightnesscontrastconfig.h"
#include "core/pikadrawable.h"
#include "core/pikaerror.h"
#include "core/pikaimage.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-constructors.h"
#include "display/pikadisplay.h"
#include "pikabrightnesscontrasttool.h"
#include "pikafilteroptions.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
#define SLIDER_WIDTH 200
static gboolean pika_brightness_contrast_tool_initialize (PikaTool *tool,
PikaDisplay *display,
GError **error);
static void pika_brightness_contrast_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display);
static void pika_brightness_contrast_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display);
static void pika_brightness_contrast_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display);
static gchar *
pika_brightness_contrast_tool_get_operation (PikaFilterTool *filter_tool,
gchar **description);
static void pika_brightness_contrast_tool_dialog (PikaFilterTool *filter_tool);
static void brightness_contrast_to_levels_callback (GtkWidget *widget,
PikaFilterTool *filter_tool);
G_DEFINE_TYPE (PikaBrightnessContrastTool, pika_brightness_contrast_tool,
PIKA_TYPE_FILTER_TOOL)
#define parent_class pika_brightness_contrast_tool_parent_class
void
pika_brightness_contrast_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL,
PIKA_TYPE_FILTER_OPTIONS, NULL,
0,
"pika-brightness-contrast-tool",
_("Brightness-Contrast"),
_("Adjust brightness and contrast"),
N_("B_rightness-Contrast..."), NULL,
NULL, PIKA_HELP_TOOL_BRIGHTNESS_CONTRAST,
PIKA_ICON_TOOL_BRIGHTNESS_CONTRAST,
data);
}
static void
pika_brightness_contrast_tool_class_init (PikaBrightnessContrastToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaFilterToolClass *filter_tool_class = PIKA_FILTER_TOOL_CLASS (klass);
tool_class->initialize = pika_brightness_contrast_tool_initialize;
tool_class->button_press = pika_brightness_contrast_tool_button_press;
tool_class->button_release = pika_brightness_contrast_tool_button_release;
tool_class->motion = pika_brightness_contrast_tool_motion;
filter_tool_class->get_operation = pika_brightness_contrast_tool_get_operation;
filter_tool_class->dialog = pika_brightness_contrast_tool_dialog;
}
static void
pika_brightness_contrast_tool_init (PikaBrightnessContrastTool *bc_tool)
{
}
static gboolean
pika_brightness_contrast_tool_initialize (PikaTool *tool,
PikaDisplay *display,
GError **error)
{
PikaBrightnessContrastTool *bc_tool = PIKA_BRIGHTNESS_CONTRAST_TOOL (tool);
PikaImage *image = pika_display_get_image (display);
GList *drawables;
if (! PIKA_TOOL_CLASS (parent_class)->initialize (tool, display, error))
{
return FALSE;
}
drawables = pika_image_get_selected_drawables (image);
/* Single drawable selection has been checked in parent initialize(). */
g_return_val_if_fail (g_list_length (drawables) == 1, FALSE);
if (pika_drawable_get_component_type (drawables->data) == PIKA_COMPONENT_TYPE_U8)
{
pika_prop_widget_set_factor (bc_tool->brightness_scale,
127.0, 1.0, 8.0, 0);
pika_prop_widget_set_factor (bc_tool->contrast_scale,
127.0, 1.0, 8.0, 0);
}
else
{
pika_prop_widget_set_factor (bc_tool->brightness_scale,
0.5, 0.01, 0.1, 3);
pika_prop_widget_set_factor (bc_tool->contrast_scale,
0.5, 0.01, 0.1, 3);
}
g_list_free (drawables);
return TRUE;
}
static gchar *
pika_brightness_contrast_tool_get_operation (PikaFilterTool *filter_tool,
gchar **description)
{
*description = g_strdup (_("Adjust Brightness and Contrast"));
return g_strdup ("pika:brightness-contrast");
}
static void
pika_brightness_contrast_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display)
{
PikaBrightnessContrastTool *bc_tool = PIKA_BRIGHTNESS_CONTRAST_TOOL (tool);
bc_tool->dragging = ! pika_filter_tool_on_guide (PIKA_FILTER_TOOL (tool),
coords, display);
if (! bc_tool->dragging)
{
PIKA_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
press_type, display);
}
else
{
gdouble brightness;
gdouble contrast;
g_object_get (PIKA_FILTER_TOOL (tool)->config,
"brightness", &brightness,
"contrast", &contrast,
NULL);
bc_tool->x = coords->x - contrast * 127.0;
bc_tool->y = coords->y + brightness * 127.0;
bc_tool->dx = contrast * 127.0;
bc_tool->dy = - brightness * 127.0;
tool->display = display;
pika_tool_control_activate (tool->control);
}
}
static void
pika_brightness_contrast_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display)
{
PikaBrightnessContrastTool *bc_tool = PIKA_BRIGHTNESS_CONTRAST_TOOL (tool);
if (! bc_tool->dragging)
{
PIKA_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
release_type, display);
}
else
{
pika_tool_control_halt (tool->control);
bc_tool->dragging = FALSE;
if (bc_tool->dx == 0 && bc_tool->dy == 0)
return;
if (release_type == PIKA_BUTTON_RELEASE_CANCEL)
pika_config_reset (PIKA_CONFIG (PIKA_FILTER_TOOL (tool)->config));
}
}
static void
pika_brightness_contrast_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display)
{
PikaBrightnessContrastTool *bc_tool = PIKA_BRIGHTNESS_CONTRAST_TOOL (tool);
if (! bc_tool->dragging)
{
PIKA_TOOL_CLASS (parent_class)->motion (tool, coords, time, state,
display);
}
else
{
bc_tool->dx = (coords->x - bc_tool->x);
bc_tool->dy = - (coords->y - bc_tool->y);
g_object_set (PIKA_FILTER_TOOL (tool)->config,
"brightness", CLAMP (bc_tool->dy, -127.0, 127.0) / 127.0,
"contrast", CLAMP (bc_tool->dx, -127.0, 127.0) / 127.0,
NULL);
}
}
/********************************/
/* Brightness Contrast dialog */
/********************************/
static void
pika_brightness_contrast_tool_dialog (PikaFilterTool *filter_tool)
{
PikaBrightnessContrastTool *bc_tool = PIKA_BRIGHTNESS_CONTRAST_TOOL (filter_tool);
GtkWidget *main_vbox;
GtkWidget *scale;
GtkWidget *button;
main_vbox = pika_filter_tool_dialog_get_vbox (filter_tool);
/* Create the brightness scale widget */
scale = pika_prop_spin_scale_new (filter_tool->config, "brightness",
0.01, 0.1, 3);
pika_spin_scale_set_label (PIKA_SPIN_SCALE (scale), _("_Brightness"));
gtk_box_pack_start (GTK_BOX (main_vbox), scale, FALSE, FALSE, 0);
bc_tool->brightness_scale = scale;
/* Create the contrast scale widget */
scale = pika_prop_spin_scale_new (filter_tool->config, "contrast",
0.01, 0.1, 3);
pika_spin_scale_set_label (PIKA_SPIN_SCALE (scale), _("_Contrast"));
gtk_box_pack_start (GTK_BOX (main_vbox), scale, FALSE, FALSE, 0);
bc_tool->contrast_scale = scale;
button = pika_icon_button_new (PIKA_ICON_TOOL_LEVELS,
_("Edit these Settings as Levels"));
gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "clicked",
G_CALLBACK (brightness_contrast_to_levels_callback),
filter_tool);
}
static void
brightness_contrast_to_levels_callback (GtkWidget *widget,
PikaFilterTool *filter_tool)
{
PikaLevelsConfig *levels;
levels = pika_brightness_contrast_config_to_levels_config (PIKA_BRIGHTNESS_CONTRAST_CONFIG (filter_tool->config));
pika_filter_tool_edit_as (filter_tool,
"pika-levels-tool",
PIKA_CONFIG (levels));
g_object_unref (levels);
}

View File

@ -0,0 +1,65 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_BRIGHTNESS_CONTRAST_TOOL_H__
#define __PIKA_BRIGHTNESS_CONTRAST_TOOL_H__
#include "pikafiltertool.h"
#define PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL (pika_brightness_contrast_tool_get_type ())
#define PIKA_BRIGHTNESS_CONTRAST_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL, PikaBrightnessContrastTool))
#define PIKA_BRIGHTNESS_CONTRAST_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL, PikaBrightnessContrastToolClass))
#define PIKA_IS_BRIGHTNESS_CONTRAST_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL))
#define PIKA_IS_BRIGHTNESS_CONTRAST_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL))
#define PIKA_BRIGHTNESS_CONTRAST_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRIGHTNESS_CONTRAST_TOOL, PikaBrightnessContrastToolClass))
typedef struct _PikaBrightnessContrastTool PikaBrightnessContrastTool;
typedef struct _PikaBrightnessContrastToolClass PikaBrightnessContrastToolClass;
struct _PikaBrightnessContrastTool
{
PikaFilterTool parent_instance;
gboolean dragging;
gdouble x, y;
gdouble dx, dy;
/* dialog */
GtkWidget *brightness_scale;
GtkWidget *contrast_scale;
};
struct _PikaBrightnessContrastToolClass
{
PikaFilterToolClass parent_class;
};
void pika_brightness_contrast_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_brightness_contrast_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_BRIGHTNESS_CONTRAST_TOOL_H__ */

455
app/tools/pikabrushtool.c Normal file
View File

@ -0,0 +1,455 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "tools-types.h"
#include "config/pikadisplayconfig.h"
#include "core/pika.h"
#include "core/pikabezierdesc.h"
#include "core/pikabrush.h"
#include "core/pikaimage.h"
#include "core/pikatoolinfo.h"
#include "paint/pikabrushcore.h"
#include "paint/pikapaintoptions.h"
#include "display/pikacanvashandle.h"
#include "display/pikacanvaspath.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "pikabrushtool.h"
#include "pikapainttool-paint.h"
#include "pikatoolcontrol.h"
static void pika_brush_tool_constructed (GObject *object);
static void pika_brush_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_brush_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
static void pika_brush_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec);
static void pika_brush_tool_paint_start (PikaPaintTool *paint_tool);
static void pika_brush_tool_paint_end (PikaPaintTool *paint_tool);
static void pika_brush_tool_paint_flush (PikaPaintTool *paint_tool);
static PikaCanvasItem *
pika_brush_tool_get_outline (PikaPaintTool *paint_tool,
PikaDisplay *display,
gdouble x,
gdouble y);
static void pika_brush_tool_brush_changed (PikaContext *context,
PikaBrush *brush,
PikaBrushTool *brush_tool);
static void pika_brush_tool_set_brush (PikaBrushCore *brush_core,
PikaBrush *brush,
PikaBrushTool *brush_tool);
static const PikaBezierDesc *
pika_brush_tool_get_boundary (PikaBrushTool *brush_tool,
gint *width,
gint *height);
G_DEFINE_TYPE (PikaBrushTool, pika_brush_tool, PIKA_TYPE_PAINT_TOOL)
#define parent_class pika_brush_tool_parent_class
static void
pika_brush_tool_class_init (PikaBrushToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaPaintToolClass *paint_tool_class = PIKA_PAINT_TOOL_CLASS (klass);
object_class->constructed = pika_brush_tool_constructed;
tool_class->oper_update = pika_brush_tool_oper_update;
tool_class->cursor_update = pika_brush_tool_cursor_update;
tool_class->options_notify = pika_brush_tool_options_notify;
paint_tool_class->paint_start = pika_brush_tool_paint_start;
paint_tool_class->paint_end = pika_brush_tool_paint_end;
paint_tool_class->paint_flush = pika_brush_tool_paint_flush;
paint_tool_class->get_outline = pika_brush_tool_get_outline;
}
static void
pika_brush_tool_init (PikaBrushTool *brush_tool)
{
PikaTool *tool = PIKA_TOOL (brush_tool);
pika_tool_control_set_action_pixel_size (tool->control,
"tools-paintbrush-pixel-size-set");
pika_tool_control_set_action_size (tool->control,
"tools-paintbrush-size-set");
pika_tool_control_set_action_aspect (tool->control,
"tools-paintbrush-aspect-ratio-set");
pika_tool_control_set_action_angle (tool->control,
"tools-paintbrush-angle-set");
pika_tool_control_set_action_spacing (tool->control,
"tools-paintbrush-spacing-set");
pika_tool_control_set_action_hardness (tool->control,
"tools-paintbrush-hardness-set");
pika_tool_control_set_action_force (tool->control,
"tools-paintbrush-force-set");
pika_tool_control_set_action_object_1 (tool->control,
"context-brush-select-set");
}
static void
pika_brush_tool_constructed (GObject *object)
{
PikaTool *tool = PIKA_TOOL (object);
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
pika_assert (PIKA_IS_BRUSH_CORE (paint_tool->core));
g_signal_connect_object (pika_tool_get_options (tool), "brush-changed",
G_CALLBACK (pika_brush_tool_brush_changed),
paint_tool, 0);
g_signal_connect_object (paint_tool->core, "set-brush",
G_CALLBACK (pika_brush_tool_set_brush),
paint_tool, 0);
}
static void
pika_brush_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaPaintOptions *paint_options = PIKA_PAINT_TOOL_GET_OPTIONS (tool);
PikaImage *image = pika_display_get_image (display);
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
PIKA_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
proximity, display);
if (! pika_color_tool_is_enabled (PIKA_COLOR_TOOL (tool)) &&
image && proximity)
{
PikaContext *context = PIKA_CONTEXT (paint_options);
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
pika_brush_core_set_brush (brush_core,
pika_context_get_brush (context));
pika_brush_core_set_dynamics (brush_core,
pika_context_get_dynamics (context));
if (PIKA_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush)
{
pika_brush_core_eval_transform_dynamics (brush_core,
image,
paint_options,
coords);
}
}
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
}
static void
pika_brush_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaBrushTool *brush_tool = PIKA_BRUSH_TOOL (tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (PIKA_PAINT_TOOL (brush_tool)->core);
if (! pika_color_tool_is_enabled (PIKA_COLOR_TOOL (tool)))
{
if (! brush_core->main_brush || ! brush_core->dynamics)
{
pika_tool_set_cursor (tool, display,
pika_tool_control_get_cursor (tool->control),
pika_tool_control_get_tool_cursor (tool->control),
PIKA_CURSOR_MODIFIER_BAD);
return;
}
}
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
static void
pika_brush_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec)
{
PIKA_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
if (! strcmp (pspec->name, "brush-size") ||
! strcmp (pspec->name, "brush-angle") ||
! strcmp (pspec->name, "brush-aspect-ratio"))
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
g_signal_emit_by_name (brush_core, "set-brush",
brush_core->main_brush);
}
}
static void
pika_brush_tool_paint_start (PikaPaintTool *paint_tool)
{
PikaBrushTool *brush_tool = PIKA_BRUSH_TOOL (paint_tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
const PikaBezierDesc *boundary;
if (PIKA_PAINT_TOOL_CLASS (parent_class)->paint_start)
PIKA_PAINT_TOOL_CLASS (parent_class)->paint_start (paint_tool);
boundary = pika_brush_tool_get_boundary (brush_tool,
&brush_tool->boundary_width,
&brush_tool->boundary_height);
if (boundary)
brush_tool->boundary = pika_bezier_desc_copy (boundary);
brush_tool->boundary_scale = brush_core->scale;
brush_tool->boundary_aspect_ratio = brush_core->aspect_ratio;
brush_tool->boundary_angle = brush_core->angle;
brush_tool->boundary_reflect = brush_core->reflect;
brush_tool->boundary_hardness = brush_core->hardness;
}
static void
pika_brush_tool_paint_end (PikaPaintTool *paint_tool)
{
PikaBrushTool *brush_tool = PIKA_BRUSH_TOOL (paint_tool);
g_clear_pointer (&brush_tool->boundary, pika_bezier_desc_free);
if (PIKA_PAINT_TOOL_CLASS (parent_class)->paint_end)
PIKA_PAINT_TOOL_CLASS (parent_class)->paint_end (paint_tool);
}
static void
pika_brush_tool_paint_flush (PikaPaintTool *paint_tool)
{
PikaBrushTool *brush_tool = PIKA_BRUSH_TOOL (paint_tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
const PikaBezierDesc *boundary;
if (PIKA_PAINT_TOOL_CLASS (parent_class)->paint_flush)
PIKA_PAINT_TOOL_CLASS (parent_class)->paint_flush (paint_tool);
if (brush_tool->boundary_scale != brush_core->scale ||
brush_tool->boundary_aspect_ratio != brush_core->aspect_ratio ||
brush_tool->boundary_angle != brush_core->angle ||
brush_tool->boundary_reflect != brush_core->reflect ||
brush_tool->boundary_hardness != brush_core->hardness)
{
g_clear_pointer (&brush_tool->boundary, pika_bezier_desc_free);
boundary = pika_brush_tool_get_boundary (brush_tool,
&brush_tool->boundary_width,
&brush_tool->boundary_height);
if (boundary)
brush_tool->boundary = pika_bezier_desc_copy (boundary);
brush_tool->boundary_scale = brush_core->scale;
brush_tool->boundary_aspect_ratio = brush_core->aspect_ratio;
brush_tool->boundary_angle = brush_core->angle;
brush_tool->boundary_reflect = brush_core->reflect;
brush_tool->boundary_hardness = brush_core->hardness;
}
}
static PikaCanvasItem *
pika_brush_tool_get_outline (PikaPaintTool *paint_tool,
PikaDisplay *display,
gdouble x,
gdouble y)
{
PikaBrushTool *brush_tool = PIKA_BRUSH_TOOL (paint_tool);
PikaCanvasItem *item;
item = pika_brush_tool_create_outline (brush_tool, display, x, y);
if (! item)
{
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
if (brush_core->main_brush && brush_core->dynamics)
{
/* if an outline was expected, but got scaled away by
* transform/dynamics, draw a circle in the "normal" size.
*/
PikaPaintOptions *options;
options = PIKA_PAINT_TOOL_GET_OPTIONS (brush_tool);
pika_paint_tool_set_draw_fallback (paint_tool,
TRUE, options->brush_size);
}
}
return item;
}
PikaCanvasItem *
pika_brush_tool_create_outline (PikaBrushTool *brush_tool,
PikaDisplay *display,
gdouble x,
gdouble y)
{
PikaTool *tool;
PikaDisplayShell *shell;
const PikaBezierDesc *boundary = NULL;
gint width = 0;
gint height = 0;
g_return_val_if_fail (PIKA_IS_BRUSH_TOOL (brush_tool), NULL);
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
if (pika_paint_tool_paint_is_active (PIKA_PAINT_TOOL (brush_tool)))
{
boundary = brush_tool->boundary;
width = brush_tool->boundary_width;
height = brush_tool->boundary_height;
}
else
{
boundary = pika_brush_tool_get_boundary (brush_tool, &width, &height);
}
if (! boundary)
return NULL;
tool = PIKA_TOOL (brush_tool);
shell = pika_display_get_shell (display);
/* don't draw the boundary if it becomes too small */
if (SCALEX (shell, width) > 4 &&
SCALEY (shell, height) > 4)
{
x -= width / 2.0;
y -= height / 2.0;
if (pika_tool_control_get_precision (tool->control) ==
PIKA_CURSOR_PRECISION_PIXEL_CENTER)
{
#define EPSILON 0.000001
/* Add EPSILON before rounding since e.g.
* (5.0 - 0.5) may end up at (4.499999999....)
* due to floating point fnords
*/
x = RINT (x + EPSILON);
y = RINT (y + EPSILON);
#undef EPSILON
}
return pika_canvas_path_new (shell, boundary, x, y, FALSE,
PIKA_PATH_STYLE_OUTLINE);
}
return NULL;
}
static void
pika_brush_tool_brush_changed (PikaContext *context,
PikaBrush *brush,
PikaBrushTool *brush_tool)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (brush_tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
pika_brush_core_set_brush (brush_core, brush);
}
static void
pika_brush_tool_set_brush (PikaBrushCore *brush_core,
PikaBrush *brush,
PikaBrushTool *brush_tool)
{
pika_draw_tool_pause (PIKA_DRAW_TOOL (brush_tool));
if (PIKA_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush)
{
PikaPaintCore *paint_core = PIKA_PAINT_CORE (brush_core);
pika_brush_core_eval_transform_dynamics (brush_core,
NULL,
PIKA_PAINT_TOOL_GET_OPTIONS (brush_tool),
&paint_core->cur_coords);
}
pika_draw_tool_resume (PIKA_DRAW_TOOL (brush_tool));
}
static const PikaBezierDesc *
pika_brush_tool_get_boundary (PikaBrushTool *brush_tool,
gint *width,
gint *height)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (brush_tool);
PikaBrushCore *brush_core = PIKA_BRUSH_CORE (paint_tool->core);
if (paint_tool->draw_brush &&
brush_core->main_brush &&
brush_core->dynamics &&
brush_core->scale > 0.0)
{
return pika_brush_transform_boundary (brush_core->main_brush,
brush_core->scale,
brush_core->aspect_ratio,
brush_core->angle,
brush_core->reflect,
brush_core->hardness,
width,
height);
}
return NULL;
}

67
app/tools/pikabrushtool.h Normal file
View File

@ -0,0 +1,67 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_BRUSH_TOOL_H__
#define __PIKA_BRUSH_TOOL_H__
#include "pikapainttool.h"
#define PIKA_TYPE_BRUSH_TOOL (pika_brush_tool_get_type ())
#define PIKA_BRUSH_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRUSH_TOOL, PikaBrushTool))
#define PIKA_BRUSH_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRUSH_TOOL, PikaBrushToolClass))
#define PIKA_IS_BRUSH_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRUSH_TOOL))
#define PIKA_IS_BRUSH_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRUSH_TOOL))
#define PIKA_BRUSH_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRUSH_TOOL, PikaBrushToolClass))
typedef struct _PikaBrushToolClass PikaBrushToolClass;
struct _PikaBrushTool
{
PikaPaintTool parent_instance;
PikaBezierDesc *boundary;
gint boundary_width;
gint boundary_height;
gdouble boundary_scale;
gdouble boundary_aspect_ratio;
gdouble boundary_angle;
gboolean boundary_reflect;
gdouble boundary_hardness;
};
struct _PikaBrushToolClass
{
PikaPaintToolClass parent_class;
};
GType pika_brush_tool_get_type (void) G_GNUC_CONST;
PikaCanvasItem * pika_brush_tool_create_outline (PikaBrushTool *brush_tool,
PikaDisplay *display,
gdouble x,
gdouble y);
#endif /* __PIKA_BRUSH_TOOL_H__ */

View File

@ -0,0 +1,876 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "libpikawidgets/pikawidgets-private.h"
#include "tools-types.h"
#include "config/pikacoreconfig.h"
#include "config/pikadialogconfig.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h"
#include "core/pikadrawable.h"
#include "core/pikaimage.h"
#include "core/pikapaintinfo.h"
#include "core/pikastrokeoptions.h"
#include "core/pikatoolinfo.h"
#include "display/pikadisplay.h"
#include "paint/pikasourceoptions.h"
#include "widgets/pikacontainercombobox.h"
#include "widgets/pikacontainertreestore.h"
#include "widgets/pikacontainerview.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikaviewablebox.h"
#include "widgets/pikaviewrenderer.h"
#include "widgets/pikawidgets-utils.h"
#include "pikabucketfilloptions.h"
#include "pikapaintoptions-gui.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_FILL_MODE,
PROP_FILL_AREA,
PROP_FILL_TRANSPARENT,
PROP_SAMPLE_MERGED,
PROP_DIAGONAL_NEIGHBORS,
PROP_ANTIALIAS,
PROP_FEATHER,
PROP_FEATHER_RADIUS,
PROP_THRESHOLD,
PROP_LINE_ART_SOURCE,
PROP_LINE_ART_THRESHOLD,
PROP_LINE_ART_MAX_GROW,
PROP_LINE_ART_STROKE,
PROP_LINE_ART_STROKE_TOOL,
PROP_LINE_ART_AUTOMATIC_CLOSURE,
PROP_LINE_ART_MAX_GAP_LENGTH,
PROP_FILL_CRITERION,
PROP_FILL_COLOR_AS_LINE_ART,
PROP_FILL_COLOR_AS_LINE_ART_THRESHOLD,
};
struct _PikaBucketFillOptionsPrivate
{
GtkWidget *diagonal_neighbors_checkbox;
GtkWidget *threshold_scale;
GtkWidget *similar_color_frame;
GtkWidget *line_art_settings;
GtkWidget *fill_as_line_art_frame;
GtkWidget *line_art_detect_opacity;
};
static void pika_bucket_fill_options_config_iface_init (PikaConfigInterface *config_iface);
static void pika_bucket_fill_options_finalize (GObject *object);
static void pika_bucket_fill_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_bucket_fill_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gboolean
pika_bucket_fill_options_select_stroke_tool (PikaContainerView *view,
GList *items,
GList *paths,
PikaBucketFillOptions *options);
static void pika_bucket_fill_options_tool_cell_renderer (GtkCellLayout *layout,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
static void pika_bucket_fill_options_image_changed (PikaContext *context,
PikaImage *image,
PikaBucketFillOptions *options);
static void pika_bucket_fill_options_reset (PikaConfig *config);
static void pika_bucket_fill_options_update_area (PikaBucketFillOptions *options);
G_DEFINE_TYPE_WITH_CODE (PikaBucketFillOptions, pika_bucket_fill_options,
PIKA_TYPE_PAINT_OPTIONS,
G_ADD_PRIVATE (PikaBucketFillOptions)
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
pika_bucket_fill_options_config_iface_init))
#define parent_class pika_bucket_fill_options_parent_class
static PikaConfigInterface *parent_config_iface = NULL;
static void
pika_bucket_fill_options_class_init (PikaBucketFillOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_bucket_fill_options_finalize;
object_class->set_property = pika_bucket_fill_options_set_property;
object_class->get_property = pika_bucket_fill_options_get_property;
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FILL_MODE,
"fill-mode",
_("Fill type"),
NULL,
PIKA_TYPE_BUCKET_FILL_MODE,
PIKA_BUCKET_FILL_FG,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FILL_AREA,
"fill-area",
_("Fill selection"),
_("Which area will be filled"),
PIKA_TYPE_BUCKET_FILL_AREA,
PIKA_BUCKET_FILL_SIMILAR_COLORS,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_FILL_TRANSPARENT,
"fill-transparent",
_("Fill transparent areas"),
_("Allow completely transparent regions "
"to be filled"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_SAMPLE_MERGED,
"sample-merged",
_("Sample merged"),
_("Base filled area on all visible layers"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_DIAGONAL_NEIGHBORS,
"diagonal-neighbors",
_("Diagonal neighbors"),
_("Treat diagonally neighboring pixels as "
"connected"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ANTIALIAS,
"antialias",
_("Antialiasing"),
_("Base fill opacity on color difference from "
"the clicked pixel (see threshold) or on line "
" art borders. Disable antialiasing to fill "
"the entire area uniformly."),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_FEATHER,
"feather",
_("Feather edges"),
_("Enable feathering of fill edges"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_FEATHER_RADIUS,
"feather-radius",
_("Radius"),
_("Radius of feathering"),
0.0, 100.0, 10.0,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_THRESHOLD,
"threshold",
_("Threshold"),
_("Maximum color difference"),
0.0, 255.0, 15.0,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_LINE_ART_SOURCE,
"line-art-source",
_("Source"),
_("Source image for line art computation"),
PIKA_TYPE_LINE_ART_SOURCE,
PIKA_LINE_ART_SOURCE_SAMPLE_MERGED,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_FILL_COLOR_AS_LINE_ART,
"fill-color-as-line-art",
_("Manual closure in fill layer"),
_("Consider pixels of selected layer and filled with the fill color as line art closure"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_FILL_COLOR_AS_LINE_ART_THRESHOLD,
"fill-color-as-line-art-threshold",
_("Threshold"),
_("Maximum color difference"),
0.0, 255.0, 15.0,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_LINE_ART_THRESHOLD,
"line-art-threshold",
_("Line art detection threshold"),
_("Threshold to detect contour (higher values will include more pixels)"),
0.0, 1.0, 0.92,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_LINE_ART_MAX_GROW,
"line-art-max-grow",
_("Maximum growing size"),
_("Maximum number of pixels grown under the line art"),
1, 100, 3,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_LINE_ART_STROKE,
"line-art-stroke-border",
_("Stroke borders"),
_("Stroke fill borders with last stroke options"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_STRING (object_class, PROP_LINE_ART_STROKE_TOOL,
"line-art-stroke-tool",
_("Stroke tool"),
_("The tool to stroke the fill borders with"),
"pika-pencil", PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_LINE_ART_AUTOMATIC_CLOSURE,
"line-art-automatic-closure",
_("Automatic closure"),
_("Geometric analysis of the stroke contours to close line arts by splines/segments"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_LINE_ART_MAX_GAP_LENGTH,
"line-art-max-gap-length",
_("Maximum gap length"),
_("Maximum gap (in pixels) in line art which can be closed"),
0, 1000, 100,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FILL_CRITERION,
"fill-criterion",
_("Fill by"),
_("Criterion used for determining color similarity"),
PIKA_TYPE_SELECT_CRITERION,
PIKA_SELECT_CRITERION_COMPOSITE,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_bucket_fill_options_config_iface_init (PikaConfigInterface *config_iface)
{
parent_config_iface = g_type_interface_peek_parent (config_iface);
config_iface->reset = pika_bucket_fill_options_reset;
}
static void
pika_bucket_fill_options_init (PikaBucketFillOptions *options)
{
options->priv = pika_bucket_fill_options_get_instance_private (options);
options->line_art_stroke_tool = NULL;
}
static void
pika_bucket_fill_options_finalize (GObject *object)
{
PikaBucketFillOptions *options = PIKA_BUCKET_FILL_OPTIONS (object);
g_clear_object (&options->stroke_options);
g_clear_pointer (&options->line_art_stroke_tool, g_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_bucket_fill_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaBucketFillOptions *options = PIKA_BUCKET_FILL_OPTIONS (object);
PikaToolOptions *tool_options = PIKA_TOOL_OPTIONS (object);
switch (property_id)
{
case PROP_FILL_MODE:
options->fill_mode = g_value_get_enum (value);
pika_bucket_fill_options_update_area (options);
break;
case PROP_FILL_AREA:
options->fill_area = g_value_get_enum (value);
pika_bucket_fill_options_update_area (options);
break;
case PROP_FILL_TRANSPARENT:
options->fill_transparent = g_value_get_boolean (value);
break;
case PROP_SAMPLE_MERGED:
options->sample_merged = g_value_get_boolean (value);
break;
case PROP_DIAGONAL_NEIGHBORS:
options->diagonal_neighbors = g_value_get_boolean (value);
break;
case PROP_ANTIALIAS:
options->antialias = g_value_get_boolean (value);
break;
case PROP_FEATHER:
options->feather = g_value_get_boolean (value);
break;
case PROP_FEATHER_RADIUS:
options->feather_radius = g_value_get_double (value);
break;
case PROP_THRESHOLD:
options->threshold = g_value_get_double (value);
break;
case PROP_LINE_ART_SOURCE:
options->line_art_source = g_value_get_enum (value);
pika_bucket_fill_options_update_area (options);
break;
case PROP_LINE_ART_THRESHOLD:
options->line_art_threshold = g_value_get_double (value);
break;
case PROP_LINE_ART_MAX_GROW:
options->line_art_max_grow = g_value_get_int (value);
break;
case PROP_LINE_ART_STROKE:
options->line_art_stroke = g_value_get_boolean (value);
break;
case PROP_LINE_ART_STROKE_TOOL:
g_clear_pointer (&options->line_art_stroke_tool, g_free);
options->line_art_stroke_tool = g_value_dup_string (value);
if (options->stroke_options)
{
PikaPaintInfo *paint_info = NULL;
Pika *pika = tool_options->tool_info->pika;
if (! options->line_art_stroke_tool)
options->line_art_stroke_tool = g_strdup ("pika-pencil");
paint_info = PIKA_PAINT_INFO (pika_container_get_child_by_name (pika->paint_info_list,
options->line_art_stroke_tool));
if (! paint_info && ! pika_container_is_empty (pika->paint_info_list))
paint_info = PIKA_PAINT_INFO (pika_container_get_child_by_index (pika->paint_info_list, 0));
g_object_set (options->stroke_options,
"paint-info", paint_info,
NULL);
}
break;
case PROP_LINE_ART_AUTOMATIC_CLOSURE:
options->line_art_automatic_closure = g_value_get_boolean (value);
break;
case PROP_LINE_ART_MAX_GAP_LENGTH:
options->line_art_max_gap_length = g_value_get_int (value);
break;
case PROP_FILL_CRITERION:
options->fill_criterion = g_value_get_enum (value);
break;
case PROP_FILL_COLOR_AS_LINE_ART:
options->fill_as_line_art = g_value_get_boolean (value);
break;
case PROP_FILL_COLOR_AS_LINE_ART_THRESHOLD:
options->fill_as_line_art_threshold = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_bucket_fill_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaBucketFillOptions *options = PIKA_BUCKET_FILL_OPTIONS (object);
switch (property_id)
{
case PROP_FILL_MODE:
g_value_set_enum (value, options->fill_mode);
break;
case PROP_FILL_AREA:
g_value_set_enum (value, options->fill_area);
break;
case PROP_FILL_TRANSPARENT:
g_value_set_boolean (value, options->fill_transparent);
break;
case PROP_SAMPLE_MERGED:
g_value_set_boolean (value, options->sample_merged);
break;
case PROP_DIAGONAL_NEIGHBORS:
g_value_set_boolean (value, options->diagonal_neighbors);
break;
case PROP_ANTIALIAS:
g_value_set_boolean (value, options->antialias);
break;
case PROP_FEATHER:
g_value_set_boolean (value, options->feather);
break;
case PROP_FEATHER_RADIUS:
g_value_set_double (value, options->feather_radius);
break;
case PROP_THRESHOLD:
g_value_set_double (value, options->threshold);
break;
case PROP_LINE_ART_SOURCE:
g_value_set_enum (value, options->line_art_source);
break;
case PROP_LINE_ART_THRESHOLD:
g_value_set_double (value, options->line_art_threshold);
break;
case PROP_LINE_ART_MAX_GROW:
g_value_set_int (value, options->line_art_max_grow);
break;
case PROP_LINE_ART_STROKE:
g_value_set_boolean (value, options->line_art_stroke);
break;
case PROP_LINE_ART_STROKE_TOOL:
g_value_set_string (value, options->line_art_stroke_tool);
break;
case PROP_LINE_ART_AUTOMATIC_CLOSURE:
g_value_set_boolean (value, options->line_art_automatic_closure);
break;
case PROP_LINE_ART_MAX_GAP_LENGTH:
g_value_set_int (value, options->line_art_max_gap_length);
break;
case PROP_FILL_CRITERION:
g_value_set_enum (value, options->fill_criterion);
break;
case PROP_FILL_COLOR_AS_LINE_ART:
g_value_set_boolean (value, options->fill_as_line_art);
break;
case PROP_FILL_COLOR_AS_LINE_ART_THRESHOLD:
g_value_set_double (value, options->fill_as_line_art_threshold);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static gboolean
pika_bucket_fill_options_select_stroke_tool (PikaContainerView *view,
GList *items,
GList *paths,
PikaBucketFillOptions *options)
{
GList *iter;
for (iter = items; iter; iter = iter->next)
{
g_object_set (options,
"line-art-stroke-tool",
iter->data ? pika_object_get_name (iter->data) : NULL,
NULL);
break;
}
return TRUE;
}
static void
pika_bucket_fill_options_tool_cell_renderer (GtkCellLayout *layout,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
PikaViewRenderer *renderer;
gtk_tree_model_get (model, iter,
PIKA_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
-1);
if (renderer->viewable)
{
PikaPaintInfo *info = PIKA_PAINT_INFO (renderer->viewable);
if (PIKA_IS_SOURCE_OPTIONS (info->paint_options))
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
PIKA_CONTAINER_TREE_STORE_COLUMN_NAME_SENSITIVE, FALSE,
-1);
}
g_object_unref (renderer);
}
static void
pika_bucket_fill_options_image_changed (PikaContext *context,
PikaImage *image,
PikaBucketFillOptions *options)
{
PikaImage *prev_image;
prev_image = g_object_get_data (G_OBJECT (options), "pika-bucket-fill-options-image");
if (image != prev_image)
{
if (prev_image)
g_signal_handlers_disconnect_by_func (prev_image,
G_CALLBACK (pika_bucket_fill_options_update_area),
options);
if (image)
{
g_signal_connect_object (image, "selected-channels-changed",
G_CALLBACK (pika_bucket_fill_options_update_area),
options, G_CONNECT_SWAPPED);
g_signal_connect_object (image, "selected-layers-changed",
G_CALLBACK (pika_bucket_fill_options_update_area),
options, G_CONNECT_SWAPPED);
}
g_object_set_data (G_OBJECT (options), "pika-bucket-fill-options-image", image);
pika_bucket_fill_options_update_area (options);
}
}
static void
pika_bucket_fill_options_reset (PikaConfig *config)
{
PikaToolOptions *tool_options = PIKA_TOOL_OPTIONS (config);
GParamSpec *pspec;
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
"threshold");
if (pspec)
G_PARAM_SPEC_DOUBLE (pspec)->default_value =
tool_options->tool_info->pika->config->default_threshold;
parent_config_iface->reset (config);
}
static void
pika_bucket_fill_options_update_area (PikaBucketFillOptions *options)
{
PikaImage *image;
GList *drawables = NULL;
const gchar *tooltip = _("Opaque pixels will be considered as line art "
"instead of low luminance pixels");
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
/* GUI not created yet. */
if (! options->priv->threshold_scale)
return;
if (image)
drawables = pika_image_get_selected_drawables (image);
switch (options->fill_area)
{
case PIKA_BUCKET_FILL_LINE_ART:
gtk_widget_hide (options->priv->similar_color_frame);
gtk_widget_show (options->priv->line_art_settings);
if ((options->fill_mode == PIKA_BUCKET_FILL_FG ||
options->fill_mode == PIKA_BUCKET_FILL_BG) &&
(options->line_art_source == PIKA_LINE_ART_SOURCE_LOWER_LAYER ||
options->line_art_source == PIKA_LINE_ART_SOURCE_UPPER_LAYER))
gtk_widget_set_sensitive (options->priv->fill_as_line_art_frame, TRUE);
else
gtk_widget_set_sensitive (options->priv->fill_as_line_art_frame, FALSE);
if (image != NULL &&
options->line_art_source != PIKA_LINE_ART_SOURCE_SAMPLE_MERGED &&
g_list_length (drawables) == 1)
{
PikaDrawable *source = NULL;
PikaItem *parent;
PikaContainer *container;
gint index;
parent = pika_item_get_parent (PIKA_ITEM (drawables->data));
if (parent)
container = pika_viewable_get_children (PIKA_VIEWABLE (parent));
else
container = pika_image_get_layers (image);
index = pika_item_get_index (PIKA_ITEM (drawables->data));
if (options->line_art_source == PIKA_LINE_ART_SOURCE_ACTIVE_LAYER)
source = drawables->data;
else if (options->line_art_source == PIKA_LINE_ART_SOURCE_LOWER_LAYER)
source = PIKA_DRAWABLE (pika_container_get_child_by_index (container, index + 1));
else if (options->line_art_source == PIKA_LINE_ART_SOURCE_UPPER_LAYER)
source = PIKA_DRAWABLE (pika_container_get_child_by_index (container, index - 1));
gtk_widget_set_sensitive (options->priv->line_art_detect_opacity,
source != NULL &&
pika_drawable_has_alpha (source));
if (source == NULL)
tooltip = _("No valid source drawable selected");
else if (! pika_drawable_has_alpha (source))
tooltip = _("The source drawable has no alpha channel");
}
else
{
gtk_widget_set_sensitive (options->priv->line_art_detect_opacity,
TRUE);
}
gtk_widget_set_tooltip_text (options->priv->line_art_detect_opacity,
tooltip);
break;
case PIKA_BUCKET_FILL_SIMILAR_COLORS:
gtk_widget_show (options->priv->similar_color_frame);
gtk_widget_hide (options->priv->line_art_settings);
break;
default:
gtk_widget_hide (options->priv->similar_color_frame);
gtk_widget_hide (options->priv->line_art_settings);
break;
}
g_list_free (drawables);
}
GtkWidget *
pika_bucket_fill_options_gui (PikaToolOptions *tool_options)
{
PikaBucketFillOptions *options = PIKA_BUCKET_FILL_OPTIONS (tool_options);
GObject *config = G_OBJECT (tool_options);
Pika *pika = tool_options->tool_info->pika;
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *box2;
GtkWidget *frame;
GtkWidget *hbox;
GtkWidget *widget;
GtkWidget *scale;
GtkWidget *combo;
gchar *str;
gboolean bold;
GdkModifierType extend_mask = pika_get_extend_selection_mask ();
GdkModifierType toggle_mask = GDK_MOD1_MASK;
/* fill type */
str = g_strdup_printf (_("Fill Type (%s)"),
pika_get_mod_string (toggle_mask)),
frame = pika_prop_enum_radio_frame_new (config, "fill-mode", str, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
g_free (str);
hbox = pika_prop_pattern_box_new (NULL, PIKA_CONTEXT (tool_options),
NULL, 2,
"pattern-view-type", "pattern-view-size");
pika_enum_radio_frame_add (GTK_FRAME (frame), hbox,
PIKA_BUCKET_FILL_PATTERN, TRUE);
/* fill selection */
str = g_strdup_printf (_("Affected Area (%s)"),
pika_get_mod_string (extend_mask));
frame = pika_prop_enum_radio_frame_new (config, "fill-area", str, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
g_free (str);
/* Similar color frame */
frame = pika_frame_new (_("Finding Similar Colors"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
options->priv->similar_color_frame = frame;
gtk_widget_show (frame);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), box2);
gtk_widget_show (box2);
/* the fill transparent areas toggle */
widget = pika_prop_check_button_new (config, "fill-transparent", NULL);
gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
/* the sample merged toggle */
widget = pika_prop_check_button_new (config, "sample-merged", NULL);
gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
/* the diagonal neighbors toggle */
widget = pika_prop_check_button_new (config, "diagonal-neighbors", NULL);
gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
options->priv->diagonal_neighbors_checkbox = widget;
/* the antialias toggle */
widget = pika_prop_check_button_new (config, "antialias", NULL);
gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
/* the threshold scale */
scale = pika_prop_spin_scale_new (config, "threshold",
1.0, 16.0, 1);
gtk_box_pack_start (GTK_BOX (box2), scale, FALSE, FALSE, 0);
options->priv->threshold_scale = scale;
/* the fill criterion combo */
combo = pika_prop_enum_combo_box_new (config, "fill-criterion", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Fill by"));
gtk_box_pack_start (GTK_BOX (box2), combo, FALSE, FALSE, 0);
/* Line art settings */
options->priv->line_art_settings = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_box_pack_start (GTK_BOX (vbox), options->priv->line_art_settings, FALSE, FALSE, 0);
pika_widget_set_identifier (options->priv->line_art_settings, "line-art-settings");
frame = pika_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (options->priv->line_art_settings), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Line art: label widget */
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
gtk_frame_set_label_widget (GTK_FRAME (frame), box2);
gtk_widget_show (box2);
widget = gtk_label_new (_("Line Art Detection"));
gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
gtk_widget_style_get (GTK_WIDGET (frame),
"label-bold", &bold,
NULL);
pika_label_set_attributes (GTK_LABEL (widget),
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
gtk_widget_show (widget);
options->line_art_busy_box = pika_busy_box_new (_("(computing...)"));
gtk_box_pack_start (GTK_BOX (box2), options->line_art_busy_box,
FALSE, FALSE, 0);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), box2);
gtk_widget_show (box2);
/* Line Art: source combo (replace sample merged!) */
combo = pika_prop_enum_combo_box_new (config, "line-art-source", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Source"));
gtk_box_pack_start (GTK_BOX (box2), combo, FALSE, FALSE, 0);
/* the fill transparent areas toggle */
widget = pika_prop_check_button_new (config, "fill-transparent",
_("Detect opacity rather than grayscale"));
options->priv->line_art_detect_opacity = widget;
gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
/* Line Art: stroke threshold */
scale = pika_prop_spin_scale_new (config, "line-art-threshold",
0.05, 0.1, 2);
gtk_box_pack_start (GTK_BOX (box2), scale, FALSE, FALSE, 0);
/* Line Art Closure frame */
frame = pika_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (options->priv->line_art_settings), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Line Art Closure: frame label */
widget = gtk_label_new (_("Line Art Closure"));
gtk_frame_set_label_widget (GTK_FRAME (frame), widget);
gtk_widget_show (widget);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), box2);
gtk_widget_show (box2);
/* Line Art Closure: max gap length */
scale = pika_prop_spin_scale_new (config, "line-art-max-gap-length",
1, 5, 0);
frame = pika_prop_expanding_frame_new (config, "line-art-automatic-closure", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
/* Line Art Closure: manual line art closure */
scale = pika_prop_spin_scale_new (config, "fill-color-as-line-art-threshold",
1.0, 16.0, 1);
frame = pika_prop_expanding_frame_new (config, "fill-color-as-line-art", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
options->priv->fill_as_line_art_frame = frame;
/* Line Art Borders frame */
frame = pika_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (options->priv->line_art_settings), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Line Art Borders: frame label */
widget = gtk_label_new (_("Fill borders"));
gtk_frame_set_label_widget (GTK_FRAME (frame), widget);
gtk_widget_show (widget);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), box2);
gtk_widget_show (box2);
/* Line Art Borders: max growing size */
scale = pika_prop_spin_scale_new (config, "line-art-max-grow",
1, 5, 0);
gtk_box_pack_start (GTK_BOX (box2), scale, FALSE, FALSE, 0);
/* Line Art Borders: feather radius scale */
scale = pika_prop_spin_scale_new (config, "feather-radius",
1.0, 10.0, 1);
frame = pika_prop_expanding_frame_new (config, "feather", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
/* Line Art Borders: stroke border with paint brush */
options->stroke_options = pika_stroke_options_new (pika,
pika_get_user_context (pika),
TRUE);
pika_config_sync (G_OBJECT (PIKA_DIALOG_CONFIG (pika->config)->stroke_options),
G_OBJECT (options->stroke_options), 0);
widget = pika_container_combo_box_new (pika->paint_info_list,
PIKA_CONTEXT (options->stroke_options),
16, 0);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (widget),
PIKA_CONTAINER_COMBO_BOX (widget)->viewable_renderer,
pika_bucket_fill_options_tool_cell_renderer,
options, NULL);
g_signal_connect (widget, "select-items",
G_CALLBACK (pika_bucket_fill_options_select_stroke_tool),
options);
frame = pika_prop_expanding_frame_new (config, "line-art-stroke-border", NULL,
widget, NULL);
gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
gtk_widget_show (widget);
pika_bucket_fill_options_update_area (options);
g_signal_connect (pika_get_user_context (PIKA_CONTEXT (tool_options)->pika),
"image-changed",
G_CALLBACK (pika_bucket_fill_options_image_changed),
tool_options);
return vbox;
}

View File

@ -0,0 +1,81 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_BUCKET_FILL_OPTIONS_H__
#define __PIKA_BUCKET_FILL_OPTIONS_H__
#include "paint/pikapaintoptions.h"
#define PIKA_TYPE_BUCKET_FILL_OPTIONS (pika_bucket_fill_options_get_type ())
#define PIKA_BUCKET_FILL_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BUCKET_FILL_OPTIONS, PikaBucketFillOptions))
#define PIKA_BUCKET_FILL_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BUCKET_FILL_OPTIONS, PikaBucketFillOptionsClass))
#define PIKA_IS_BUCKET_FILL_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BUCKET_FILL_OPTIONS))
#define PIKA_IS_BUCKET_FILL_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BUCKET_FILL_OPTIONS))
#define PIKA_BUCKET_FILL_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BUCKET_FILL_OPTIONS, PikaBucketFillOptionsClass))
typedef struct _PikaBucketFillOptions PikaBucketFillOptions;
typedef struct _PikaBucketFillOptionsPrivate PikaBucketFillOptionsPrivate;
typedef struct _PikaPaintOptionsClass PikaBucketFillOptionsClass;
struct _PikaBucketFillOptions
{
PikaPaintOptions paint_options;
PikaBucketFillMode fill_mode;
PikaBucketFillArea fill_area;
gboolean fill_transparent;
gboolean sample_merged;
gboolean diagonal_neighbors;
gboolean antialias;
gboolean feather;
gdouble feather_radius;
gdouble threshold;
GtkWidget *line_art_busy_box;
PikaLineArtSource line_art_source;
gdouble line_art_threshold;
gint line_art_max_grow;
gboolean line_art_automatic_closure;
gint line_art_max_gap_length;
gboolean line_art_stroke;
gchar *line_art_stroke_tool;
PikaStrokeOptions *stroke_options;
gboolean fill_as_line_art;
gdouble fill_as_line_art_threshold;
PikaSelectCriterion fill_criterion;
PikaBucketFillOptionsPrivate *priv;
};
GType pika_bucket_fill_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_bucket_fill_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_BUCKET_FILL_OPTIONS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_BUCKET_FILL_TOOL_H__
#define __PIKA_BUCKET_FILL_TOOL_H__
#include "pikacolortool.h"
#define PIKA_TYPE_BUCKET_FILL_TOOL (pika_bucket_fill_tool_get_type ())
#define PIKA_BUCKET_FILL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BUCKET_FILL_TOOL, PikaBucketFillTool))
#define PIKA_BUCKET_FILL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BUCKET_FILL_TOOL, PikaBucketFillToolClass))
#define PIKA_IS_BUCKET_FILL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BUCKET_FILL_TOOL))
#define PIKA_IS_BUCKET_FILL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BUCKET_FILL_TOOL))
#define PIKA_BUCKET_FILL_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BUCKET_FILL_TOOL, PikaBucketFillToolClass))
#define PIKA_BUCKET_FILL_TOOL_GET_OPTIONS(t) (PIKA_BUCKET_FILL_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaBucketFillTool PikaBucketFillTool;
typedef struct _PikaBucketFillToolClass PikaBucketFillToolClass;
typedef struct _PikaBucketFillToolPrivate PikaBucketFillToolPrivate;
struct _PikaBucketFillTool
{
PikaColorTool parent_instance;
PikaBucketFillToolPrivate *priv;
};
struct _PikaBucketFillToolClass
{
PikaColorToolClass parent_class;
};
void pika_bucket_fill_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_bucket_fill_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_BUCKET_FILL_TOOL_H__ */

View File

@ -0,0 +1,167 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikabycolorselecttool.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikaimage.h"
#include "core/pikaimage-new.h"
#include "core/pikaitem.h"
#include "core/pikapickable.h"
#include "core/pikapickable-contiguous-region.h"
#include "widgets/pikahelp-ids.h"
#include "display/pikadisplay.h"
#include "pikabycolorselecttool.h"
#include "pikaregionselectoptions.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static GeglBuffer * pika_by_color_select_tool_get_mask (PikaRegionSelectTool *region_select,
PikaDisplay *display);
G_DEFINE_TYPE (PikaByColorSelectTool, pika_by_color_select_tool,
PIKA_TYPE_REGION_SELECT_TOOL)
#define parent_class pika_by_color_select_tool_parent_class
void
pika_by_color_select_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_BY_COLOR_SELECT_TOOL,
PIKA_TYPE_REGION_SELECT_OPTIONS,
pika_region_select_options_gui,
0,
"pika-by-color-select-tool",
_("Select by Color"),
_("Select by Color Tool: Select regions with similar colors"),
N_("_By Color Select"), "<shift>O",
NULL, PIKA_HELP_TOOL_BY_COLOR_SELECT,
PIKA_ICON_TOOL_BY_COLOR_SELECT,
data);
}
static void
pika_by_color_select_tool_class_init (PikaByColorSelectToolClass *klass)
{
PikaRegionSelectToolClass *region_class;
region_class = PIKA_REGION_SELECT_TOOL_CLASS (klass);
region_class->undo_desc = C_("command", "Select by Color");
region_class->get_mask = pika_by_color_select_tool_get_mask;
}
static void
pika_by_color_select_tool_init (PikaByColorSelectTool *by_color_select)
{
PikaTool *tool = PIKA_TOOL (by_color_select);
pika_tool_control_set_tool_cursor (tool->control, PIKA_TOOL_CURSOR_HAND);
}
static GeglBuffer *
pika_by_color_select_tool_get_mask (PikaRegionSelectTool *region_select,
PikaDisplay *display)
{
PikaTool *tool = PIKA_TOOL (region_select);
PikaSelectionOptions *sel_options = PIKA_SELECTION_TOOL_GET_OPTIONS (tool);
PikaRegionSelectOptions *options = PIKA_REGION_SELECT_TOOL_GET_OPTIONS (tool);
PikaImage *image = pika_display_get_image (display);
PikaImage *select_image = NULL;
GList *drawables = pika_image_get_selected_drawables (image);
PikaPickable *pickable;
GeglBuffer *mask = NULL;
PikaRGB srgb;
gint x, y;
x = region_select->x;
y = region_select->y;
if (! options->sample_merged)
{
if (g_list_length (drawables) == 1)
{
gint off_x, off_y;
pika_item_get_offset (drawables->data, &off_x, &off_y);
x -= off_x;
y -= off_y;
pickable = PIKA_PICKABLE (drawables->data);
}
else
{
select_image = pika_image_new_from_drawables (image->pika, drawables, FALSE, FALSE);
pika_container_remove (image->pika->images, PIKA_OBJECT (select_image));
pickable = PIKA_PICKABLE (select_image);
pika_pickable_flush (pickable);
}
}
else
{
pickable = PIKA_PICKABLE (image);
}
g_list_free (drawables);
pika_pickable_flush (pickable);
if (pika_pickable_get_color_at (pickable, x, y, &srgb))
{
PikaRGB color;
pika_pickable_srgb_to_image_color (pickable, &srgb, &color);
mask = pika_pickable_contiguous_region_by_color (pickable,
sel_options->antialias,
options->threshold / 255.0,
options->select_transparent,
options->select_criterion,
&color);
}
if (select_image)
g_object_unref (select_image);
return mask;
}

View File

@ -0,0 +1,59 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikabycolorselectool.h
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_BY_COLOR_SELECT_TOOL_H__
#define __PIKA_BY_COLOR_SELECT_TOOL_H__
#include "pikaregionselecttool.h"
#define PIKA_TYPE_BY_COLOR_SELECT_TOOL (pika_by_color_select_tool_get_type ())
#define PIKA_BY_COLOR_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BY_COLOR_SELECT_TOOL, PikaByColorSelectTool))
#define PIKA_BY_COLOR_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BY_COLOR_SELECT_TOOL, PikaByColorSelectToolClass))
#define PIKA_IS_BY_COLOR_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BY_COLOR_SELECT_TOOL))
#define PIKA_IS_BY_COLOR_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BY_COLOR_SELECT_TOOL))
#define PIKA_BY_COLOR_SELECT_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BY_COLOR_SELECT_TOOL, PikaByColorSelectToolClass))
typedef struct _PikaByColorSelectTool PikaByColorSelectTool;
typedef struct _PikaByColorSelectToolClass PikaByColorSelectToolClass;
struct _PikaByColorSelectTool
{
PikaRegionSelectTool parent_instance;
};
struct _PikaByColorSelectToolClass
{
PikaRegionSelectToolClass parent_class;
};
void pika_by_color_select_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_by_color_select_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_BY_COLOR_SELECT_TOOL_H__ */

155
app/tools/pikacageoptions.c Normal file
View File

@ -0,0 +1,155 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
*
* pikacageoptions.c
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "pikacageoptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_CAGE_MODE,
PROP_FILL_PLAIN_COLOR
};
static void pika_cage_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_cage_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaCageOptions, pika_cage_options,
PIKA_TYPE_TOOL_OPTIONS)
#define parent_class pika_cage_options_parent_class
static void
pika_cage_options_class_init (PikaCageOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_cage_options_set_property;
object_class->get_property = pika_cage_options_get_property;
PIKA_CONFIG_PROP_ENUM (object_class, PROP_CAGE_MODE,
"cage-mode",
NULL, NULL,
PIKA_TYPE_CAGE_MODE,
PIKA_CAGE_MODE_CAGE_CHANGE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_FILL_PLAIN_COLOR,
"fill-plain-color",
_("Fill the original position\n"
"of the cage with a color"),
NULL,
FALSE,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_cage_options_init (PikaCageOptions *options)
{
}
static void
pika_cage_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaCageOptions *options = PIKA_CAGE_OPTIONS (object);
switch (property_id)
{
case PROP_CAGE_MODE:
options->cage_mode = g_value_get_enum (value);
break;
case PROP_FILL_PLAIN_COLOR:
options->fill_plain_color = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_cage_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaCageOptions *options = PIKA_CAGE_OPTIONS (object);
switch (property_id)
{
case PROP_CAGE_MODE:
g_value_set_enum (value, options->cage_mode);
break;
case PROP_FILL_PLAIN_COLOR:
g_value_set_boolean (value, options->fill_plain_color);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
pika_cage_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_tool_options_gui (tool_options);
GtkWidget *mode;
GtkWidget *button;
mode = pika_prop_enum_radio_box_new (config, "cage-mode", 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), mode, FALSE, FALSE, 0);
button = pika_prop_check_button_new (config, "fill-plain-color", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
return vbox;
}

View File

@ -0,0 +1,61 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
*
* pikacageoptions.h
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CAGE_OPTIONS_H__
#define __PIKA_CAGE_OPTIONS_H__
#include "core/pikatooloptions.h"
#define PIKA_TYPE_CAGE_OPTIONS (pika_cage_options_get_type ())
#define PIKA_CAGE_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CAGE_OPTIONS, PikaCageOptions))
#define PIKA_CAGE_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CAGE_OPTIONS, PikaCageOptionsClass))
#define PIKA_IS_CAGE_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CAGE_OPTIONS))
#define PIKA_IS_CAGE_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CAGE_OPTIONS))
#define PIKA_CAGE_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CAGE_OPTIONS, PikaCageOptionsClass))
typedef struct _PikaCageOptions PikaCageOptions;
typedef struct _PikaCageOptionsClass PikaCageOptionsClass;
struct _PikaCageOptions
{
PikaToolOptions parent_instance;
PikaCageMode cage_mode;
gboolean fill_plain_color;
};
struct _PikaCageOptionsClass
{
PikaToolOptionsClass parent_class;
};
GType pika_cage_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_cage_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_CAGE_OPTIONS_H__ */

1325
app/tools/pikacagetool.c Normal file

File diff suppressed because it is too large Load Diff

89
app/tools/pikacagetool.h Normal file
View File

@ -0,0 +1,89 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
*
* pikacagetool.h
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CAGE_TOOL_H__
#define __PIKA_CAGE_TOOL_H__
#include "pikadrawtool.h"
#define PIKA_TYPE_CAGE_TOOL (pika_cage_tool_get_type ())
#define PIKA_CAGE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CAGE_TOOL, PikaCageTool))
#define PIKA_CAGE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CAGE_TOOL, PikaCageToolClass))
#define PIKA_IS_CAGE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CAGE_TOOL))
#define PIKA_IS_CAGE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CAGE_TOOL))
#define PIKA_CAGE_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CAGE_TOOL, PikaCageToolClass))
#define PIKA_CAGE_TOOL_GET_OPTIONS(t) (PIKA_CAGE_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaCageTool PikaCageTool;
typedef struct _PikaCageToolClass PikaCageToolClass;
struct _PikaCageTool
{
PikaDrawTool parent_instance;
PikaCageConfig *config;
gint offset_x; /* used to convert the cage point coords */
gint offset_y; /* to drawable coords */
gdouble cursor_x; /* Hold the cursor x position */
gdouble cursor_y; /* Hold the cursor y position */
gdouble movement_start_x; /* Where the movement started */
gdouble movement_start_y; /* Where the movement started */
gdouble selection_start_x; /* Where the selection started */
gdouble selection_start_y; /* Where the selection started */
gint hovering_handle; /* Handle which the cursor is above */
gint hovering_edge; /* Edge which the cursor is above */
GeglBuffer *coef; /* Gegl buffer where the coefficient of the transformation are stored */
gboolean dirty_coef; /* Indicate if the coef are still valid */
GeglNode *render_node; /* Gegl node graph to render the transformation */
GeglNode *cage_node; /* Gegl node that compute the cage transform */
GeglNode *coef_node; /* Gegl node that read in the coef buffer */
gint tool_state; /* Current state in statemachine */
PikaDrawableFilter *filter; /* For preview */
};
struct _PikaCageToolClass
{
PikaDrawToolClass parent_class;
};
void pika_cage_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_cage_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_CAGE_TOOL_H__ */

View File

@ -0,0 +1,320 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikaimage.h"
#include "core/pikaitem.h"
#include "paint/pikacloneoptions.h"
#include "widgets/pikaviewablebox.h"
#include "widgets/pikawidgets-utils.h"
#include "pikacloneoptions-gui.h"
#include "pikapaintoptions-gui.h"
#include "pika-intl.h"
static gboolean pika_clone_options_sync_source (GBinding *binding,
const GValue *source_value,
GValue *target_value,
gpointer user_data);
static void pika_clone_options_gui_drawables_changed (PikaImage *image,
PikaSourceOptions *options);
static void pika_clone_options_gui_src_changed (PikaSourceOptions *options,
GParamSpec *pspec,
GtkWidget *label);
static void pika_clone_options_gui_context_image_changed (PikaContext *context,
PikaImage *image,
PikaSourceOptions *options);
static gboolean pika_clone_options_gui_update_src_label (PikaSourceOptions *options);
static gboolean
pika_clone_options_sync_source (GBinding *binding,
const GValue *source_value,
GValue *target_value,
gpointer user_data)
{
PikaCloneType type = g_value_get_enum (source_value);
g_value_set_boolean (target_value,
type == GPOINTER_TO_INT (user_data));
return TRUE;
}
static void
pika_clone_options_gui_drawables_changed (PikaImage *image,
PikaSourceOptions *options)
{
GList *drawables;
GtkWidget *button;
drawables = pika_image_get_selected_drawables (image);
button = g_object_get_data (G_OBJECT (options), "sample-merged-checkbox");
gtk_widget_set_sensitive (button, (g_list_length (drawables) < 2));
g_list_free (drawables);
/* In case this was called several times in a row by threads. */
g_idle_remove_by_data (options);
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc) pika_clone_options_gui_update_src_label,
g_object_ref (options), (GDestroyNotify) g_object_unref);
}
static void
pika_clone_options_gui_src_changed (PikaSourceOptions *options,
GParamSpec *pspec,
GtkWidget *label)
{
/* In case this was called several times in a row by threads. */
g_idle_remove_by_data (options);
/* Why we need absolutely to run this in a thread is that it updates
* the GUI. And sometimes this src_changed callback may be called by
* paint threads (see pikapainttool-paint.c). This may cause crashes
* as in recent GTK, all GTK/GDK calls should be main from the main
* thread. Idle functions are ensured to be run in this main thread.
*/
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc) pika_clone_options_gui_update_src_label,
g_object_ref (options), (GDestroyNotify) g_object_unref);
}
static void
pika_clone_options_gui_context_image_changed (PikaContext *context,
PikaImage *image,
PikaSourceOptions *options)
{
PikaImage *prev_image;
GtkWidget *button;
button = g_object_get_data (G_OBJECT (options), "sample-merged-checkbox");
prev_image = g_object_get_data (G_OBJECT (button), "pika-clone-options-gui-image");
if (image != prev_image)
{
if (prev_image)
g_signal_handlers_disconnect_by_func (prev_image,
G_CALLBACK (pika_clone_options_gui_drawables_changed),
options);
if (image)
{
g_signal_connect_object (image, "selected-channels-changed",
G_CALLBACK (pika_clone_options_gui_drawables_changed),
options, 0);
g_signal_connect_object (image, "selected-layers-changed",
G_CALLBACK (pika_clone_options_gui_drawables_changed),
options, 0);
pika_clone_options_gui_drawables_changed (image, options);
}
else
{
gtk_widget_set_sensitive (button, TRUE);
}
g_object_set_data (G_OBJECT (button), "pika-clone-options-gui-image", image);
}
}
static gboolean
pika_clone_options_gui_update_src_label (PikaSourceOptions *options)
{
GtkWidget *label;
gchar *markup = NULL;
label = g_object_get_data (G_OBJECT (options), "src-label");
if (options->src_drawables == NULL)
{
markup = g_strdup_printf ("<i>%s</i>", _("No source selected"));
}
else
{
PikaImage *image;
GList *drawables;
gchar *str = NULL;
gboolean sample_merged;
image = pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika));
drawables = pika_image_get_selected_drawables (image);
sample_merged = options->sample_merged && g_list_length (drawables) == 1;
if (g_list_length (drawables) > 1)
{
str = g_strdup_printf (ngettext ("Source: %d item to itself",
"Source: %d items to themselves",
g_list_length (drawables)),
g_list_length (drawables));
}
else
{
PikaImage *src_image = NULL;
src_image = pika_item_get_image (options->src_drawables->data);
if (sample_merged)
{
if (image == src_image)
str = g_strdup (_("All composited visible layers"));
else
str = g_strdup_printf (_("All composited visible layers from '%s'"),
pika_image_get_display_name (src_image));
}
else
{
if (image == src_image)
str = g_strdup_printf (ngettext ("Source: %d item",
"Source: %d items",
g_list_length (options->src_drawables)),
g_list_length (options->src_drawables));
else
str = g_strdup_printf (ngettext ("Source: %d item from '%s'",
"Source: %d items from '%s'",
g_list_length (options->src_drawables)),
g_list_length (options->src_drawables),
pika_image_get_display_name (src_image));
}
}
markup = g_strdup_printf ("<i>%s</i>", str);
g_list_free (drawables);
g_free (str);
}
gtk_label_set_markup (GTK_LABEL (label), markup);
g_free (markup);
return G_SOURCE_REMOVE;
}
/* Public functions. */
GtkWidget *
pika_clone_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *frame;
GtkWidget *label;
GtkWidget *combo;
GtkWidget *source_vbox;
GtkWidget *button;
GtkWidget *hbox;
gchar *str;
/* the source frame */
frame = pika_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (vbox), frame, 2);
gtk_widget_show (frame);
/* the source type menu */
combo = pika_prop_enum_combo_box_new (config, "clone-type", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Source"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_frame_set_label_widget (GTK_FRAME (frame), combo);
source_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), source_vbox);
gtk_widget_show (source_vbox);
button = pika_prop_check_button_new (config, "sample-merged", NULL);
g_object_set_data (G_OBJECT (tool_options), "sample-merged-checkbox", button);
gtk_box_pack_start (GTK_BOX (source_vbox), button, FALSE, FALSE, 0);
g_object_bind_property_full (config, "clone-type",
button, "visible",
G_BINDING_SYNC_CREATE,
pika_clone_options_sync_source,
NULL,
GINT_TO_POINTER (PIKA_CLONE_IMAGE), NULL);
label = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
str = g_strdup_printf ("<i>%s</i>", _("No source selected"));
gtk_label_set_markup (GTK_LABEL (label), str);
g_object_set_data_full (G_OBJECT (tool_options), "src-label",
g_object_ref (label),
(GDestroyNotify) g_object_unref);
g_free (str);
gtk_box_pack_start (GTK_BOX (source_vbox), label, FALSE, FALSE, 0);
g_object_bind_property_full (config, "clone-type",
label, "visible",
G_BINDING_SYNC_CREATE,
pika_clone_options_sync_source,
NULL,
GINT_TO_POINTER (PIKA_CLONE_IMAGE), NULL);
g_signal_connect (pika_get_user_context (PIKA_CONTEXT (tool_options)->pika),
"image-changed",
G_CALLBACK (pika_clone_options_gui_context_image_changed),
tool_options);
hbox = pika_prop_pattern_box_new (NULL, PIKA_CONTEXT (tool_options),
NULL, 2,
"pattern-view-type", "pattern-view-size");
gtk_box_pack_start (GTK_BOX (source_vbox), hbox, FALSE, FALSE, 0);
g_object_bind_property_full (config, "clone-type",
hbox, "visible",
G_BINDING_SYNC_CREATE,
pika_clone_options_sync_source,
NULL,
GINT_TO_POINTER (PIKA_CLONE_PATTERN), NULL);
combo = pika_prop_enum_combo_box_new (config, "align-mode", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Alignment"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (vbox), combo, TRUE, TRUE, 0);
gtk_box_reorder_child (GTK_BOX (vbox), combo, 3);
/* A few options which can trigger a change in the source label. */
g_signal_connect (config, "notify::src-drawables",
G_CALLBACK (pika_clone_options_gui_src_changed),
label);
g_signal_connect (config, "notify::sample-merged",
G_CALLBACK (pika_clone_options_gui_src_changed),
label);
pika_clone_options_gui_src_changed (PIKA_SOURCE_OPTIONS (config), NULL, label);
return vbox;
}

View File

@ -0,0 +1,29 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CLONE_OPTIONS_GUI_H__
#define __PIKA_CLONE_OPTIONS_GUI_H__
GtkWidget * pika_clone_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_CLONE_OPTIONS_GUI_H__ */

112
app/tools/pikaclonetool.c Normal file
View File

@ -0,0 +1,112 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "operations/layer-modes/pika-layer-modes.h"
#include "paint/pikaclone.h"
#include "paint/pikacloneoptions.h"
#include "widgets/pikahelp-ids.h"
#include "display/pikadisplay.h"
#include "pikaclonetool.h"
#include "pikacloneoptions-gui.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static gboolean pika_clone_tool_is_alpha_only (PikaPaintTool *paint_tool,
PikaDrawable *drawable);
G_DEFINE_TYPE (PikaCloneTool, pika_clone_tool, PIKA_TYPE_SOURCE_TOOL)
#define parent_class pika_clone_tool_parent_class
void
pika_clone_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_CLONE_TOOL,
PIKA_TYPE_CLONE_OPTIONS,
pika_clone_options_gui,
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
PIKA_CONTEXT_PROP_MASK_PATTERN,
"pika-clone-tool",
_("Clone"),
_("Clone Tool: Selectively copy from an image or pattern, using a brush"),
N_("_Clone"), "C",
NULL, PIKA_HELP_TOOL_CLONE,
PIKA_ICON_TOOL_CLONE,
data);
}
static void
pika_clone_tool_class_init (PikaCloneToolClass *klass)
{
PikaPaintToolClass *paint_tool_class = PIKA_PAINT_TOOL_CLASS (klass);
paint_tool_class->is_alpha_only = pika_clone_tool_is_alpha_only;
}
static void
pika_clone_tool_init (PikaCloneTool *clone)
{
PikaTool *tool = PIKA_TOOL (clone);
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (tool);
PikaSourceTool *source_tool = PIKA_SOURCE_TOOL (tool);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_CLONE);
pika_tool_control_set_action_object_2 (tool->control,
"context-pattern-select-set");
paint_tool->status = _("Click to clone");
paint_tool->status_ctrl = _("%s to set a new clone source");
source_tool->status_paint = _("Click to clone");
/* Translators: the translation of "Click" must be the first word */
source_tool->status_set_source = _("Click to set a new clone source");
source_tool->status_set_source_ctrl = _("%s to set a new clone source");
}
static gboolean
pika_clone_tool_is_alpha_only (PikaPaintTool *paint_tool,
PikaDrawable *drawable)
{
PikaPaintOptions *paint_options = PIKA_PAINT_TOOL_GET_OPTIONS (paint_tool);
PikaContext *context = PIKA_CONTEXT (paint_options);
PikaLayerMode paint_mode = pika_context_get_paint_mode (context);
return pika_layer_mode_is_alpha_only (paint_mode);
}

57
app/tools/pikaclonetool.h Normal file
View File

@ -0,0 +1,57 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CLONE_TOOL_H__
#define __PIKA_CLONE_TOOL_H__
#include "pikasourcetool.h"
#define PIKA_TYPE_CLONE_TOOL (pika_clone_tool_get_type ())
#define PIKA_CLONE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CLONE_TOOL, PikaCloneTool))
#define PIKA_CLONE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CLONE_TOOL, PikaCloneToolClass))
#define PIKA_IS_CLONE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CLONE_TOOL))
#define PIKA_IS_CLONE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CLONE_TOOL))
#define PIKA_CLONE_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CLONE_TOOL, PikaCloneToolClass))
typedef struct _PikaCloneTool PikaCloneTool;
typedef struct _PikaCloneToolClass PikaCloneToolClass;
struct _PikaCloneTool
{
PikaSourceTool parent_instance;
};
struct _PikaCloneToolClass
{
PikaSourceToolClass parent_class;
};
void pika_clone_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_clone_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_CLONE_TOOL_H__ */

View File

@ -0,0 +1,173 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikapropwidgets.h"
#include "pikacoloroptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_SAMPLE_MERGED,
PROP_SAMPLE_AVERAGE,
PROP_AVERAGE_RADIUS
};
static void pika_color_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaColorOptions, pika_color_options,
PIKA_TYPE_TOOL_OPTIONS)
static void
pika_color_options_class_init (PikaColorOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_color_options_set_property;
object_class->get_property = pika_color_options_get_property;
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_SAMPLE_MERGED,
"sample-merged",
_("Sample merged"),
_("Use merged color value from "
"all composited visible layers"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_SAMPLE_AVERAGE,
"sample-average",
_("Sample average"),
_("Use averaged color value from "
"nearby pixels"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_AVERAGE_RADIUS,
"average-radius",
_("Radius"),
_("Color Picker Average Radius"),
1.0, 300.0, 3.0,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_color_options_init (PikaColorOptions *options)
{
}
static void
pika_color_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorOptions *options = PIKA_COLOR_OPTIONS (object);
switch (property_id)
{
case PROP_SAMPLE_MERGED:
options->sample_merged = g_value_get_boolean (value);
break;
case PROP_SAMPLE_AVERAGE:
options->sample_average = g_value_get_boolean (value);
break;
case PROP_AVERAGE_RADIUS:
options->average_radius = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorOptions *options = PIKA_COLOR_OPTIONS (object);
switch (property_id)
{
case PROP_SAMPLE_MERGED:
g_value_set_boolean (value, options->sample_merged);
break;
case PROP_SAMPLE_AVERAGE:
g_value_set_boolean (value, options->sample_average);
break;
case PROP_AVERAGE_RADIUS:
g_value_set_double (value, options->average_radius);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
pika_color_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_tool_options_gui (tool_options);
GtkWidget *button;
GtkWidget *frame;
GtkWidget *scale;
/* the sample average options */
scale = pika_prop_spin_scale_new (config, "average-radius",
1.0, 10.0, 0);
frame = pika_prop_expanding_frame_new (config, "sample-average", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
/* The Sample merged checkbox. */
button = pika_prop_check_button_new (config, "sample-merged", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
return vbox;
}

View File

@ -0,0 +1,59 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_OPTIONS_H__
#define __PIKA_COLOR_OPTIONS_H__
#include "core/pikatooloptions.h"
#define PIKA_TYPE_COLOR_OPTIONS (pika_color_options_get_type ())
#define PIKA_COLOR_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_OPTIONS, PikaColorOptions))
#define PIKA_COLOR_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_OPTIONS, PikaColorOptionsClass))
#define PIKA_IS_COLOR_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_OPTIONS))
#define PIKA_IS_COLOR_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_OPTIONS))
#define PIKA_COLOR_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_OPTIONS, PikaColorOptionsClass))
typedef struct _PikaColorOptionsClass PikaColorOptionsClass;
struct _PikaColorOptions
{
PikaToolOptions parent_instance;
gboolean sample_merged;
gboolean sample_average;
gdouble average_radius;
};
struct _PikaColorOptionsClass
{
PikaToolOptionsClass parent_instance;
};
GType pika_color_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_COLOR_OPTIONS_H__ */

View File

@ -0,0 +1,209 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikawidgets-utils.h"
#include "pikacolorpickeroptions.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_SAMPLE_AVERAGE, /* overrides a PikaColorOptions property */
PROP_PICK_TARGET,
PROP_USE_INFO_WINDOW,
PROP_FRAME1_MODE,
PROP_FRAME2_MODE
};
static void pika_color_picker_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_picker_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaColorPickerOptions, pika_color_picker_options,
PIKA_TYPE_COLOR_OPTIONS)
static void
pika_color_picker_options_class_init (PikaColorPickerOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_color_picker_options_set_property;
object_class->get_property = pika_color_picker_options_get_property;
/* override a PikaColorOptions property to get a different default value */
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_SAMPLE_AVERAGE,
"sample-average",
_("Sample average"),
_("Use averaged color value from "
"nearby pixels"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_PICK_TARGET,
"pick-target",
_("Pick Target"),
_("Choose what the color picker will do"),
PIKA_TYPE_COLOR_PICK_TARGET,
PIKA_COLOR_PICK_TARGET_FOREGROUND,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_USE_INFO_WINDOW,
"use-info-window",
_("Use info window"),
_("Open a floating dialog to view picked "
"color values in various color models"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FRAME1_MODE,
"frame1-mode",
"Frame 1 Mode", NULL,
PIKA_TYPE_COLOR_PICK_MODE,
PIKA_COLOR_PICK_MODE_PIXEL,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FRAME2_MODE,
"frame2-mode",
"Frame 2 Mode", NULL,
PIKA_TYPE_COLOR_PICK_MODE,
PIKA_COLOR_PICK_MODE_RGB_PERCENT,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_color_picker_options_init (PikaColorPickerOptions *options)
{
}
static void
pika_color_picker_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorPickerOptions *options = PIKA_COLOR_PICKER_OPTIONS (object);
switch (property_id)
{
case PROP_SAMPLE_AVERAGE:
PIKA_COLOR_OPTIONS (options)->sample_average = g_value_get_boolean (value);
break;
case PROP_PICK_TARGET:
options->pick_target = g_value_get_enum (value);
break;
case PROP_USE_INFO_WINDOW:
options->use_info_window = g_value_get_boolean (value);
break;
case PROP_FRAME1_MODE:
options->frame1_mode = g_value_get_enum (value);
break;
case PROP_FRAME2_MODE:
options->frame2_mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_picker_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorPickerOptions *options = PIKA_COLOR_PICKER_OPTIONS (object);
switch (property_id)
{
case PROP_SAMPLE_AVERAGE:
g_value_set_boolean (value,
PIKA_COLOR_OPTIONS (options)->sample_average);
break;
case PROP_PICK_TARGET:
g_value_set_enum (value, options->pick_target);
break;
case PROP_USE_INFO_WINDOW:
g_value_set_boolean (value, options->use_info_window);
break;
case PROP_FRAME1_MODE:
g_value_set_enum (value, options->frame1_mode);
break;
case PROP_FRAME2_MODE:
g_value_set_enum (value, options->frame2_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
pika_color_picker_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_color_options_gui (tool_options);
GtkWidget *button;
GtkWidget *frame;
gchar *str;
GdkModifierType extend_mask = pika_get_extend_selection_mask ();
GdkModifierType toggle_mask = pika_get_toggle_behavior_mask ();
/* the pick FG/BG frame */
str = g_strdup_printf (_("Pick Target (%s)"),
pika_get_mod_string (toggle_mask));
frame = pika_prop_enum_radio_frame_new (config, "pick-target", str, -1, -1);
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
g_free (str);
/* the use_info_window toggle button */
str = g_strdup_printf (_("Use info window (%s)"),
pika_get_mod_string (extend_mask));
button = pika_prop_check_button_new (config, "use-info-window", str);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
g_free (str);
return vbox;
}

View File

@ -0,0 +1,56 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_PICKER_OPTIONS_H__
#define __PIKA_COLOR_PICKER_OPTIONS_H__
#include "pikacoloroptions.h"
#define PIKA_TYPE_COLOR_PICKER_OPTIONS (pika_color_picker_options_get_type ())
#define PIKA_COLOR_PICKER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PICKER_OPTIONS, PikaColorPickerOptions))
#define PIKA_COLOR_PICKER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PICKER_OPTIONS, PikaColorPickerOptionsClass))
#define PIKA_IS_COLOR_PICKER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PICKER_OPTIONS))
#define PIKA_IS_COLOR_PICKER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PICKER_OPTIONS))
#define PIKA_COLOR_PICKER_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PICKER_OPTIONS, PikaColorPickerOptionsClass))
typedef struct _PikaColorPickerOptions PikaColorPickerOptions;
typedef struct _PikaToolOptionsClass PikaColorPickerOptionsClass;
struct _PikaColorPickerOptions
{
PikaColorOptions parent_instance;
PikaColorPickTarget pick_target;
gboolean use_info_window;
PikaColorPickMode frame1_mode;
PikaColorPickMode frame2_mode;
};
GType pika_color_picker_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_picker_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_COLOR_PICKER_OPTIONS_H__ */

View File

@ -0,0 +1,461 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "libpikacolor/pikacolor.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pikadrawable.h"
#include "core/pikaimage.h"
#include "core/pikatoolinfo.h"
#include "widgets/pikacolorframe.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"
#include "display/pikadisplay.h"
#include "display/pikatoolgui.h"
#include "pikacolorpickeroptions.h"
#include "pikacolorpickertool.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
/* local function prototypes */
static void pika_color_picker_tool_constructed (GObject *object);
static void pika_color_picker_tool_dispose (GObject *object);
static void pika_color_picker_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display);
static void pika_color_picker_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display);
static void pika_color_picker_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_color_picker_tool_picked (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color);
static void pika_color_picker_tool_info_create (PikaColorPickerTool *picker_tool,
PikaDisplay *display);
static void pika_color_picker_tool_info_response (PikaToolGui *gui,
gint response_id,
PikaColorPickerTool *picker_tool);
static void pika_color_picker_tool_info_update (PikaColorPickerTool *picker_tool,
PikaDisplay *display,
gboolean sample_average,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color,
gint x,
gint y);
G_DEFINE_TYPE (PikaColorPickerTool, pika_color_picker_tool,
PIKA_TYPE_COLOR_TOOL)
#define parent_class pika_color_picker_tool_parent_class
void
pika_color_picker_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_COLOR_PICKER_TOOL,
PIKA_TYPE_COLOR_PICKER_OPTIONS,
pika_color_picker_options_gui,
PIKA_CONTEXT_PROP_MASK_FOREGROUND |
PIKA_CONTEXT_PROP_MASK_BACKGROUND,
"pika-color-picker-tool",
_("Color Picker"),
_("Color Picker Tool: Set colors from image pixels"),
N_("C_olor Picker"), "O",
NULL, PIKA_HELP_TOOL_COLOR_PICKER,
PIKA_ICON_TOOL_COLOR_PICKER,
data);
}
static void
pika_color_picker_tool_class_init (PikaColorPickerToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaColorToolClass *color_tool_class = PIKA_COLOR_TOOL_CLASS (klass);
object_class->constructed = pika_color_picker_tool_constructed;
object_class->dispose = pika_color_picker_tool_dispose;
tool_class->control = pika_color_picker_tool_control;
tool_class->modifier_key = pika_color_picker_tool_modifier_key;
tool_class->oper_update = pika_color_picker_tool_oper_update;
color_tool_class->picked = pika_color_picker_tool_picked;
}
static void
pika_color_picker_tool_init (PikaColorPickerTool *picker_tool)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (picker_tool);
color_tool->pick_target = PIKA_COLOR_PICK_TARGET_FOREGROUND;
}
static void
pika_color_picker_tool_constructed (GObject *object)
{
PikaTool *tool = PIKA_TOOL (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
pika_color_tool_enable (PIKA_COLOR_TOOL (object),
PIKA_COLOR_TOOL_GET_OPTIONS (tool));
}
static void
pika_color_picker_tool_dispose (GObject *object)
{
PikaColorPickerTool *picker_tool = PIKA_COLOR_PICKER_TOOL (object);
g_clear_object (&picker_tool->gui);
picker_tool->color_area = NULL;
picker_tool->color_frame1 = NULL;
picker_tool->color_frame2 = NULL;
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_color_picker_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display)
{
PikaColorPickerTool *picker_tool = PIKA_COLOR_PICKER_TOOL (tool);
switch (action)
{
case PIKA_TOOL_ACTION_PAUSE:
case PIKA_TOOL_ACTION_RESUME:
break;
case PIKA_TOOL_ACTION_HALT:
if (picker_tool->gui)
pika_tool_gui_hide (picker_tool->gui);
break;
case PIKA_TOOL_ACTION_COMMIT:
break;
}
PIKA_TOOL_CLASS (parent_class)->control (tool, action, display);
}
static void
pika_color_picker_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display)
{
PikaColorPickerOptions *options = PIKA_COLOR_PICKER_TOOL_GET_OPTIONS (tool);
if (key == pika_get_extend_selection_mask ())
{
g_object_set (options, "use-info-window", ! options->use_info_window,
NULL);
}
else if (key == pika_get_toggle_behavior_mask ())
{
switch (options->pick_target)
{
case PIKA_COLOR_PICK_TARGET_FOREGROUND:
g_object_set (options,
"pick-target", PIKA_COLOR_PICK_TARGET_BACKGROUND,
NULL);
break;
case PIKA_COLOR_PICK_TARGET_BACKGROUND:
g_object_set (options,
"pick-target", PIKA_COLOR_PICK_TARGET_FOREGROUND,
NULL);
break;
default:
break;
}
}
}
static void
pika_color_picker_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaColorPickerTool *picker_tool = PIKA_COLOR_PICKER_TOOL (tool);
PikaColorPickerOptions *options = PIKA_COLOR_PICKER_TOOL_GET_OPTIONS (tool);
PIKA_COLOR_TOOL (tool)->pick_target = options->pick_target;
pika_tool_pop_status (tool, display);
if (proximity)
{
gchar *status_help = NULL;
GdkModifierType extend_mask = 0;
GdkModifierType toggle_mask;
if (! picker_tool->gui)
extend_mask = pika_get_extend_selection_mask ();
toggle_mask = pika_get_toggle_behavior_mask ();
switch (options->pick_target)
{
case PIKA_COLOR_PICK_TARGET_NONE:
status_help = pika_suggest_modifiers (_("Click in any image to view"
" its color"),
extend_mask & ~state,
NULL, NULL, NULL);
break;
case PIKA_COLOR_PICK_TARGET_FOREGROUND:
status_help = pika_suggest_modifiers (_("Click in any image to pick"
" the foreground color"),
(extend_mask | toggle_mask) &
~state,
NULL, NULL, NULL);
break;
case PIKA_COLOR_PICK_TARGET_BACKGROUND:
status_help = pika_suggest_modifiers (_("Click in any image to pick"
" the background color"),
(extend_mask | toggle_mask) &
~state,
NULL, NULL, NULL);
break;
case PIKA_COLOR_PICK_TARGET_PALETTE:
status_help = pika_suggest_modifiers (_("Click in any image to add"
" the color to the palette"),
extend_mask & ~state,
NULL, NULL, NULL);
break;
}
if (status_help != NULL)
{
pika_tool_push_status (tool, display, "%s", status_help);
g_free (status_help);
}
}
PIKA_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
display);
}
static void
pika_color_picker_tool_picked (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color)
{
PikaColorPickerTool *picker_tool = PIKA_COLOR_PICKER_TOOL (color_tool);
PikaColorPickerOptions *options;
options = PIKA_COLOR_PICKER_TOOL_GET_OPTIONS (color_tool);
if (options->use_info_window && ! picker_tool->gui)
pika_color_picker_tool_info_create (picker_tool, display);
if (picker_tool->gui &&
(options->use_info_window ||
pika_tool_gui_get_visible (picker_tool->gui)))
{
pika_color_picker_tool_info_update (picker_tool, display,
PIKA_COLOR_OPTIONS (options)->sample_average,
sample_format, pixel, color,
(gint) floor (coords->x),
(gint) floor (coords->y));
}
PIKA_COLOR_TOOL_CLASS (parent_class)->picked (color_tool,
coords, display, pick_state,
sample_format, pixel, color);
}
static void
pika_color_picker_tool_info_create (PikaColorPickerTool *picker_tool,
PikaDisplay *display)
{
Pika *pika = pika_display_get_pika (display);
PikaTool *tool = PIKA_TOOL (picker_tool);
PikaToolOptions *options = PIKA_TOOL_GET_OPTIONS (tool);
PikaContext *context = PIKA_CONTEXT (tool->tool_info->tool_options);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
GList *drawables = pika_image_get_selected_drawables (image);
GtkWidget *hbox;
GtkWidget *frame;
PikaRGB color;
picker_tool->gui = pika_tool_gui_new (tool->tool_info,
NULL,
_("Color Picker Information"),
NULL, NULL,
pika_widget_get_monitor (GTK_WIDGET (shell)),
TRUE,
_("_Close"), GTK_RESPONSE_CLOSE,
NULL);
pika_tool_gui_set_auto_overlay (picker_tool->gui, TRUE);
pika_tool_gui_set_focus_on_map (picker_tool->gui, FALSE);
pika_tool_gui_set_viewables (picker_tool->gui, drawables);
g_signal_connect (picker_tool->gui, "response",
G_CALLBACK (pika_color_picker_tool_info_response),
picker_tool);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (pika_tool_gui_get_vbox (picker_tool->gui)),
hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
picker_tool->color_frame1 = pika_color_frame_new (pika);
pika_color_frame_set_color_config (PIKA_COLOR_FRAME (picker_tool->color_frame1),
context->pika->config->color_management);
pika_color_frame_set_has_coords (PIKA_COLOR_FRAME (picker_tool->color_frame1),
TRUE);
g_object_bind_property (options, "frame1-mode",
picker_tool->color_frame1, "mode",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
gtk_box_pack_start (GTK_BOX (hbox), picker_tool->color_frame1,
FALSE, FALSE, 0);
gtk_widget_show (picker_tool->color_frame1);
picker_tool->color_frame2 = pika_color_frame_new (pika);
pika_color_frame_set_color_config (PIKA_COLOR_FRAME (picker_tool->color_frame2),
context->pika->config->color_management);
g_object_bind_property (options, "frame2-mode",
picker_tool->color_frame2, "mode",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
gtk_box_pack_start (GTK_BOX (hbox), picker_tool->color_frame2,
FALSE, FALSE, 0);
gtk_widget_show (picker_tool->color_frame2);
frame = gtk_frame_new (NULL);
pika_widget_set_fully_opaque (frame, TRUE);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
pika_rgba_set (&color, 0.0, 0.0, 0.0, 0.0);
picker_tool->color_area =
pika_color_area_new (&color,
drawables && pika_drawable_has_alpha (drawables->data) ?
PIKA_COLOR_AREA_LARGE_CHECKS :
PIKA_COLOR_AREA_FLAT,
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK);
pika_color_area_set_color_config (PIKA_COLOR_AREA (picker_tool->color_area),
context->pika->config->color_management);
gtk_widget_set_size_request (picker_tool->color_area, 48, -1);
gtk_drag_dest_unset (picker_tool->color_area);
gtk_container_add (GTK_CONTAINER (frame), picker_tool->color_area);
gtk_widget_show (picker_tool->color_area);
g_list_free (drawables);
}
static void
pika_color_picker_tool_info_response (PikaToolGui *gui,
gint response_id,
PikaColorPickerTool *picker_tool)
{
PikaTool *tool = PIKA_TOOL (picker_tool);
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, NULL);
}
static void
pika_color_picker_tool_info_update (PikaColorPickerTool *picker_tool,
PikaDisplay *display,
gboolean sample_average,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color,
gint x,
gint y)
{
PikaTool *tool = PIKA_TOOL (picker_tool);
PikaImage *image = pika_display_get_image (display);
GList *drawables = pika_image_get_selected_drawables (image);
tool->display = display;
pika_tool_gui_set_shell (picker_tool->gui,
pika_display_get_shell (display));
pika_tool_gui_set_viewables (picker_tool->gui, drawables);
g_list_free (drawables);
pika_color_area_set_color (PIKA_COLOR_AREA (picker_tool->color_area),
color);
pika_color_frame_set_color (PIKA_COLOR_FRAME (picker_tool->color_frame1),
sample_average, sample_format, pixel, color,
x, y);
pika_color_frame_set_color (PIKA_COLOR_FRAME (picker_tool->color_frame2),
sample_average, sample_format, pixel, color,
x, y);
pika_tool_gui_show (picker_tool->gui);
}

View File

@ -0,0 +1,64 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_PICKER_TOOL_H__
#define __PIKA_COLOR_PICKER_TOOL_H__
#include "pikacolortool.h"
#define PIKA_TYPE_COLOR_PICKER_TOOL (pika_color_picker_tool_get_type ())
#define PIKA_COLOR_PICKER_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PICKER_TOOL, PikaColorPickerTool))
#define PIKA_COLOR_PICKER_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PICKER_TOOL, PikaColorPickerToolClass))
#define PIKA_IS_COLOR_PICKER_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PICKER_TOOL))
#define PIKA_IS_COLOR_PICKER_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PICKER_TOOL))
#define PIKA_COLOR_PICKER_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PICKER_TOOL, PikaColorPickerToolClass))
#define PIKA_COLOR_PICKER_TOOL_GET_OPTIONS(t) (PIKA_COLOR_PICKER_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaColorPickerTool PikaColorPickerTool;
typedef struct _PikaColorPickerToolClass PikaColorPickerToolClass;
struct _PikaColorPickerTool
{
PikaColorTool parent_instance;
PikaToolGui *gui;
GtkWidget *color_area;
GtkWidget *color_frame1;
GtkWidget *color_frame2;
};
struct _PikaColorPickerToolClass
{
PikaColorToolClass parent_class;
};
void pika_color_picker_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_color_picker_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_COLOR_PICKER_TOOL_H__ */

704
app/tools/pikacolortool.c Normal file
View File

@ -0,0 +1,704 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "config/pikadisplayconfig.h"
#include "core/pika.h"
#include "core/pikadata.h"
#include "core/pikaimage.h"
#include "core/pikaimage-pick-color.h"
#include "core/pikaimage-pick-item.h"
#include "core/pikaimage-sample-points.h"
#include "core/pikamarshal.h"
#include "core/pikasamplepoint.h"
#include "widgets/pikacolormapeditor.h"
#include "widgets/pikadialogfactory.h"
#include "widgets/pikadockable.h"
#include "widgets/pikadockcontainer.h"
#include "widgets/pikapaletteeditor.h"
#include "widgets/pikawidgets-utils.h"
#include "widgets/pikawindowstrategy.h"
#include "display/pikacanvasitem.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikadisplayshell-appearance.h"
#include "pikacoloroptions.h"
#include "pikacolortool.h"
#include "pikasamplepointtool.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
enum
{
PICKED,
LAST_SIGNAL
};
/* local function prototypes */
static void pika_color_tool_finalize (GObject *object);
static void pika_color_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display);
static void pika_color_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display);
static void pika_color_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display);
static void pika_color_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_color_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
static void pika_color_tool_draw (PikaDrawTool *draw_tool);
static gboolean
pika_color_tool_real_can_pick (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display);
static gboolean pika_color_tool_real_pick (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display,
const Babl **sample_format,
gpointer pixel,
PikaRGB *color);
static void pika_color_tool_real_picked (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color);
static gboolean pika_color_tool_can_pick (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display);
static void pika_color_tool_pick (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state);
G_DEFINE_TYPE (PikaColorTool, pika_color_tool, PIKA_TYPE_DRAW_TOOL)
#define parent_class pika_color_tool_parent_class
static guint pika_color_tool_signals[LAST_SIGNAL] = { 0 };
static void
pika_color_tool_class_init (PikaColorToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaDrawToolClass *draw_class = PIKA_DRAW_TOOL_CLASS (klass);
pika_color_tool_signals[PICKED] =
g_signal_new ("picked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorToolClass, picked),
NULL, NULL,
pika_marshal_VOID__POINTER_OBJECT_ENUM_POINTER_POINTER_BOXED,
G_TYPE_NONE, 6,
G_TYPE_POINTER,
PIKA_TYPE_DISPLAY,
PIKA_TYPE_COLOR_PICK_STATE,
G_TYPE_POINTER,
G_TYPE_POINTER,
PIKA_TYPE_RGB | G_SIGNAL_TYPE_STATIC_SCOPE);
object_class->finalize = pika_color_tool_finalize;
tool_class->button_press = pika_color_tool_button_press;
tool_class->button_release = pika_color_tool_button_release;
tool_class->motion = pika_color_tool_motion;
tool_class->oper_update = pika_color_tool_oper_update;
tool_class->cursor_update = pika_color_tool_cursor_update;
draw_class->draw = pika_color_tool_draw;
klass->can_pick = pika_color_tool_real_can_pick;
klass->pick = pika_color_tool_real_pick;
klass->picked = pika_color_tool_real_picked;
}
static void
pika_color_tool_init (PikaColorTool *color_tool)
{
PikaTool *tool = PIKA_TOOL (color_tool);
pika_tool_control_set_action_size (tool->control,
"tools-color-average-radius-set");
}
static void
pika_color_tool_finalize (GObject *object)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (object);
g_clear_object (&color_tool->options);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_color_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (tool);
if (color_tool->enabled)
{
if (color_tool->sample_point)
{
pika_sample_point_tool_start_edit (tool, display,
color_tool->sample_point);
}
else if (pika_color_tool_can_pick (color_tool, coords, display))
{
pika_color_tool_pick (color_tool, coords, display,
PIKA_COLOR_PICK_STATE_START);
pika_tool_control_activate (tool->control);
}
}
else
{
PIKA_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
press_type, display);
}
}
static void
pika_color_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (tool);
if (color_tool->enabled)
{
pika_tool_control_halt (tool->control);
if (! color_tool->sample_point &&
pika_color_tool_can_pick (color_tool, coords, display))
{
pika_color_tool_pick (color_tool, coords, display,
PIKA_COLOR_PICK_STATE_END);
}
}
else
{
PIKA_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
release_type, display);
}
}
static void
pika_color_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (tool);
if (color_tool->enabled)
{
if (! color_tool->sample_point)
{
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
color_tool->can_pick = pika_color_tool_can_pick (color_tool,
coords, display);
color_tool->center_x = coords->x;
color_tool->center_y = coords->y;
if (color_tool->can_pick)
{
pika_color_tool_pick (color_tool, coords, display,
PIKA_COLOR_PICK_STATE_UPDATE);
}
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
}
}
else
{
PIKA_TOOL_CLASS (parent_class)->motion (tool, coords, time, state,
display);
}
}
static void
pika_color_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (tool);
if (color_tool->enabled)
{
PikaDrawTool *draw_tool = PIKA_DRAW_TOOL (tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaSamplePoint *sample_point = NULL;
pika_draw_tool_pause (draw_tool);
if (! draw_tool->widget &&
pika_draw_tool_is_active (draw_tool) &&
(draw_tool->display != display ||
! proximity))
{
pika_draw_tool_stop (draw_tool);
}
if (pika_display_shell_get_show_sample_points (shell) &&
proximity)
{
PikaImage *image = pika_display_get_image (display);
gint snap_distance = display->config->snap_distance;
sample_point =
pika_image_pick_sample_point (image,
coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance));
}
color_tool->sample_point = sample_point;
color_tool->can_pick = pika_color_tool_can_pick (color_tool,
coords, display);
color_tool->center_x = coords->x;
color_tool->center_y = coords->y;
if (! draw_tool->widget &&
! pika_draw_tool_is_active (draw_tool) &&
proximity)
{
pika_draw_tool_start (draw_tool, display);
}
pika_draw_tool_resume (draw_tool);
}
else
{
PIKA_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
proximity, display);
}
}
static void
pika_color_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (tool);
if (color_tool->enabled)
{
if (color_tool->sample_point)
{
pika_tool_set_cursor (tool, display,
PIKA_CURSOR_MOUSE,
PIKA_TOOL_CURSOR_COLOR_PICKER,
PIKA_CURSOR_MODIFIER_MOVE);
}
else
{
PikaCursorModifier modifier = PIKA_CURSOR_MODIFIER_BAD;
if (pika_color_tool_can_pick (color_tool, coords, display))
{
switch (color_tool->pick_target)
{
case PIKA_COLOR_PICK_TARGET_NONE:
modifier = PIKA_CURSOR_MODIFIER_NONE;
break;
case PIKA_COLOR_PICK_TARGET_FOREGROUND:
modifier = PIKA_CURSOR_MODIFIER_FOREGROUND;
break;
case PIKA_COLOR_PICK_TARGET_BACKGROUND:
modifier = PIKA_CURSOR_MODIFIER_BACKGROUND;
break;
case PIKA_COLOR_PICK_TARGET_PALETTE:
modifier = PIKA_CURSOR_MODIFIER_PLUS;
break;
}
}
pika_tool_set_cursor (tool, display,
PIKA_CURSOR_COLOR_PICKER,
PIKA_TOOL_CURSOR_COLOR_PICKER,
modifier);
}
}
else
{
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state,
display);
}
}
static void
pika_color_tool_draw (PikaDrawTool *draw_tool)
{
PikaColorTool *color_tool = PIKA_COLOR_TOOL (draw_tool);
PIKA_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
if (color_tool->enabled)
{
if (color_tool->sample_point)
{
PikaImage *image = pika_display_get_image (draw_tool->display);
PikaCanvasItem *item;
gint index;
gint x;
gint y;
pika_sample_point_get_position (color_tool->sample_point, &x, &y);
index = g_list_index (pika_image_get_sample_points (image),
color_tool->sample_point) + 1;
item = pika_draw_tool_add_sample_point (draw_tool, x, y, index);
pika_canvas_item_set_highlight (item, TRUE);
}
else if (color_tool->can_pick && color_tool->options->sample_average)
{
gdouble radius = color_tool->options->average_radius;
pika_draw_tool_add_rectangle (draw_tool,
FALSE,
color_tool->center_x - radius,
color_tool->center_y - radius,
2 * radius + 1,
2 * radius + 1);
}
}
}
static gboolean
pika_color_tool_real_can_pick (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display)
{
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
return pika_image_coords_in_active_pickable (image, coords,
shell->show_all,
color_tool->options->sample_merged,
FALSE);
}
static gboolean
pika_color_tool_real_pick (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display,
const Babl **sample_format,
gpointer pixel,
PikaRGB *color)
{
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
GList *drawables = pika_image_get_selected_drawables (image);
g_return_val_if_fail (drawables != NULL, FALSE);
return pika_image_pick_color (image, drawables,
coords->x, coords->y,
shell->show_all,
color_tool->options->sample_merged,
color_tool->options->sample_average,
color_tool->options->average_radius,
sample_format,
pixel,
color);
}
static void
pika_color_tool_real_picked (PikaColorTool *color_tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color)
{
PikaTool *tool = PIKA_TOOL (color_tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImageWindow *image_window;
PikaDialogFactory *dialog_factory;
PikaContext *context;
image_window = pika_display_shell_get_window (shell);
dialog_factory = pika_dock_container_get_dialog_factory (PIKA_DOCK_CONTAINER (image_window));
/* use this tool's own options here (NOT color_tool->options) */
context = PIKA_CONTEXT (pika_tool_get_options (tool));
if (color_tool->pick_target == PIKA_COLOR_PICK_TARGET_FOREGROUND ||
color_tool->pick_target == PIKA_COLOR_PICK_TARGET_BACKGROUND)
{
GtkWidget *widget;
widget = pika_dialog_factory_find_widget (dialog_factory,
"pika-indexed-palette");
if (widget)
{
GtkWidget *editor = gtk_bin_get_child (GTK_BIN (widget));
PikaImage *image = pika_display_get_image (display);
if (babl_format_is_palette (sample_format))
{
guchar *index = pixel;
pika_colormap_editor_set_index (PIKA_COLORMAP_EDITOR (editor),
*index, NULL);
}
else if (pika_image_get_base_type (image) == PIKA_INDEXED)
{
/* When Sample merged is set, we don't have the index
* information and it is possible to pick colors out of
* the colormap (with compositing). In such a case, the
* sample format will not be a palette format even though
* the image is indexed. Still search if the color exists
* in the colormap.
* Note that even if it does, we might still pick the
* wrong color, since several indexes may contain the same
* color and we can't know for sure which is the right
* one.
*/
gint index = pika_colormap_editor_get_index (PIKA_COLORMAP_EDITOR (editor),
color);
if (index > -1)
pika_colormap_editor_set_index (PIKA_COLORMAP_EDITOR (editor),
index, NULL);
}
}
widget = pika_dialog_factory_find_widget (dialog_factory,
"pika-palette-editor");
if (widget)
{
GtkWidget *editor = gtk_bin_get_child (GTK_BIN (widget));
gint index;
index = pika_palette_editor_get_index (PIKA_PALETTE_EDITOR (editor),
color);
if (index != -1)
pika_palette_editor_set_index (PIKA_PALETTE_EDITOR (editor),
index, NULL);
}
}
switch (color_tool->pick_target)
{
case PIKA_COLOR_PICK_TARGET_NONE:
break;
case PIKA_COLOR_PICK_TARGET_FOREGROUND:
pika_context_set_foreground (context, color);
break;
case PIKA_COLOR_PICK_TARGET_BACKGROUND:
pika_context_set_background (context, color);
break;
case PIKA_COLOR_PICK_TARGET_PALETTE:
{
GdkMonitor *monitor = pika_widget_get_monitor (GTK_WIDGET (shell));
GtkWidget *dockable;
dockable =
pika_window_strategy_show_dockable_dialog (PIKA_WINDOW_STRATEGY (pika_get_window_strategy (display->pika)),
display->pika,
dialog_factory,
monitor,
"pika-palette-editor");
if (dockable)
{
GtkWidget *palette_editor;
PikaData *data;
/* don't blink like mad when updating */
if (pick_state != PIKA_COLOR_PICK_STATE_START)
pika_widget_blink_cancel (dockable);
palette_editor = gtk_bin_get_child (GTK_BIN (dockable));
data = pika_data_editor_get_data (PIKA_DATA_EDITOR (palette_editor));
if (! data)
{
data = PIKA_DATA (pika_context_get_palette (context));
pika_data_editor_set_data (PIKA_DATA_EDITOR (palette_editor),
data);
}
pika_palette_editor_pick_color (PIKA_PALETTE_EDITOR (palette_editor),
color, pick_state);
}
}
break;
}
}
static gboolean
pika_color_tool_can_pick (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display)
{
PikaColorToolClass *klass;
klass = PIKA_COLOR_TOOL_GET_CLASS (tool);
return klass->can_pick && klass->can_pick (tool, coords, display);
}
static void
pika_color_tool_pick (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state)
{
PikaColorToolClass *klass;
const Babl *sample_format;
gdouble pixel[4];
PikaRGB color;
klass = PIKA_COLOR_TOOL_GET_CLASS (tool);
if (klass->pick &&
klass->pick (tool, coords, display, &sample_format, pixel, &color))
{
g_signal_emit (tool, pika_color_tool_signals[PICKED], 0,
coords, display, pick_state,
sample_format, pixel, &color);
}
}
/* public functions */
void
pika_color_tool_enable (PikaColorTool *color_tool,
PikaColorOptions *options)
{
PikaTool *tool;
g_return_if_fail (PIKA_IS_COLOR_TOOL (color_tool));
g_return_if_fail (PIKA_IS_COLOR_OPTIONS (options));
tool = PIKA_TOOL (color_tool);
if (pika_tool_control_is_active (tool->control))
{
g_warning ("Trying to enable PikaColorTool while it is active.");
return;
}
g_set_object (&color_tool->options, options);
/* color picking doesn't snap, see bug #768058 */
color_tool->saved_snap_to = pika_tool_control_get_snap_to (tool->control);
pika_tool_control_set_snap_to (tool->control, FALSE);
color_tool->enabled = TRUE;
}
void
pika_color_tool_disable (PikaColorTool *color_tool)
{
PikaTool *tool;
g_return_if_fail (PIKA_IS_COLOR_TOOL (color_tool));
tool = PIKA_TOOL (color_tool);
if (pika_tool_control_is_active (tool->control))
{
g_warning ("Trying to disable PikaColorTool while it is active.");
return;
}
g_clear_object (&color_tool->options);
pika_tool_control_set_snap_to (tool->control, color_tool->saved_snap_to);
color_tool->saved_snap_to = FALSE;
color_tool->enabled = FALSE;
}
gboolean
pika_color_tool_is_enabled (PikaColorTool *color_tool)
{
return color_tool->enabled;
}

91
app/tools/pikacolortool.h Normal file
View File

@ -0,0 +1,91 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_TOOL_H__
#define __PIKA_COLOR_TOOL_H__
#include "pikadrawtool.h"
#define PIKA_TYPE_COLOR_TOOL (pika_color_tool_get_type ())
#define PIKA_COLOR_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_TOOL, PikaColorTool))
#define PIKA_COLOR_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_TOOL, PikaColorToolClass))
#define PIKA_IS_COLOR_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_TOOL))
#define PIKA_IS_COLOR_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_TOOL))
#define PIKA_COLOR_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_TOOL, PikaColorToolClass))
#define PIKA_COLOR_TOOL_GET_OPTIONS(t) (PIKA_COLOR_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaColorToolClass PikaColorToolClass;
struct _PikaColorTool
{
PikaDrawTool parent_instance;
gboolean enabled;
PikaColorOptions *options;
gboolean saved_snap_to;
PikaColorPickTarget pick_target;
gboolean can_pick;
gint center_x;
gint center_y;
PikaSamplePoint *sample_point;
};
struct _PikaColorToolClass
{
PikaDrawToolClass parent_class;
/* virtual functions */
gboolean (* can_pick) (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display);
gboolean (* pick) (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display,
const Babl **sample_format,
gpointer pixel,
PikaRGB *color);
/* signals */
void (* picked) (PikaColorTool *tool,
const PikaCoords *coords,
PikaDisplay *display,
PikaColorPickState pick_state,
const Babl *sample_format,
gpointer pixel,
const PikaRGB *color);
};
GType pika_color_tool_get_type (void) G_GNUC_CONST;
void pika_color_tool_enable (PikaColorTool *color_tool,
PikaColorOptions *options);
void pika_color_tool_disable (PikaColorTool *color_tool);
gboolean pika_color_tool_is_enabled (PikaColorTool *color_tool);
#endif /* __PIKA_COLOR_TOOL_H__ */

View File

@ -0,0 +1,232 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "paint/pikaconvolveoptions.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-utils.h"
#include "pikaconvolvetool.h"
#include "pikapaintoptions-gui.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static void pika_convolve_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display);
static void pika_convolve_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
static void pika_convolve_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_convolve_tool_status_update (PikaTool *tool,
PikaConvolveType type);
static GtkWidget * pika_convolve_options_gui (PikaToolOptions *options);
G_DEFINE_TYPE (PikaConvolveTool, pika_convolve_tool, PIKA_TYPE_BRUSH_TOOL)
#define parent_class pika_convolve_tool_parent_class
void
pika_convolve_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_CONVOLVE_TOOL,
PIKA_TYPE_CONVOLVE_OPTIONS,
pika_convolve_options_gui,
PIKA_PAINT_OPTIONS_CONTEXT_MASK,
"pika-convolve-tool",
_("Blur / Sharpen"),
_("Blur / Sharpen Tool: Selective blurring or unblurring using a brush"),
N_("Bl_ur / Sharpen"), "<shift>U",
NULL, PIKA_HELP_TOOL_CONVOLVE,
PIKA_ICON_TOOL_BLUR,
data);
}
static void
pika_convolve_tool_class_init (PikaConvolveToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
tool_class->modifier_key = pika_convolve_tool_modifier_key;
tool_class->cursor_update = pika_convolve_tool_cursor_update;
tool_class->oper_update = pika_convolve_tool_oper_update;
}
static void
pika_convolve_tool_init (PikaConvolveTool *convolve)
{
PikaTool *tool = PIKA_TOOL (convolve);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_BLUR);
pika_tool_control_set_toggle_cursor_modifier (tool->control,
PIKA_CURSOR_MODIFIER_MINUS);
pika_convolve_tool_status_update (tool, PIKA_CONVOLVE_BLUR);
}
static void
pika_convolve_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display)
{
PikaConvolveTool *convolve = PIKA_CONVOLVE_TOOL (tool);
PikaConvolveOptions *options = PIKA_CONVOLVE_TOOL_GET_OPTIONS (tool);
GdkModifierType line_mask = PIKA_PAINT_TOOL_LINE_MASK;
GdkModifierType toggle_mask = pika_get_toggle_behavior_mask ();
if (((key == toggle_mask) &&
! (state & line_mask) && /* leave stuff untouched in line draw mode */
press != convolve->toggled)
||
(key == line_mask && /* toggle back after keypresses CTRL(hold)-> */
! press && /* SHIFT(hold)->CTRL(release)->SHIFT(release) */
convolve->toggled &&
! (state & toggle_mask)))
{
convolve->toggled = press;
switch (options->type)
{
case PIKA_CONVOLVE_BLUR:
g_object_set (options, "type", PIKA_CONVOLVE_SHARPEN, NULL);
break;
case PIKA_CONVOLVE_SHARPEN:
g_object_set (options, "type", PIKA_CONVOLVE_BLUR, NULL);
break;
}
}
}
static void
pika_convolve_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaConvolveOptions *options = PIKA_CONVOLVE_TOOL_GET_OPTIONS (tool);
pika_tool_control_set_toggled (tool->control,
options->type == PIKA_CONVOLVE_SHARPEN);
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
static void
pika_convolve_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaConvolveOptions *options = PIKA_CONVOLVE_TOOL_GET_OPTIONS (tool);
pika_convolve_tool_status_update (tool, options->type);
PIKA_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
display);
}
static void
pika_convolve_tool_status_update (PikaTool *tool,
PikaConvolveType type)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (tool);
switch (type)
{
case PIKA_CONVOLVE_BLUR:
paint_tool->status = _("Click to blur");
paint_tool->status_line = _("Click to blur the line");
paint_tool->status_ctrl = _("%s to sharpen");
break;
case PIKA_CONVOLVE_SHARPEN:
paint_tool->status = _("Click to sharpen");
paint_tool->status_line = _("Click to sharpen the line");
paint_tool->status_ctrl = _("%s to blur");
break;
default:
break;
}
}
/* tool options stuff */
static GtkWidget *
pika_convolve_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *frame;
GtkWidget *scale;
gchar *str;
GdkModifierType toggle_mask;
toggle_mask = pika_get_toggle_behavior_mask ();
/* the type radio box */
str = g_strdup_printf (_("Convolve Type (%s)"),
pika_get_mod_string (toggle_mask));
frame = pika_prop_enum_radio_frame_new (config, "type",
str, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
g_free (str);
/* the rate scale */
scale = pika_prop_spin_scale_new (config, "rate",
1.0, 10.0, 1);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
return vbox;
}

View File

@ -0,0 +1,61 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CONVOLVE_TOOL_H__
#define __PIKA_CONVOLVE_TOOL_H__
#include "pikabrushtool.h"
#define PIKA_TYPE_CONVOLVE_TOOL (pika_convolve_tool_get_type ())
#define PIKA_CONVOLVE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CONVOLVE_TOOL, PikaConvolveTool))
#define PIKA_CONVOLVE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CONVOLVE_TOOL, PikaConvolveToolClass))
#define PIKA_IS_CONVOLVE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CONVOLVE_TOOL))
#define PIKA_IS_CONVOLVE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CONVOLVE_TOOL))
#define PIKA_CONVOLVE_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CONVOLVE_TOOL, PikaConvolveToolClass))
#define PIKA_CONVOLVE_TOOL_GET_OPTIONS(t) (PIKA_CONVOLVE_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaConvolveTool PikaConvolveTool;
typedef struct _PikaConvolveToolClass PikaConvolveToolClass;
struct _PikaConvolveTool
{
PikaBrushTool parent_instance;
gboolean toggled;
};
struct _PikaConvolveToolClass
{
PikaBrushToolClass parent_class;
};
void pika_convolve_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_convolve_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_CONVOLVE_TOOL_H__ */

243
app/tools/pikacropoptions.c Normal file
View File

@ -0,0 +1,243 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-utils.h"
#include "pikarectangleoptions.h"
#include "pikacropoptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
enum
{
PROP_LAYER_ONLY = PIKA_RECTANGLE_OPTIONS_PROP_LAST + 1,
PROP_ALLOW_GROWING,
PROP_FILL_TYPE,
PROP_DELETE_PIXELS
};
static void pika_crop_options_rectangle_options_iface_init (PikaRectangleOptionsInterface *iface);
static void pika_crop_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_crop_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE_WITH_CODE (PikaCropOptions, pika_crop_options,
PIKA_TYPE_TOOL_OPTIONS,
G_IMPLEMENT_INTERFACE (PIKA_TYPE_RECTANGLE_OPTIONS,
pika_crop_options_rectangle_options_iface_init))
static void
pika_crop_options_class_init (PikaCropOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_crop_options_set_property;
object_class->get_property = pika_crop_options_get_property;
/* The 'highlight' property is defined here because we want different
* default values for the Crop and the Rectangle Select tools.
*/
PIKA_CONFIG_PROP_BOOLEAN (object_class,
PIKA_RECTANGLE_OPTIONS_PROP_HIGHLIGHT,
"highlight",
_("Highlight"),
_("Dim everything outside selection"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class,
PIKA_RECTANGLE_OPTIONS_PROP_HIGHLIGHT_OPACITY,
"highlight-opacity",
_("Highlight opacity"),
_("How much to dim everything outside selection"),
0.0, 1.0, 0.5,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_LAYER_ONLY,
"layer-only",
_("Selected layers only"),
_("Crop only currently selected layers"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_DELETE_PIXELS,
"delete-pixels",
_("Delete cropped pixels"),
_("Discard non-locked layer data that falls out of the crop region"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_ALLOW_GROWING,
"allow-growing",
_("Allow growing"),
_("Allow resizing canvas by dragging cropping frame "
"beyond image boundary"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FILL_TYPE,
"fill-type",
_("Fill with"),
_("How to fill new areas created by 'Allow growing'"),
PIKA_TYPE_FILL_TYPE,
PIKA_FILL_TRANSPARENT,
PIKA_PARAM_STATIC_STRINGS);
pika_rectangle_options_install_properties (object_class);
}
static void
pika_crop_options_init (PikaCropOptions *options)
{
}
static void
pika_crop_options_rectangle_options_iface_init (PikaRectangleOptionsInterface *iface)
{
}
static void
pika_crop_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaCropOptions *options = PIKA_CROP_OPTIONS (object);
switch (property_id)
{
case PROP_LAYER_ONLY:
options->layer_only = g_value_get_boolean (value);
break;
case PROP_DELETE_PIXELS:
options->delete_pixels = g_value_get_boolean (value);
break;
case PROP_ALLOW_GROWING:
options->allow_growing = g_value_get_boolean (value);
break;
case PROP_FILL_TYPE:
options->fill_type = g_value_get_enum (value);
break;
default:
pika_rectangle_options_set_property (object, property_id, value, pspec);
break;
}
}
static void
pika_crop_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaCropOptions *options = PIKA_CROP_OPTIONS (object);
switch (property_id)
{
case PROP_LAYER_ONLY:
g_value_set_boolean (value, options->layer_only);
break;
case PROP_DELETE_PIXELS:
g_value_set_boolean (value, options->delete_pixels);
break;
case PROP_ALLOW_GROWING:
g_value_set_boolean (value, options->allow_growing);
break;
case PROP_FILL_TYPE:
g_value_set_enum (value, options->fill_type);
break;
default:
pika_rectangle_options_get_property (object, property_id, value, pspec);
break;
}
}
GtkWidget *
pika_crop_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_tool_options_gui (tool_options);
GtkWidget *vbox_rectangle;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *combo;
GtkWidget *frame;
/* layer toggle */
button = pika_prop_check_button_new (config, "layer-only", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* delete pixels toggle */
button2 = pika_prop_check_button_new (config, "delete-pixels", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button2, FALSE, FALSE, 0);
g_object_bind_property (G_OBJECT (config), "layer-only",
G_OBJECT (button2), "sensitive",
G_BINDING_SYNC_CREATE |
G_BINDING_INVERT_BOOLEAN);
/* fill type combo */
combo = pika_prop_enum_combo_box_new (config, "fill-type", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Fill with"));
/* allow growing toggle/frame */
frame = pika_prop_expanding_frame_new (config, "allow-growing", NULL,
combo, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
/* rectangle options */
vbox_rectangle = pika_rectangle_options_gui (tool_options);
gtk_box_pack_start (GTK_BOX (vbox), vbox_rectangle, FALSE, FALSE, 0);
gtk_widget_show (vbox_rectangle);
return vbox;
}

View File

@ -0,0 +1,65 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CROP_OPTIONS_H__
#define __PIKA_CROP_OPTIONS_H__
#include "core/pikatooloptions.h"
#define PIKA_TYPE_CROP_OPTIONS (pika_crop_options_get_type ())
#define PIKA_CROP_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CROP_OPTIONS, PikaCropOptions))
#define PIKA_CROP_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CROP_OPTIONS, PikaCropOptionsClass))
#define PIKA_IS_CROP_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CROP_OPTIONS))
#define PIKA_IS_CROP_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CROP_OPTIONS))
#define PIKA_CROP_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CROP_OPTIONS, PikaCropOptionsClass))
typedef struct _PikaCropOptions PikaCropOptions;
typedef struct _PikaToolOptionsClass PikaCropOptionsClass;
struct _PikaCropOptions
{
PikaToolOptions parent_instance;
/* Work on the current layer rather than the image. */
gboolean layer_only;
/* Allow the crop rectangle to be larger than the image/layer. This
* will resize the image/layer.
*/
gboolean allow_growing;
/* How to fill new areas created by 'allow_growing. */
PikaFillType fill_type;
/* Whether to discard layer data that falls out of the crop region */
gboolean delete_pixels;
};
GType pika_crop_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_crop_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_CROP_OPTIONS_H__ */

752
app/tools/pikacroptool.c Normal file
View File

@ -0,0 +1,752 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikaimage.h"
#include "core/pikaimage-crop.h"
#include "core/pikaimage-undo.h"
#include "core/pikaitem.h"
#include "core/pikatoolinfo.h"
#include "widgets/pikahelp-ids.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikatoolrectangle.h"
#include "pikacropoptions.h"
#include "pikacroptool.h"
#include "pikarectangleoptions.h"
#include "pikatoolcontrol.h"
#include "pikatools-utils.h"
#include "pika-intl.h"
static void pika_crop_tool_constructed (GObject *object);
static void pika_crop_tool_dispose (GObject *object);
static void pika_crop_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display);
static void pika_crop_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display);
static void pika_crop_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display);
static void pika_crop_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display);
static void pika_crop_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec);
static void pika_crop_tool_rectangle_changed (PikaToolWidget *rectangle,
PikaCropTool *crop_tool);
static void pika_crop_tool_rectangle_response (PikaToolWidget *rectangle,
gint response_id,
PikaCropTool *crop_tool);
static void pika_crop_tool_rectangle_change_complete (PikaToolRectangle *rectangle,
PikaCropTool *crop_tool);
static void pika_crop_tool_start (PikaCropTool *crop_tool,
PikaDisplay *display);
static void pika_crop_tool_commit (PikaCropTool *crop_tool);
static void pika_crop_tool_halt (PikaCropTool *crop_tool);
static void pika_crop_tool_update_option_defaults (PikaCropTool *crop_tool,
gboolean ignore_pending);
static PikaRectangleConstraint
pika_crop_tool_get_constraint (PikaCropTool *crop_tool);
static void pika_crop_tool_image_changed (PikaCropTool *crop_tool,
PikaImage *image,
PikaContext *context);
static void pika_crop_tool_image_size_changed (PikaCropTool *crop_tool);
static void pika_crop_tool_image_selected_layers_changed (PikaCropTool *crop_tool);
static void pika_crop_tool_layer_size_changed (PikaCropTool *crop_tool);
static void pika_crop_tool_auto_shrink (PikaCropTool *crop_tool);
G_DEFINE_TYPE (PikaCropTool, pika_crop_tool, PIKA_TYPE_DRAW_TOOL)
#define parent_class pika_crop_tool_parent_class
/* public functions */
void
pika_crop_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_CROP_TOOL,
PIKA_TYPE_CROP_OPTIONS,
pika_crop_options_gui,
PIKA_CONTEXT_PROP_MASK_FOREGROUND |
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
PIKA_CONTEXT_PROP_MASK_PATTERN,
"pika-crop-tool",
_("Crop"),
_("Crop Tool: Remove edge areas from image or layer"),
N_("_Crop"), "<shift>C",
NULL, PIKA_HELP_TOOL_CROP,
PIKA_ICON_TOOL_CROP,
data);
}
static void
pika_crop_tool_class_init (PikaCropToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
object_class->constructed = pika_crop_tool_constructed;
object_class->dispose = pika_crop_tool_dispose;
tool_class->control = pika_crop_tool_control;
tool_class->button_press = pika_crop_tool_button_press;
tool_class->button_release = pika_crop_tool_button_release;
tool_class->motion = pika_crop_tool_motion;
tool_class->options_notify = pika_crop_tool_options_notify;
}
static void
pika_crop_tool_init (PikaCropTool *crop_tool)
{
PikaTool *tool = PIKA_TOOL (crop_tool);
pika_tool_control_set_wants_click (tool->control, TRUE);
pika_tool_control_set_active_modifiers (tool->control,
PIKA_TOOL_ACTIVE_MODIFIERS_SEPARATE);
pika_tool_control_set_precision (tool->control,
PIKA_CURSOR_PRECISION_PIXEL_BORDER);
pika_tool_control_set_cursor (tool->control,
PIKA_CURSOR_CROSSHAIR_SMALL);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_CROP);
pika_draw_tool_set_default_status (PIKA_DRAW_TOOL (tool),
_("Click-Drag to draw a crop rectangle"));
}
static void
pika_crop_tool_constructed (GObject *object)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (object);
PikaContext *context;
PikaToolInfo *tool_info;
G_OBJECT_CLASS (parent_class)->constructed (object);
tool_info = PIKA_TOOL (crop_tool)->tool_info;
context = pika_get_user_context (tool_info->pika);
g_signal_connect_object (context, "image-changed",
G_CALLBACK (pika_crop_tool_image_changed),
crop_tool,
G_CONNECT_SWAPPED);
/* Make sure we are connected to "size-changed" for the initial
* image.
*/
pika_crop_tool_image_changed (crop_tool,
pika_context_get_image (context),
context);
}
static void
pika_crop_tool_dispose (GObject *object)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (object);
/* Clean up current_image and current_layers. */
pika_crop_tool_image_changed (crop_tool, NULL, NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_crop_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (tool);
switch (action)
{
case PIKA_TOOL_ACTION_PAUSE:
case PIKA_TOOL_ACTION_RESUME:
break;
case PIKA_TOOL_ACTION_HALT:
pika_crop_tool_halt (crop_tool);
break;
case PIKA_TOOL_ACTION_COMMIT:
pika_crop_tool_commit (crop_tool);
break;
}
PIKA_TOOL_CLASS (parent_class)->control (tool, action, display);
}
static void
pika_crop_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (tool);
if (tool->display && display != tool->display)
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, tool->display);
if (! tool->display)
{
pika_crop_tool_start (crop_tool, display);
pika_tool_widget_hover (crop_tool->widget, coords, state, TRUE);
/* HACK: force CREATING on a newly created rectangle; otherwise,
* property bindings would cause the rectangle to start with the
* size from tool options.
*/
pika_tool_rectangle_set_function (PIKA_TOOL_RECTANGLE (crop_tool->widget),
PIKA_TOOL_RECTANGLE_CREATING);
}
if (pika_tool_widget_button_press (crop_tool->widget, coords, time, state,
press_type))
{
crop_tool->grab_widget = crop_tool->widget;
}
pika_tool_control_activate (tool->control);
}
static void
pika_crop_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (tool);
pika_tool_control_halt (tool->control);
if (crop_tool->grab_widget)
{
pika_tool_widget_button_release (crop_tool->grab_widget,
coords, time, state, release_type);
crop_tool->grab_widget = NULL;
}
pika_tool_push_status (tool, display, _("Click or press Enter to crop"));
}
static void
pika_crop_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (tool);
if (crop_tool->grab_widget)
{
pika_tool_widget_motion (crop_tool->grab_widget, coords, time, state);
}
}
static void
pika_crop_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec)
{
PikaCropTool *crop_tool = PIKA_CROP_TOOL (tool);
if (! strcmp (pspec->name, "layer-only") ||
! strcmp (pspec->name, "allow-growing"))
{
if (crop_tool->widget)
{
pika_tool_rectangle_set_constraint (PIKA_TOOL_RECTANGLE (crop_tool->widget),
pika_crop_tool_get_constraint (crop_tool));
}
else
{
pika_crop_tool_update_option_defaults (crop_tool, FALSE);
}
}
}
static void
pika_crop_tool_rectangle_changed (PikaToolWidget *rectangle,
PikaCropTool *crop_tool)
{
}
static void
pika_crop_tool_rectangle_response (PikaToolWidget *rectangle,
gint response_id,
PikaCropTool *crop_tool)
{
PikaTool *tool = PIKA_TOOL (crop_tool);
switch (response_id)
{
case PIKA_TOOL_WIDGET_RESPONSE_CONFIRM:
pika_tool_control (tool, PIKA_TOOL_ACTION_COMMIT, tool->display);
break;
case PIKA_TOOL_WIDGET_RESPONSE_CANCEL:
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, tool->display);
break;
}
}
static void
pika_crop_tool_rectangle_change_complete (PikaToolRectangle *rectangle,
PikaCropTool *crop_tool)
{
pika_crop_tool_update_option_defaults (crop_tool, FALSE);
}
static void
pika_crop_tool_start (PikaCropTool *crop_tool,
PikaDisplay *display)
{
static const gchar *properties[] =
{
"highlight",
"highlight-opacity",
"guide",
"x",
"y",
"width",
"height",
"fixed-rule-active",
"fixed-rule",
"desired-fixed-width",
"desired-fixed-height",
"desired-fixed-size-width",
"desired-fixed-size-height",
"aspect-numerator",
"aspect-denominator",
"fixed-center"
};
PikaTool *tool = PIKA_TOOL (crop_tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaCropOptions *options = PIKA_CROP_TOOL_GET_OPTIONS (crop_tool);
PikaToolWidget *widget;
gint i;
tool->display = display;
crop_tool->widget = widget = pika_tool_rectangle_new (shell);
g_object_set (widget,
"status-title", _("Crop to: "),
NULL);
pika_draw_tool_set_widget (PIKA_DRAW_TOOL (tool), widget);
for (i = 0; i < G_N_ELEMENTS (properties); i++)
{
GBinding *binding =
g_object_bind_property (G_OBJECT (options), properties[i],
G_OBJECT (widget), properties[i],
G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
crop_tool->bindings = g_list_prepend (crop_tool->bindings, binding);
}
pika_rectangle_options_connect (PIKA_RECTANGLE_OPTIONS (options),
pika_display_get_image (shell->display),
G_CALLBACK (pika_crop_tool_auto_shrink),
crop_tool);
pika_tool_rectangle_set_constraint (PIKA_TOOL_RECTANGLE (widget),
pika_crop_tool_get_constraint (crop_tool));
g_signal_connect (widget, "changed",
G_CALLBACK (pika_crop_tool_rectangle_changed),
crop_tool);
g_signal_connect (widget, "response",
G_CALLBACK (pika_crop_tool_rectangle_response),
crop_tool);
g_signal_connect (widget, "change-complete",
G_CALLBACK (pika_crop_tool_rectangle_change_complete),
crop_tool);
pika_draw_tool_start (PIKA_DRAW_TOOL (tool), display);
}
static void
pika_crop_tool_commit (PikaCropTool *crop_tool)
{
PikaTool *tool = PIKA_TOOL (crop_tool);
if (tool->display)
{
PikaCropOptions *options = PIKA_CROP_TOOL_GET_OPTIONS (tool);
PikaImage *image = pika_display_get_image (tool->display);
gdouble x, y;
gdouble x2, y2;
gint w, h;
pika_tool_rectangle_get_public_rect (PIKA_TOOL_RECTANGLE (crop_tool->widget),
&x, &y, &x2, &y2);
w = x2 - x;
h = y2 - y;
pika_tool_pop_status (tool, tool->display);
/* if rectangle exists, crop it */
if (w > 0 && h > 0)
{
if (options->layer_only)
{
GList *layers = pika_image_get_selected_layers (image);
GList *iter;
gint off_x, off_y;
gchar *undo_text;
if (! layers)
{
pika_tool_message_literal (tool, tool->display,
_("There are no selected layers to crop."));
return;
}
for (iter = layers; iter; iter = iter->next)
if (! pika_item_is_content_locked (PIKA_ITEM (iter->data), NULL))
break;
if (iter == NULL)
{
pika_tool_message_literal (tool, tool->display,
_("All selected layers' pixels are locked."));
pika_tools_blink_lock_box (tool->display->pika, PIKA_ITEM (layers->data));
return;
}
undo_text = ngettext ("Resize Layer", "Resize %d layers",
g_list_length (layers));
undo_text = g_strdup_printf (undo_text, g_list_length (layers));
pika_image_undo_group_start (image,
PIKA_UNDO_GROUP_IMAGE_CROP,
undo_text);
g_free (undo_text);
for (iter = layers; iter; iter = iter->next)
{
pika_item_get_offset (PIKA_ITEM (iter->data), &off_x, &off_y);
off_x -= x;
off_y -= y;
pika_item_resize (PIKA_ITEM (iter->data),
PIKA_CONTEXT (options), options->fill_type,
w, h, off_x, off_y);
}
pika_image_undo_group_end (image);
}
else
{
pika_image_crop (image,
PIKA_CONTEXT (options), PIKA_FILL_TRANSPARENT,
x, y, w, h, options->delete_pixels);
}
pika_image_flush (image);
}
}
}
static void
pika_crop_tool_halt (PikaCropTool *crop_tool)
{
PikaTool *tool = PIKA_TOOL (crop_tool);
PikaCropOptions *options = PIKA_CROP_TOOL_GET_OPTIONS (crop_tool);
if (tool->display)
{
PikaDisplayShell *shell = pika_display_get_shell (tool->display);
pika_display_shell_set_highlight (shell, NULL, 0.0);
pika_rectangle_options_disconnect (PIKA_RECTANGLE_OPTIONS (options),
G_CALLBACK (pika_crop_tool_auto_shrink),
crop_tool);
}
if (pika_draw_tool_is_active (PIKA_DRAW_TOOL (tool)))
pika_draw_tool_stop (PIKA_DRAW_TOOL (tool));
/* disconnect bindings manually so they are really gone *now*, we
* might be in the middle of a signal emission that keeps the
* widget and its bindings alive.
*/
g_list_free_full (crop_tool->bindings, (GDestroyNotify) g_object_unref);
crop_tool->bindings = NULL;
pika_draw_tool_set_widget (PIKA_DRAW_TOOL (tool), NULL);
g_clear_object (&crop_tool->widget);
tool->display = NULL;
g_list_free (tool->drawables);
tool->drawables = NULL;
pika_crop_tool_update_option_defaults (crop_tool, TRUE);
}
/**
* pika_crop_tool_update_option_defaults:
* @crop_tool:
* @ignore_pending: %TRUE to ignore any pending crop rectangle.
*
* Sets the default Fixed: Aspect ratio and Fixed: Size option
* properties.
*/
static void
pika_crop_tool_update_option_defaults (PikaCropTool *crop_tool,
gboolean ignore_pending)
{
PikaTool *tool = PIKA_TOOL (crop_tool);
PikaToolRectangle *rectangle = PIKA_TOOL_RECTANGLE (crop_tool->widget);
PikaRectangleOptions *options;
options = PIKA_RECTANGLE_OPTIONS (PIKA_TOOL_GET_OPTIONS (tool));
if (rectangle && ! ignore_pending)
{
/* There is a pending rectangle and we should not ignore it, so
* set default Fixed: Aspect ratio to the same as the current
* pending rectangle width/height.
*/
pika_tool_rectangle_pending_size_set (rectangle,
G_OBJECT (options),
"default-aspect-numerator",
"default-aspect-denominator");
g_object_set (G_OBJECT (options),
"use-string-current", TRUE,
NULL);
}
else
{
/* There is no pending rectangle, set default Fixed: Aspect
* ratio to that of the current image/layer.
*/
if (! rectangle)
{
/* ugly hack: if we don't have a widget, construct a temporary one
* so that we can use it to call
* pika_tool_rectangle_constraint_size_set().
*/
PikaContext *context = pika_get_user_context (tool->tool_info->pika);
PikaDisplay *display = pika_context_get_display (context);
if (display)
{
PikaDisplayShell *shell = pika_display_get_shell (display);
rectangle = PIKA_TOOL_RECTANGLE (pika_tool_rectangle_new (shell));
pika_tool_rectangle_set_constraint (
rectangle, pika_crop_tool_get_constraint (crop_tool));
}
}
if (rectangle)
{
pika_tool_rectangle_constraint_size_set (rectangle,
G_OBJECT (options),
"default-aspect-numerator",
"default-aspect-denominator");
if (! crop_tool->widget)
g_object_unref (rectangle);
}
g_object_set (G_OBJECT (options),
"use-string-current", FALSE,
NULL);
}
}
static PikaRectangleConstraint
pika_crop_tool_get_constraint (PikaCropTool *crop_tool)
{
PikaCropOptions *crop_options = PIKA_CROP_TOOL_GET_OPTIONS (crop_tool);
if (crop_options->allow_growing)
{
return PIKA_RECTANGLE_CONSTRAIN_NONE;
}
else
{
return crop_options->layer_only ? PIKA_RECTANGLE_CONSTRAIN_DRAWABLE :
PIKA_RECTANGLE_CONSTRAIN_IMAGE;
}
}
static void
pika_crop_tool_image_changed (PikaCropTool *crop_tool,
PikaImage *image,
PikaContext *context)
{
if (crop_tool->current_image)
{
g_signal_handlers_disconnect_by_func (crop_tool->current_image,
pika_crop_tool_image_size_changed,
NULL);
g_signal_handlers_disconnect_by_func (crop_tool->current_image,
pika_crop_tool_image_selected_layers_changed,
NULL);
}
g_set_weak_pointer (&crop_tool->current_image, image);
if (crop_tool->current_image)
{
g_signal_connect_object (crop_tool->current_image, "size-changed",
G_CALLBACK (pika_crop_tool_image_size_changed),
crop_tool,
G_CONNECT_SWAPPED);
g_signal_connect_object (crop_tool->current_image, "selected-layers-changed",
G_CALLBACK (pika_crop_tool_image_selected_layers_changed),
crop_tool,
G_CONNECT_SWAPPED);
}
/* Make sure we are connected to "size-changed" for the initial
* layer.
*/
pika_crop_tool_image_selected_layers_changed (crop_tool);
pika_crop_tool_update_option_defaults (PIKA_CROP_TOOL (crop_tool), FALSE);
}
static void
pika_crop_tool_image_size_changed (PikaCropTool *crop_tool)
{
pika_crop_tool_update_option_defaults (crop_tool, FALSE);
}
static void
pika_crop_tool_image_selected_layers_changed (PikaCropTool *crop_tool)
{
GList *iter;
if (crop_tool->current_layers)
{
for (iter = crop_tool->current_layers; iter; iter = iter->next)
{
if (iter->data)
{
g_signal_handlers_disconnect_by_func (iter->data,
pika_crop_tool_layer_size_changed,
NULL);
g_clear_weak_pointer (&iter->data);
}
}
g_list_free (crop_tool->current_layers);
crop_tool->current_layers = NULL;
}
if (crop_tool->current_image)
{
crop_tool->current_layers = pika_image_get_selected_layers (crop_tool->current_image);
crop_tool->current_layers = g_list_copy (crop_tool->current_layers);
}
else
{
crop_tool->current_layers = NULL;
}
if (crop_tool->current_layers)
{
for (iter = crop_tool->current_layers; iter; iter = iter->next)
{
/* NOT g_set_weak_pointer() because the pointer is already set */
g_object_add_weak_pointer (G_OBJECT (iter->data),
(gpointer) &iter->data);
g_signal_connect_object (iter->data, "size-changed",
G_CALLBACK (pika_crop_tool_layer_size_changed),
crop_tool,
G_CONNECT_SWAPPED);
}
}
pika_crop_tool_update_option_defaults (crop_tool, FALSE);
}
static void
pika_crop_tool_layer_size_changed (PikaCropTool *crop_tool)
{
pika_crop_tool_update_option_defaults (crop_tool, FALSE);
}
static void
pika_crop_tool_auto_shrink (PikaCropTool *crop_tool)
{
gboolean shrink_merged ;
g_object_get (pika_tool_get_options (PIKA_TOOL (crop_tool)),
"shrink-merged", &shrink_merged,
NULL);
pika_tool_rectangle_auto_shrink (PIKA_TOOL_RECTANGLE (crop_tool->widget),
shrink_merged);
}

66
app/tools/pikacroptool.h Normal file
View File

@ -0,0 +1,66 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CROP_TOOL_H__
#define __PIKA_CROP_TOOL_H__
#include "pikadrawtool.h"
#define PIKA_TYPE_CROP_TOOL (pika_crop_tool_get_type ())
#define PIKA_CROP_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CROP_TOOL, PikaCropTool))
#define PIKA_CROP_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CROP_TOOL, PikaCropToolClass))
#define PIKA_IS_CROP_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CROP_TOOL))
#define PIKA_IS_CROP_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CROP_TOOL))
#define PIKA_CROP_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CROP_TOOL, PikaCropToolClass))
#define PIKA_CROP_TOOL_GET_OPTIONS(t) (PIKA_CROP_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaCropTool PikaCropTool;
typedef struct _PikaCropToolClass PikaCropToolClass;
struct _PikaCropTool
{
PikaDrawTool parent_instance;
PikaImage *current_image;
GList *current_layers;
PikaToolWidget *widget;
PikaToolWidget *grab_widget;
GList *bindings;
};
struct _PikaCropToolClass
{
PikaDrawToolClass parent_class;
};
void pika_crop_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_crop_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_CROP_TOOL_H__ */

1177
app/tools/pikacurvestool.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CURVES_TOOL_H__
#define __PIKA_CURVES_TOOL_H__
#include "pikafiltertool.h"
#define PIKA_TYPE_CURVES_TOOL (pika_curves_tool_get_type ())
#define PIKA_CURVES_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CURVES_TOOL, PikaCurvesTool))
#define PIKA_IS_CURVES_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CURVES_TOOL))
#define PIKA_CURVES_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CURVES_TOOL, PikaCurvesToolClass))
#define PIKA_IS_CURVES_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CURVES_TOOL))
typedef struct _PikaCurvesTool PikaCurvesTool;
typedef struct _PikaCurvesToolClass PikaCurvesToolClass;
struct _PikaCurvesTool
{
PikaFilterTool parent_instance;
/* dialog */
gdouble scale;
gdouble picked_color[5];
GtkWidget *channel_menu;
GtkWidget *xrange;
GtkWidget *yrange;
GtkWidget *graph;
GtkWidget *point_box;
GtkWidget *point_input;
GtkWidget *point_output;
GtkWidget *point_type;
GtkWidget *curve_type;
/* export dialog */
gboolean export_old_format;
};
struct _PikaCurvesToolClass
{
PikaFilterToolClass parent_class;
};
void pika_curves_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_curves_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_CURVES_TOOL_H__ */

View File

@ -0,0 +1,242 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "paint/pikadodgeburnoptions.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-utils.h"
#include "pikadodgeburntool.h"
#include "pikapaintoptions-gui.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static void pika_dodge_burn_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display);
static void pika_dodge_burn_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
static void pika_dodge_burn_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_dodge_burn_tool_status_update (PikaTool *tool,
PikaDodgeBurnType type);
static GtkWidget * pika_dodge_burn_options_gui (PikaToolOptions *tool_options);
G_DEFINE_TYPE (PikaDodgeBurnTool, pika_dodge_burn_tool, PIKA_TYPE_BRUSH_TOOL)
#define parent_class pika_dodge_burn_tool_parent_class
void
pika_dodge_burn_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_DODGE_BURN_TOOL,
PIKA_TYPE_DODGE_BURN_OPTIONS,
pika_dodge_burn_options_gui,
PIKA_PAINT_OPTIONS_CONTEXT_MASK,
"pika-dodge-burn-tool",
_("Dodge / Burn"),
_("Dodge / Burn Tool: Selectively lighten or darken using a brush"),
N_("Dod_ge / Burn"), "<shift>D",
NULL, PIKA_HELP_TOOL_DODGE_BURN,
PIKA_ICON_TOOL_DODGE,
data);
}
static void
pika_dodge_burn_tool_class_init (PikaDodgeBurnToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
tool_class->modifier_key = pika_dodge_burn_tool_modifier_key;
tool_class->cursor_update = pika_dodge_burn_tool_cursor_update;
tool_class->oper_update = pika_dodge_burn_tool_oper_update;
}
static void
pika_dodge_burn_tool_init (PikaDodgeBurnTool *dodgeburn)
{
PikaTool *tool = PIKA_TOOL (dodgeburn);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_DODGE);
pika_tool_control_set_toggle_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_BURN);
pika_dodge_burn_tool_status_update (tool, PIKA_DODGE_BURN_TYPE_BURN);
}
static void
pika_dodge_burn_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display)
{
PikaDodgeBurnTool *dodgeburn = PIKA_DODGE_BURN_TOOL (tool);
PikaDodgeBurnOptions *options = PIKA_DODGE_BURN_TOOL_GET_OPTIONS (tool);
GdkModifierType line_mask = PIKA_PAINT_TOOL_LINE_MASK;
GdkModifierType toggle_mask = pika_get_toggle_behavior_mask ();
if ((key == toggle_mask &&
! (state & line_mask) && /* leave stuff untouched in line draw mode */
press != dodgeburn->toggled)
||
(key == line_mask && /* toggle back after keypresses CTRL(hold)-> */
! press && /* SHIFT(hold)->CTRL(release)->SHIFT(release) */
dodgeburn->toggled &&
! (state & toggle_mask)))
{
dodgeburn->toggled = press;
switch (options->type)
{
case PIKA_DODGE_BURN_TYPE_DODGE:
g_object_set (options, "type", PIKA_DODGE_BURN_TYPE_BURN, NULL);
break;
case PIKA_DODGE_BURN_TYPE_BURN:
g_object_set (options, "type", PIKA_DODGE_BURN_TYPE_DODGE, NULL);
break;
default:
break;
}
}
PIKA_TOOL_CLASS (parent_class)->modifier_key (tool, key, press, state,
display);
}
static void
pika_dodge_burn_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaDodgeBurnOptions *options = PIKA_DODGE_BURN_TOOL_GET_OPTIONS (tool);
pika_tool_control_set_toggled (tool->control,
options->type == PIKA_DODGE_BURN_TYPE_BURN);
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state,
display);
}
static void
pika_dodge_burn_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaDodgeBurnOptions *options = PIKA_DODGE_BURN_TOOL_GET_OPTIONS (tool);
pika_dodge_burn_tool_status_update (tool, options->type);
PIKA_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
display);
}
static void
pika_dodge_burn_tool_status_update (PikaTool *tool,
PikaDodgeBurnType type)
{
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (tool);
switch (type)
{
case PIKA_DODGE_BURN_TYPE_DODGE:
paint_tool->status = _("Click to dodge");
paint_tool->status_line = _("Click to dodge the line");
paint_tool->status_ctrl = _("%s to burn");
break;
case PIKA_DODGE_BURN_TYPE_BURN:
paint_tool->status = _("Click to burn");
paint_tool->status_line = _("Click to burn the line");
paint_tool->status_ctrl = _("%s to dodge");
break;
default:
break;
}
}
/* tool options stuff */
static GtkWidget *
pika_dodge_burn_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *frame;
GtkWidget *scale;
gchar *str;
GdkModifierType toggle_mask;
toggle_mask = pika_get_toggle_behavior_mask ();
/* the type (dodge or burn) */
str = g_strdup_printf (_("Type (%s)"),
pika_get_mod_string (toggle_mask));
frame = pika_prop_enum_radio_frame_new (config, "type",
str, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
g_free (str);
/* mode (highlights, midtones, or shadows) */
frame = pika_prop_enum_radio_frame_new (config, "mode", NULL,
0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
/* the exposure scale */
scale = pika_prop_spin_scale_new (config, "exposure",
1.0, 10.0, 1);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
return vbox;
}

View File

@ -0,0 +1,60 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_DODGE_BURN_TOOL_H__
#define __PIKA_DODGE_BURN_TOOL_H__
#include "pikabrushtool.h"
#define PIKA_TYPE_DODGE_BURN_TOOL (pika_dodge_burn_tool_get_type ())
#define PIKA_DODGE_BURN_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_DODGE_BURN_TOOL, PikaDodgeBurnTool))
#define PIKA_IS_DODGE_BURN_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_DODGE_BURN_TOOL))
#define PIKA_DODGE_BURN_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_DODGE_BURN_TOOL, PikaDodgeBurnToolClass))
#define PIKA_IS_DODGE_BURN_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_DODGE_BURN_TOOL))
#define PIKA_DODGE_BURN_TOOL_GET_OPTIONS(t) (PIKA_DODGE_BURN_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaDodgeBurnTool PikaDodgeBurnTool;
typedef struct _PikaDodgeBurnToolClass PikaDodgeBurnToolClass;
struct _PikaDodgeBurnTool
{
PikaBrushTool parent_instance;
gboolean toggled;
};
struct _PikaDodgeBurnToolClass
{
PikaBrushToolClass parent_class;
};
void pika_dodge_burn_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_dodge_burn_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_DODGEBURN_TOOL_H__ */

1334
app/tools/pikadrawtool.c Normal file

File diff suppressed because it is too large Load Diff

216
app/tools/pikadrawtool.h Normal file
View File

@ -0,0 +1,216 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_DRAW_TOOL_H__
#define __PIKA_DRAW_TOOL_H__
#include "pikatool.h"
#define PIKA_TOOL_HANDLE_SIZE_CIRCLE 13
#define PIKA_TOOL_HANDLE_SIZE_CROSS 15
#define PIKA_TOOL_HANDLE_SIZE_CROSSHAIR 43
#define PIKA_TOOL_HANDLE_SIZE_LARGE 25
#define PIKA_TOOL_HANDLE_SIZE_SMALL 7
#define PIKA_TYPE_DRAW_TOOL (pika_draw_tool_get_type ())
#define PIKA_DRAW_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_DRAW_TOOL, PikaDrawTool))
#define PIKA_DRAW_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_DRAW_TOOL, PikaDrawToolClass))
#define PIKA_IS_DRAW_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_DRAW_TOOL))
#define PIKA_IS_DRAW_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_DRAW_TOOL))
#define PIKA_DRAW_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_DRAW_TOOL, PikaDrawToolClass))
typedef struct _PikaDrawToolClass PikaDrawToolClass;
struct _PikaDrawTool
{
PikaTool parent_instance;
PikaDisplay *display; /* The display we are drawing to (may be
* a different one than tool->display)
*/
gint paused_count; /* count to keep track of multiple pauses */
guint draw_timeout; /* draw delay timeout ID */
guint64 last_draw_time; /* time of last draw(), monotonically */
PikaToolWidget *widget;
gchar *default_status;
PikaCanvasItem *preview;
PikaCanvasItem *item;
GList *group_stack;
};
struct _PikaDrawToolClass
{
PikaToolClass parent_class;
/* virtual function */
void (* draw) (PikaDrawTool *draw_tool);
};
GType pika_draw_tool_get_type (void) G_GNUC_CONST;
void pika_draw_tool_start (PikaDrawTool *draw_tool,
PikaDisplay *display);
void pika_draw_tool_stop (PikaDrawTool *draw_tool);
gboolean pika_draw_tool_is_active (PikaDrawTool *draw_tool);
void pika_draw_tool_pause (PikaDrawTool *draw_tool);
void pika_draw_tool_resume (PikaDrawTool *draw_tool);
gdouble pika_draw_tool_calc_distance (PikaDrawTool *draw_tool,
PikaDisplay *display,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
gdouble pika_draw_tool_calc_distance_square (PikaDrawTool *draw_tool,
PikaDisplay *display,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
void pika_draw_tool_set_widget (PikaDrawTool *draw_tool,
PikaToolWidget *widget);
void pika_draw_tool_set_default_status (PikaDrawTool *draw_tool,
const gchar *status);
void pika_draw_tool_add_preview (PikaDrawTool *draw_tool,
PikaCanvasItem *item);
void pika_draw_tool_remove_preview (PikaDrawTool *draw_tool,
PikaCanvasItem *item);
void pika_draw_tool_add_item (PikaDrawTool *draw_tool,
PikaCanvasItem *item);
void pika_draw_tool_remove_item (PikaDrawTool *draw_tool,
PikaCanvasItem *item);
PikaCanvasGroup* pika_draw_tool_add_stroke_group (PikaDrawTool *draw_tool);
PikaCanvasGroup* pika_draw_tool_add_fill_group (PikaDrawTool *draw_tool);
void pika_draw_tool_push_group (PikaDrawTool *draw_tool,
PikaCanvasGroup *group);
void pika_draw_tool_pop_group (PikaDrawTool *draw_tool);
PikaCanvasItem * pika_draw_tool_add_line (PikaDrawTool *draw_tool,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
PikaCanvasItem * pika_draw_tool_add_guide (PikaDrawTool *draw_tool,
PikaOrientationType orientation,
gint position,
PikaGuideStyle style);
PikaCanvasItem * pika_draw_tool_add_crosshair (PikaDrawTool *draw_tool,
gint position_x,
gint position_y);
PikaCanvasItem * pika_draw_tool_add_sample_point (PikaDrawTool *draw_tool,
gint x,
gint y,
gint index);
PikaCanvasItem * pika_draw_tool_add_rectangle (PikaDrawTool *draw_tool,
gboolean filled,
gdouble x,
gdouble y,
gdouble width,
gdouble height);
PikaCanvasItem * pika_draw_tool_add_arc (PikaDrawTool *draw_tool,
gboolean filled,
gdouble x,
gdouble y,
gdouble width,
gdouble height,
gdouble start_angle,
gdouble slice_angle);
PikaCanvasItem * pika_draw_tool_add_transform_preview(PikaDrawTool *draw_tool,
PikaPickable *pickable,
const PikaMatrix3 *transform,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
PikaCanvasItem * pika_draw_tool_add_handle (PikaDrawTool *draw_tool,
PikaHandleType type,
gdouble x,
gdouble y,
gint width,
gint height,
PikaHandleAnchor anchor);
PikaCanvasItem * pika_draw_tool_add_lines (PikaDrawTool *draw_tool,
const PikaVector2 *points,
gint n_points,
PikaMatrix3 *transform,
gboolean filled);
PikaCanvasItem * pika_draw_tool_add_strokes (PikaDrawTool *draw_tool,
const PikaCoords *points,
gint n_points,
PikaMatrix3 *transform,
gboolean filled);
PikaCanvasItem * pika_draw_tool_add_pen (PikaDrawTool *draw_tool,
const PikaVector2 *points,
gint n_points,
PikaContext *context,
PikaActiveColor color,
gint width);
PikaCanvasItem * pika_draw_tool_add_boundary (PikaDrawTool *draw_tool,
const PikaBoundSeg *bound_segs,
gint n_bound_segs,
PikaMatrix3 *transform,
gdouble offset_x,
gdouble offset_y);
PikaCanvasItem * pika_draw_tool_add_text_cursor (PikaDrawTool *draw_tool,
PangoRectangle *cursor,
gboolean overwrite,
PikaTextDirection direction);
PikaCanvasItem * pika_draw_tool_add_text (PikaDrawTool *draw_tool,
gdouble x,
gdouble y,
gdouble font_size,
gchar *text);
gboolean pika_draw_tool_on_handle (PikaDrawTool *draw_tool,
PikaDisplay *display,
gdouble x,
gdouble y,
PikaHandleType type,
gdouble handle_x,
gdouble handle_y,
gint width,
gint height,
PikaHandleAnchor anchor);
#endif /* __PIKA_DRAW_TOOL_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_EDIT_SELECTION_TOOL_H__
#define __PIKA_EDIT_SELECTION_TOOL_H__
#include "pikadrawtool.h"
#define PIKA_TYPE_EDIT_SELECTION_TOOL (pika_edit_selection_tool_get_type ())
#define PIKA_EDIT_SELECTION_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_EDIT_SELECTION_TOOL, PikaEditSelectionTool))
#define PIKA_EDIT_SELECTION_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_EDIT_SELECTION_TOOL, PikaEditSelectionToolClass))
#define PIKA_IS_EDIT_SELECTION_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_EDIT_SELECTION_TOOL))
#define PIKA_IS_EDIT_SELECTION_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_EDIT_SELECTION_TOOL))
GType pika_edit_selection_tool_get_type (void) G_GNUC_CONST;
void pika_edit_selection_tool_start (PikaTool *parent_tool,
PikaDisplay *display,
const PikaCoords *coords,
PikaTranslateMode edit_mode,
gboolean propagate_release);
gboolean pika_edit_selection_tool_key_press (PikaTool *tool,
GdkEventKey *kevent,
PikaDisplay *display);
gboolean pika_edit_selection_tool_translate (PikaTool *tool,
GdkEventKey *kevent,
PikaTransformType translate_type,
PikaDisplay *display,
GtkWidget **type_box);
#endif /* __PIKA_EDIT_SELECTION_TOOL_H__ */

View File

@ -0,0 +1,116 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pikachannel-select.h"
#include "core/pikaimage.h"
#include "widgets/pikahelp-ids.h"
#include "display/pikadisplay.h"
#include "pikaellipseselecttool.h"
#include "pikarectangleselectoptions.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static void pika_ellipse_select_tool_select (PikaRectangleSelectTool *rect_tool,
PikaChannelOps operation,
gint x,
gint y,
gint w,
gint h);
G_DEFINE_TYPE (PikaEllipseSelectTool, pika_ellipse_select_tool,
PIKA_TYPE_RECTANGLE_SELECT_TOOL)
#define parent_class pika_ellipse_select_tool_parent_class
void
pika_ellipse_select_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_ELLIPSE_SELECT_TOOL,
PIKA_TYPE_RECTANGLE_SELECT_OPTIONS,
pika_rectangle_select_options_gui,
0,
"pika-ellipse-select-tool",
_("Ellipse Select"),
_("Ellipse Select Tool: Select an elliptical region"),
N_("_Ellipse Select"), "E",
NULL, PIKA_HELP_TOOL_ELLIPSE_SELECT,
PIKA_ICON_TOOL_ELLIPSE_SELECT,
data);
}
static void
pika_ellipse_select_tool_class_init (PikaEllipseSelectToolClass *klass)
{
PikaRectangleSelectToolClass *rect_tool_class;
rect_tool_class = PIKA_RECTANGLE_SELECT_TOOL_CLASS (klass);
rect_tool_class->select = pika_ellipse_select_tool_select;
rect_tool_class->draw_ellipse = TRUE;
}
static void
pika_ellipse_select_tool_init (PikaEllipseSelectTool *ellipse_select)
{
PikaTool *tool = PIKA_TOOL (ellipse_select);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_ELLIPSE_SELECT);
}
static void
pika_ellipse_select_tool_select (PikaRectangleSelectTool *rect_tool,
PikaChannelOps operation,
gint x,
gint y,
gint w,
gint h)
{
PikaTool *tool = PIKA_TOOL (rect_tool);
PikaSelectionOptions *options = PIKA_SELECTION_TOOL_GET_OPTIONS (rect_tool);
PikaImage *image = pika_display_get_image (tool->display);
pika_channel_select_ellipse (pika_image_get_mask (image),
x, y, w, h,
operation,
options->antialias,
options->feather,
options->feather_radius,
options->feather_radius,
TRUE);
}

View File

@ -0,0 +1,57 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_ELLIPSE_SELECT_TOOL_H__
#define __PIKA_ELLIPSE_SELECT_TOOL_H__
#include "pikarectangleselecttool.h"
#define PIKA_TYPE_ELLIPSE_SELECT_TOOL (pika_ellipse_select_tool_get_type ())
#define PIKA_ELLIPSE_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ELLIPSE_SELECT_TOOL, PikaEllipseSelectTool))
#define PIKA_ELLIPSE_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ELLIPSE_SELECT_TOOL, PikaEllipseSelectToolClass))
#define PIKA_IS_ELLIPSE_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ELLIPSE_SELECT_TOOL))
#define PIKA_IS_ELLIPSE_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ELLIPSE_SELECT_TOOL))
#define PIKA_ELLIPSE_SELECT_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ELLIPSE_SELECT_TOOL, PikaEllipseSelectToolClass))
typedef struct _PikaEllipseSelectTool PikaEllipseSelectTool;
typedef struct _PikaEllipseSelectToolClass PikaEllipseSelectToolClass;
struct _PikaEllipseSelectTool
{
PikaRectangleSelectTool parent_instance;
};
struct _PikaEllipseSelectToolClass
{
PikaRectangleSelectToolClass parent_class;
};
void pika_ellipse_select_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_ellipse_select_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_ELLIPSE_SELECT_TOOL_H__ */

179
app/tools/pikaerasertool.c Normal file
View File

@ -0,0 +1,179 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pikadrawable.h"
#include "paint/pikaeraseroptions.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"
#include "pikaerasertool.h"
#include "pikapaintoptions-gui.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static void pika_eraser_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display);
static void pika_eraser_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
static gboolean pika_eraser_tool_is_alpha_only (PikaPaintTool *paint_tool,
PikaDrawable *drawable);
static GtkWidget * pika_eraser_options_gui (PikaToolOptions *tool_options);
G_DEFINE_TYPE (PikaEraserTool, pika_eraser_tool, PIKA_TYPE_BRUSH_TOOL)
#define parent_class pika_eraser_tool_parent_class
void
pika_eraser_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_ERASER_TOOL,
PIKA_TYPE_ERASER_OPTIONS,
pika_eraser_options_gui,
PIKA_PAINT_OPTIONS_CONTEXT_MASK,
"pika-eraser-tool",
_("Eraser"),
_("Eraser Tool: Erase to background or transparency using a brush"),
N_("_Eraser"), "<shift>E",
NULL, PIKA_HELP_TOOL_ERASER,
PIKA_ICON_TOOL_ERASER,
data);
}
static void
pika_eraser_tool_class_init (PikaEraserToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaPaintToolClass *paint_tool_class = PIKA_PAINT_TOOL_CLASS (klass);
tool_class->modifier_key = pika_eraser_tool_modifier_key;
tool_class->cursor_update = pika_eraser_tool_cursor_update;
paint_tool_class->is_alpha_only = pika_eraser_tool_is_alpha_only;
}
static void
pika_eraser_tool_init (PikaEraserTool *eraser)
{
PikaTool *tool = PIKA_TOOL (eraser);
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (eraser);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_ERASER);
pika_tool_control_set_toggle_cursor_modifier (tool->control,
PIKA_CURSOR_MODIFIER_MINUS);
pika_paint_tool_enable_color_picker (paint_tool,
PIKA_COLOR_PICK_TARGET_BACKGROUND);
paint_tool->status = _("Click to erase");
paint_tool->status_line = _("Click to erase the line");
paint_tool->status_ctrl = _("%s to pick a background color");
}
static void
pika_eraser_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display)
{
if (key == GDK_MOD1_MASK)
{
PikaEraserOptions *options = PIKA_ERASER_TOOL_GET_OPTIONS (tool);
g_object_set (options,
"anti-erase", ! options->anti_erase,
NULL);
}
PIKA_TOOL_CLASS (parent_class)->modifier_key (tool, key, press, state, display);
}
static void
pika_eraser_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaEraserOptions *options = PIKA_ERASER_TOOL_GET_OPTIONS (tool);
pika_tool_control_set_toggled (tool->control, options->anti_erase);
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
static gboolean
pika_eraser_tool_is_alpha_only (PikaPaintTool *paint_tool,
PikaDrawable *drawable)
{
PikaEraserOptions *options = PIKA_ERASER_TOOL_GET_OPTIONS (paint_tool);
if (! options->anti_erase)
return pika_drawable_has_alpha (drawable);
else
return TRUE;
}
/* tool options stuff */
static GtkWidget *
pika_eraser_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *button;
gchar *str;
/* the anti_erase toggle */
str = g_strdup_printf (_("Anti erase (%s)"),
pika_get_mod_string (GDK_MOD1_MASK));
button = pika_prop_check_button_new (config, "anti-erase", str);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
g_free (str);
return vbox;
}

View File

@ -0,0 +1,59 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_ERASER_TOOL_H__
#define __PIKA_ERASER_TOOL_H__
#include "pikabrushtool.h"
#define PIKA_TYPE_ERASER_TOOL (pika_eraser_tool_get_type ())
#define PIKA_ERASER_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ERASER_TOOL, PikaEraserTool))
#define PIKA_ERASER_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ERASER_TOOL, PikaEraserToolClass))
#define PIKA_IS_ERASER_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ERASER_TOOL))
#define PIKA_IS_ERASER_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ERASER_TOOL))
#define PIKA_ERASER_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ERASER_TOOL, PikaEraserToolClass))
#define PIKA_ERASER_TOOL_GET_OPTIONS(t) (PIKA_ERASER_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaEraserTool PikaEraserTool;
typedef struct _PikaEraserToolClass PikaEraserToolClass;
struct _PikaEraserTool
{
PikaBrushTool parent_instance;
};
struct _PikaEraserToolClass
{
PikaBrushToolClass parent_class;
};
void pika_eraser_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_eraser_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_ERASER_TOOL_H__ */

View File

@ -0,0 +1,274 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "tools-types.h"
#include "pikafilteroptions.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_PREVIEW,
PROP_PREVIEW_SPLIT,
PROP_PREVIEW_SPLIT_ALIGNMENT,
PROP_PREVIEW_SPLIT_POSITION,
PROP_CONTROLLER,
PROP_BLENDING_OPTIONS_EXPANDED,
PROP_COLOR_OPTIONS_EXPANDED
};
static void pika_filter_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_filter_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaFilterOptions, pika_filter_options,
PIKA_TYPE_COLOR_OPTIONS)
#define parent_class pika_filter_options_parent_class
static void
pika_filter_options_class_init (PikaFilterOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_filter_options_set_property;
object_class->get_property = pika_filter_options_get_property;
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_PREVIEW,
"preview",
_("_Preview"),
NULL,
TRUE,
PIKA_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_PREVIEW_SPLIT,
g_param_spec_boolean ("preview-split",
_("Split _view"),
NULL,
FALSE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_PREVIEW_SPLIT_ALIGNMENT,
g_param_spec_enum ("preview-split-alignment",
NULL, NULL,
PIKA_TYPE_ALIGNMENT_TYPE,
PIKA_ALIGN_LEFT,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_PREVIEW_SPLIT_POSITION,
g_param_spec_int ("preview-split-position",
NULL, NULL,
G_MININT, G_MAXINT, 0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_CONTROLLER,
"controller",
_("On-canvas con_trols"),
_("Show on-canvas filter controls"),
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_BLENDING_OPTIONS_EXPANDED,
"blending-options-expanded",
NULL, NULL,
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_COLOR_OPTIONS_EXPANDED,
"color-options-expanded",
NULL, NULL,
FALSE,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_filter_options_init (PikaFilterOptions *options)
{
}
static void
pika_filter_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaFilterOptions *options = PIKA_FILTER_OPTIONS (object);
switch (property_id)
{
case PROP_PREVIEW:
options->preview = g_value_get_boolean (value);
break;
case PROP_PREVIEW_SPLIT:
options->preview_split = g_value_get_boolean (value);
break;
case PROP_PREVIEW_SPLIT_ALIGNMENT:
options->preview_split_alignment = g_value_get_enum (value);
break;
case PROP_PREVIEW_SPLIT_POSITION:
options->preview_split_position = g_value_get_int (value);
break;
case PROP_CONTROLLER:
options->controller = g_value_get_boolean (value);
break;
case PROP_BLENDING_OPTIONS_EXPANDED:
options->blending_options_expanded = g_value_get_boolean (value);
break;
case PROP_COLOR_OPTIONS_EXPANDED:
options->color_options_expanded = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_filter_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaFilterOptions *options = PIKA_FILTER_OPTIONS (object);
switch (property_id)
{
case PROP_PREVIEW:
g_value_set_boolean (value, options->preview);
break;
case PROP_PREVIEW_SPLIT:
g_value_set_boolean (value, options->preview_split);
break;
case PROP_PREVIEW_SPLIT_ALIGNMENT:
g_value_set_enum (value, options->preview_split_alignment);
break;
case PROP_PREVIEW_SPLIT_POSITION:
g_value_set_int (value, options->preview_split_position);
break;
case PROP_CONTROLLER:
g_value_set_boolean (value, options->controller);
break;
case PROP_BLENDING_OPTIONS_EXPANDED:
g_value_set_boolean (value, options->blending_options_expanded);
break;
case PROP_COLOR_OPTIONS_EXPANDED:
g_value_set_boolean (value, options->color_options_expanded);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* public functions */
void
pika_filter_options_switch_preview_side (PikaFilterOptions *options)
{
PikaAlignmentType alignment;
g_return_if_fail (PIKA_IS_FILTER_OPTIONS (options));
switch (options->preview_split_alignment)
{
case PIKA_ALIGN_LEFT: alignment = PIKA_ALIGN_RIGHT; break;
case PIKA_ALIGN_RIGHT: alignment = PIKA_ALIGN_LEFT; break;
case PIKA_ALIGN_TOP: alignment = PIKA_ALIGN_BOTTOM; break;
case PIKA_ALIGN_BOTTOM: alignment = PIKA_ALIGN_TOP; break;
default:
g_return_if_reached ();
}
g_object_set (options, "preview-split-alignment", alignment, NULL);
}
void
pika_filter_options_switch_preview_orientation (PikaFilterOptions *options,
gint position_x,
gint position_y)
{
PikaAlignmentType alignment;
gint position;
g_return_if_fail (PIKA_IS_FILTER_OPTIONS (options));
switch (options->preview_split_alignment)
{
case PIKA_ALIGN_LEFT: alignment = PIKA_ALIGN_TOP; break;
case PIKA_ALIGN_RIGHT: alignment = PIKA_ALIGN_BOTTOM; break;
case PIKA_ALIGN_TOP: alignment = PIKA_ALIGN_LEFT; break;
case PIKA_ALIGN_BOTTOM: alignment = PIKA_ALIGN_RIGHT; break;
default:
g_return_if_reached ();
}
if (alignment == PIKA_ALIGN_LEFT ||
alignment == PIKA_ALIGN_RIGHT)
{
position = position_x;
}
else
{
position = position_y;
}
g_object_set (options,
"preview-split-alignment", alignment,
"preview-split-position", position,
NULL);
}

View File

@ -0,0 +1,67 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FILTER_OPTIONS_H__
#define __PIKA_FILTER_OPTIONS_H__
#include "pikacoloroptions.h"
#define PIKA_TYPE_FILTER_OPTIONS (pika_filter_options_get_type ())
#define PIKA_FILTER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FILTER_OPTIONS, PikaFilterOptions))
#define PIKA_FILTER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FILTER_OPTIONS, PikaFilterOptionsClass))
#define PIKA_IS_FILTER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FILTER_OPTIONS))
#define PIKA_IS_FILTER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FILTER_OPTIONS))
#define PIKA_FILTER_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FILTER_OPTIONS, PikaFilterOptionsClass))
typedef struct _PikaFilterOptionsClass PikaFilterOptionsClass;
struct _PikaFilterOptions
{
PikaColorOptions parent_instance;
gboolean preview;
gboolean preview_split;
PikaAlignmentType preview_split_alignment;
gint preview_split_position;
gboolean controller;
gboolean blending_options_expanded;
gboolean color_options_expanded;
};
struct _PikaFilterOptionsClass
{
PikaColorOptionsClass parent_instance;
};
GType pika_filter_options_get_type (void) G_GNUC_CONST;
void pika_filter_options_switch_preview_side (PikaFilterOptions *options);
void pika_filter_options_switch_preview_orientation (PikaFilterOptions *options,
gint position_x,
gint position_y);
#endif /* __PIKA_FILTER_OPTIONS_H__ */

View File

@ -0,0 +1,256 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikafiltertool-settings.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikatoolinfo.h"
#include "widgets/pikasettingsbox.h"
#include "display/pikatoolgui.h"
#include "pikafiltertool.h"
#include "pikafiltertool-settings.h"
#include "pika-intl.h"
/* local function prototypes */
static gboolean pika_filter_tool_settings_import (PikaSettingsBox *box,
GFile *file,
PikaFilterTool *filter_tool);
static gboolean pika_filter_tool_settings_export (PikaSettingsBox *box,
GFile *file,
PikaFilterTool *filter_tool);
/* public functions */
GtkWidget *
pika_filter_tool_get_settings_box (PikaFilterTool *filter_tool)
{
PikaToolInfo *tool_info = PIKA_TOOL (filter_tool)->tool_info;
GQuark quark = g_quark_from_static_string ("settings-folder");
GType type = G_TYPE_FROM_INSTANCE (filter_tool->config);
GFile *settings_folder;
GtkWidget *box;
GtkWidget *label;
GtkWidget *combo;
gchar *import_title;
gchar *export_title;
settings_folder = g_type_get_qdata (type, quark);
import_title = g_strdup_printf (_("Import '%s' Settings"),
pika_tool_get_label (PIKA_TOOL (filter_tool)));
export_title = g_strdup_printf (_("Export '%s' Settings"),
pika_tool_get_label (PIKA_TOOL (filter_tool)));
box = pika_settings_box_new (tool_info->pika,
filter_tool->config,
filter_tool->settings,
import_title,
export_title,
pika_tool_get_help_id (PIKA_TOOL (filter_tool)),
settings_folder,
NULL);
g_free (import_title);
g_free (export_title);
g_signal_connect (box, "import",
G_CALLBACK (pika_filter_tool_settings_import),
filter_tool);
g_signal_connect (box, "export",
G_CALLBACK (pika_filter_tool_settings_export),
filter_tool);
g_signal_connect_swapped (box, "selected",
G_CALLBACK (pika_filter_tool_set_config),
filter_tool);
label = gtk_label_new_with_mnemonic (_("Pre_sets:"));
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (box), label, 0);
gtk_widget_show (label);
combo = pika_settings_box_get_combo (PIKA_SETTINGS_BOX (box));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
return box;
}
gboolean
pika_filter_tool_real_settings_import (PikaFilterTool *filter_tool,
GInputStream *input,
GError **error)
{
return pika_config_deserialize_stream (PIKA_CONFIG (filter_tool->config),
input,
NULL, error);
}
gboolean
pika_filter_tool_real_settings_export (PikaFilterTool *filter_tool,
GOutputStream *output,
GError **error)
{
PikaTool *tool = PIKA_TOOL (filter_tool);
gchar *header;
gchar *footer;
gboolean success;
header = g_strdup_printf ("PIKA '%s' settings",
pika_tool_get_label (tool));
footer = g_strdup_printf ("end of '%s' settings",
pika_tool_get_label (tool));
success = pika_config_serialize_to_stream (PIKA_CONFIG (filter_tool->config),
output,
header, footer,
NULL, error);
g_free (header);
g_free (footer);
return success;
}
/* private functions */
static gboolean
pika_filter_tool_settings_import (PikaSettingsBox *box,
GFile *file,
PikaFilterTool *filter_tool)
{
PikaFilterToolClass *tool_class = PIKA_FILTER_TOOL_GET_CLASS (filter_tool);
GInputStream *input;
GError *error = NULL;
g_return_val_if_fail (tool_class->settings_import != NULL, FALSE);
if (PIKA_TOOL (filter_tool)->tool_info->pika->be_verbose)
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
if (! input)
{
pika_message (PIKA_TOOL (filter_tool)->tool_info->pika,
G_OBJECT (pika_tool_gui_get_dialog (filter_tool->gui)),
PIKA_MESSAGE_ERROR,
_("Could not open '%s' for reading: %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
return FALSE;
}
if (! tool_class->settings_import (filter_tool, input, &error))
{
pika_message (PIKA_TOOL (filter_tool)->tool_info->pika,
G_OBJECT (pika_tool_gui_get_dialog (filter_tool->gui)),
PIKA_MESSAGE_ERROR,
_("Error reading '%s': %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
g_object_unref (input);
return FALSE;
}
g_object_unref (input);
return TRUE;
}
static gboolean
pika_filter_tool_settings_export (PikaSettingsBox *box,
GFile *file,
PikaFilterTool *filter_tool)
{
PikaFilterToolClass *tool_class = PIKA_FILTER_TOOL_GET_CLASS (filter_tool);
GOutputStream *output;
GError *error = NULL;
g_return_val_if_fail (tool_class->settings_export != NULL, FALSE);
if (PIKA_TOOL (filter_tool)->tool_info->pika->be_verbose)
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE, G_FILE_CREATE_NONE,
NULL, &error));
if (! output)
{
pika_message_literal (PIKA_TOOL (filter_tool)->tool_info->pika,
G_OBJECT (pika_tool_gui_get_dialog (filter_tool->gui)),
PIKA_MESSAGE_ERROR,
error->message);
g_clear_error (&error);
return FALSE;
}
if (! tool_class->settings_export (filter_tool, output, &error))
{
GCancellable *cancellable = g_cancellable_new ();
pika_message (PIKA_TOOL (filter_tool)->tool_info->pika,
G_OBJECT (pika_tool_gui_get_dialog (filter_tool->gui)),
PIKA_MESSAGE_ERROR,
_("Error writing '%s': %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
/* Cancel the overwrite initiated by g_file_replace(). */
g_cancellable_cancel (cancellable);
g_output_stream_close (output, cancellable, NULL);
g_object_unref (cancellable);
g_object_unref (output);
return FALSE;
}
g_object_unref (output);
pika_message (PIKA_TOOL (filter_tool)->tool_info->pika,
G_OBJECT (PIKA_TOOL (filter_tool)->display),
PIKA_MESSAGE_INFO,
_("Settings saved to '%s'"),
pika_file_get_utf8_name (file));
return TRUE;
}

View File

@ -0,0 +1,41 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikafiltertool-settings.h
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FILTER_TOOL_SETTINGS_H__
#define __PIKA_FILTER_TOOL_SETTINGS_H__
GtkWidget * pika_filter_tool_get_settings_box (PikaFilterTool *filter_tool);
/* virtual functions of PikaSettingsTool, don't call directly */
gboolean pika_filter_tool_real_settings_import (PikaFilterTool *filter_tool,
GInputStream *input,
GError **error);
gboolean pika_filter_tool_real_settings_export (PikaFilterTool *filter_tool,
GOutputStream *output,
GError **error);
#endif /* __PIKA_FILTER_TOOL_SETTINGS_H__ */

View File

@ -0,0 +1,967 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikafiltertool-widgets.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "tools-types.h"
#include "core/pikacontainer.h"
#include "core/pikaitem.h"
#include "display/pikadisplay.h"
#include "display/pikatoolfocus.h"
#include "display/pikatoolgyroscope.h"
#include "display/pikatoolline.h"
#include "display/pikatooltransformgrid.h"
#include "display/pikatoolwidgetgroup.h"
#include "pikafilteroptions.h"
#include "pikafiltertool.h"
#include "pikafiltertool-widgets.h"
typedef struct _Controller Controller;
struct _Controller
{
PikaFilterTool *filter_tool;
PikaControllerType controller_type;
PikaToolWidget *widget;
GCallback creator_callback;
gpointer creator_data;
};
/* local function prototypes */
static Controller * pika_filter_tool_controller_new (void);
static void pika_filter_tool_controller_free (Controller *controller);
static void pika_filter_tool_set_line (Controller *controller,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
static void pika_filter_tool_line_changed (PikaToolWidget *widget,
Controller *controller);
static void pika_filter_tool_set_slider_line (Controller *controller,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2,
const PikaControllerSlider *sliders,
gint n_sliders);
static void pika_filter_tool_slider_line_changed (PikaToolWidget *widget,
Controller *controller);
static void pika_filter_tool_set_transform_grid (Controller *controller,
GeglRectangle *area,
const PikaMatrix3 *transform);
static void pika_filter_tool_transform_grid_changed (PikaToolWidget *widget,
Controller *controller);
static void pika_filter_tool_set_transform_grids (Controller *controller,
GeglRectangle *area,
const PikaMatrix3 *transforms,
gint n_transforms);
static void pika_filter_tool_transform_grids_changed (PikaToolWidget *widget,
Controller *controller);
static void pika_filter_tool_set_gyroscope (Controller *controller,
GeglRectangle *area,
gdouble yaw,
gdouble pitch,
gdouble roll,
gdouble zoom,
gboolean invert);
static void pika_filter_tool_gyroscope_changed (PikaToolWidget *widget,
Controller *controller);
static void pika_filter_tool_set_focus (Controller *controller,
GeglRectangle *area,
PikaLimitType type,
gdouble x,
gdouble y,
gdouble radius,
gdouble aspect_ratio,
gdouble angle,
gdouble inner_limit,
gdouble midpoint);
static void pika_filter_tool_focus_changed (PikaToolWidget *widget,
Controller *controller);
/* public functions */
PikaToolWidget *
pika_filter_tool_create_widget (PikaFilterTool *filter_tool,
PikaControllerType controller_type,
const gchar *status_title,
GCallback callback,
gpointer callback_data,
GCallback *set_func,
gpointer *set_func_data)
{
PikaTool *tool;
PikaDisplayShell *shell;
Controller *controller;
g_return_val_if_fail (PIKA_IS_FILTER_TOOL (filter_tool), NULL);
g_return_val_if_fail (filter_tool->config != NULL, NULL);
tool = PIKA_TOOL (filter_tool);
g_return_val_if_fail (tool->display != NULL, NULL);
shell = pika_display_get_shell (tool->display);
controller = pika_filter_tool_controller_new ();
controller->filter_tool = filter_tool;
controller->controller_type = controller_type;
controller->creator_callback = callback;
controller->creator_data = callback_data;
switch (controller_type)
{
case PIKA_CONTROLLER_TYPE_LINE:
controller->widget = pika_tool_line_new (shell, 100, 100, 500, 500);
g_object_set (controller->widget,
"status-title", status_title,
NULL);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (pika_filter_tool_line_changed),
controller);
*set_func = (GCallback) pika_filter_tool_set_line;
*set_func_data = controller;
break;
case PIKA_CONTROLLER_TYPE_SLIDER_LINE:
controller->widget = pika_tool_line_new (shell, 100, 100, 500, 500);
g_object_set (controller->widget,
"status-title", status_title,
NULL);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (pika_filter_tool_slider_line_changed),
controller);
*set_func = (GCallback) pika_filter_tool_set_slider_line;
*set_func_data = controller;
break;
case PIKA_CONTROLLER_TYPE_TRANSFORM_GRID:
{
PikaMatrix3 transform;
gint off_x, off_y;
GeglRectangle area;
gdouble x1, y1;
gdouble x2, y2;
pika_matrix3_identity (&transform);
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x1 = off_x + area.x;
y1 = off_y + area.y;
x2 = x1 + area.width;
y2 = y1 + area.height;
controller->widget = pika_tool_transform_grid_new (shell, &transform,
x1, y1, x2, y2);
g_object_set (controller->widget,
"pivot-x", (x1 + x2) / 2.0,
"pivot-y", (y1 + y2) / 2.0,
"inside-function", PIKA_TRANSFORM_FUNCTION_MOVE,
"outside-function", PIKA_TRANSFORM_FUNCTION_ROTATE,
"use-corner-handles", TRUE,
"use-perspective-handles", TRUE,
"use-side-handles", TRUE,
"use-shear-handles", TRUE,
"use-pivot-handle", TRUE,
NULL);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (pika_filter_tool_transform_grid_changed),
controller);
*set_func = (GCallback) pika_filter_tool_set_transform_grid;
*set_func_data = controller;
}
break;
case PIKA_CONTROLLER_TYPE_TRANSFORM_GRIDS:
{
controller->widget = pika_tool_widget_group_new (shell);
pika_tool_widget_group_set_auto_raise (
PIKA_TOOL_WIDGET_GROUP (controller->widget), TRUE);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (pika_filter_tool_transform_grids_changed),
controller);
*set_func = (GCallback) pika_filter_tool_set_transform_grids;
*set_func_data = controller;
}
break;
case PIKA_CONTROLLER_TYPE_GYROSCOPE:
{
GeglRectangle area;
gint off_x, off_y;
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
controller->widget = pika_tool_gyroscope_new (shell);
g_object_set (controller->widget,
"speed", 1.0 / MAX (area.width, area.height),
"pivot-x", off_x + area.x + area.width / 2.0,
"pivot-y", off_y + area.y + area.height / 2.0,
NULL);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (pika_filter_tool_gyroscope_changed),
controller);
*set_func = (GCallback) pika_filter_tool_set_gyroscope;
*set_func_data = controller;
}
break;
case PIKA_CONTROLLER_TYPE_FOCUS:
controller->widget = pika_tool_focus_new (shell);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (pika_filter_tool_focus_changed),
controller);
*set_func = (GCallback) pika_filter_tool_set_focus;
*set_func_data = controller;
break;
}
g_object_add_weak_pointer (G_OBJECT (controller->widget),
(gpointer) &controller->widget);
g_object_set_data_full (filter_tool->config,
"pika-filter-tool-controller", controller,
(GDestroyNotify) pika_filter_tool_controller_free);
return controller->widget;
}
static void
pika_filter_tool_reset_transform_grid (PikaToolWidget *widget,
PikaFilterTool *filter_tool)
{
PikaMatrix3 *transform;
gint off_x, off_y;
GeglRectangle area;
gdouble x1, y1;
gdouble x2, y2;
gdouble pivot_x, pivot_y;
g_object_get (widget,
"transform", &transform,
NULL);
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x1 = off_x + area.x;
y1 = off_y + area.y;
x2 = x1 + area.width;
y2 = y1 + area.height;
pika_matrix3_transform_point (transform,
(x1 + x2) / 2.0, (y1 + y2) / 2.0,
&pivot_x, &pivot_y);
g_object_set (widget,
"pivot-x", pivot_x,
"pivot-y", pivot_y,
NULL);
g_free (transform);
}
void
pika_filter_tool_reset_widget (PikaFilterTool *filter_tool,
PikaToolWidget *widget)
{
Controller *controller;
g_return_if_fail (PIKA_IS_FILTER_TOOL (filter_tool));
g_return_if_fail (PIKA_IS_TOOL_WIDGET (widget));
g_return_if_fail (filter_tool->config != NULL);
controller = g_object_get_data (filter_tool->config,
"pika-filter-tool-controller");
g_return_if_fail (controller != NULL);
switch (controller->controller_type)
{
case PIKA_CONTROLLER_TYPE_TRANSFORM_GRID:
{
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_transform_grid_changed,
controller);
pika_filter_tool_reset_transform_grid (controller->widget, filter_tool);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_transform_grid_changed,
controller);
}
break;
case PIKA_CONTROLLER_TYPE_TRANSFORM_GRIDS:
{
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_transform_grids_changed,
controller);
pika_container_foreach (
pika_tool_widget_group_get_children (
PIKA_TOOL_WIDGET_GROUP (controller->widget)),
(GFunc) pika_filter_tool_reset_transform_grid,
filter_tool);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_transform_grids_changed,
controller);
}
break;
default:
break;
}
}
/* private functions */
static Controller *
pika_filter_tool_controller_new (void)
{
return g_slice_new0 (Controller);
}
static void
pika_filter_tool_controller_free (Controller *controller)
{
if (controller->widget)
{
g_signal_handlers_disconnect_by_data (controller->widget, controller);
g_clear_weak_pointer (&controller->widget);
}
g_slice_free (Controller, controller);
}
static void
pika_filter_tool_set_line (Controller *controller,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2)
{
PikaTool *tool;
PikaDrawable *drawable;
if (! controller->widget)
return;
tool = PIKA_TOOL (controller->filter_tool);
drawable = tool->drawables->data;
if (drawable)
{
gint off_x, off_y;
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
x1 += off_x + area->x;
y1 += off_y + area->y;
x2 += off_x + area->x;
y2 += off_y + area->y;
}
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_line_changed,
controller);
g_object_set (controller->widget,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
NULL);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_line_changed,
controller);
}
static void
pika_filter_tool_line_changed (PikaToolWidget *widget,
Controller *controller)
{
PikaFilterTool *filter_tool = controller->filter_tool;
PikaControllerLineCallback line_callback;
gdouble x1, y1, x2, y2;
gint off_x, off_y;
GeglRectangle area;
line_callback = (PikaControllerLineCallback) controller->creator_callback;
g_object_get (widget,
"x1", &x1,
"y1", &y1,
"x2", &x2,
"y2", &y2,
NULL);
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x1 -= off_x + area.x;
y1 -= off_y + area.y;
x2 -= off_x + area.x;
y2 -= off_y + area.y;
line_callback (controller->creator_data,
&area, x1, y1, x2, y2);
}
static void
pika_filter_tool_set_slider_line (Controller *controller,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2,
const PikaControllerSlider *sliders,
gint n_sliders)
{
PikaTool *tool;
PikaDrawable *drawable;
if (! controller->widget)
return;
tool = PIKA_TOOL (controller->filter_tool);
drawable = tool->drawables->data;
if (drawable)
{
gint off_x, off_y;
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
x1 += off_x + area->x;
y1 += off_y + area->y;
x2 += off_x + area->x;
y2 += off_y + area->y;
}
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_slider_line_changed,
controller);
g_object_set (controller->widget,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
NULL);
pika_tool_line_set_sliders (PIKA_TOOL_LINE (controller->widget),
sliders, n_sliders);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_slider_line_changed,
controller);
}
static void
pika_filter_tool_slider_line_changed (PikaToolWidget *widget,
Controller *controller)
{
PikaFilterTool *filter_tool = controller->filter_tool;
PikaControllerSliderLineCallback slider_line_callback;
gdouble x1, y1, x2, y2;
const PikaControllerSlider *sliders;
gint n_sliders;
gint off_x, off_y;
GeglRectangle area;
slider_line_callback =
(PikaControllerSliderLineCallback) controller->creator_callback;
g_object_get (widget,
"x1", &x1,
"y1", &y1,
"x2", &x2,
"y2", &y2,
NULL);
sliders = pika_tool_line_get_sliders (PIKA_TOOL_LINE (controller->widget),
&n_sliders);
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x1 -= off_x + area.x;
y1 -= off_y + area.y;
x2 -= off_x + area.x;
y2 -= off_y + area.y;
slider_line_callback (controller->creator_data,
&area, x1, y1, x2, y2, sliders, n_sliders);
}
static void
pika_filter_tool_set_transform_grid (Controller *controller,
GeglRectangle *area,
const PikaMatrix3 *transform)
{
PikaTool *tool;
PikaDrawable *drawable;
gdouble x1 = area->x;
gdouble y1 = area->y;
gdouble x2 = area->x + area->width;
gdouble y2 = area->y + area->height;
PikaMatrix3 matrix;
if (! controller->widget)
return;
tool = PIKA_TOOL (controller->filter_tool);
drawable = tool->drawables->data;
if (drawable)
{
gint off_x, off_y;
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
x1 += off_x;
y1 += off_y;
x2 += off_x;
y2 += off_y;
}
pika_matrix3_identity (&matrix);
pika_matrix3_translate (&matrix, -x1, -y1);
pika_matrix3_mult (transform, &matrix);
pika_matrix3_translate (&matrix, +x1, +y1);
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_transform_grid_changed,
controller);
g_object_set (controller->widget,
"transform", &matrix,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
NULL);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_transform_grid_changed,
controller);
}
static void
pika_filter_tool_transform_grid_changed (PikaToolWidget *widget,
Controller *controller)
{
PikaFilterTool *filter_tool = controller->filter_tool;
PikaControllerTransformGridCallback transform_grid_callback;
gint off_x, off_y;
GeglRectangle area;
PikaMatrix3 *transform;
PikaMatrix3 matrix;
transform_grid_callback =
(PikaControllerTransformGridCallback) controller->creator_callback;
g_object_get (widget,
"transform", &transform,
NULL);
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
pika_matrix3_identity (&matrix);
pika_matrix3_translate (&matrix, +(off_x + area.x), +(off_y + area.y));
pika_matrix3_mult (transform, &matrix);
pika_matrix3_translate (&matrix, -(off_x + area.x), -(off_y + area.y));
transform_grid_callback (controller->creator_data,
&area, &matrix);
g_free (transform);
}
static void
pika_filter_tool_set_transform_grids (Controller *controller,
GeglRectangle *area,
const PikaMatrix3 *transforms,
gint n_transforms)
{
PikaTool *tool;
PikaDisplayShell *shell;
PikaDrawable *drawable;
PikaContainer *grids;
PikaToolWidget *grid = NULL;
gdouble x1 = area->x;
gdouble y1 = area->y;
gdouble x2 = area->x + area->width;
gdouble y2 = area->y + area->height;
PikaMatrix3 matrix;
gint i;
if (! controller->widget)
return;
tool = PIKA_TOOL (controller->filter_tool);
shell = pika_display_get_shell (tool->display);
drawable = tool->drawables->data;
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_transform_grids_changed,
controller);
if (drawable)
{
gint off_x, off_y;
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
x1 += off_x;
y1 += off_y;
x2 += off_x;
y2 += off_y;
}
grids = pika_tool_widget_group_get_children (
PIKA_TOOL_WIDGET_GROUP (controller->widget));
if (n_transforms > pika_container_get_n_children (grids))
{
pika_matrix3_identity (&matrix);
for (i = pika_container_get_n_children (grids); i < n_transforms; i++)
{
gdouble pivot_x;
gdouble pivot_y;
grid = pika_tool_transform_grid_new (shell, &matrix, x1, y1, x2, y2);
if (i > 0 && ! memcmp (&transforms[i], &transforms[i - 1],
sizeof (PikaMatrix3)))
{
g_object_get (pika_container_get_last_child (grids),
"pivot-x", &pivot_x,
"pivot-y", &pivot_y,
NULL);
}
else
{
pivot_x = (x1 + x2) / 2.0;
pivot_y = (y1 + y2) / 2.0;
pika_matrix3_transform_point (&transforms[i],
pivot_x, pivot_y,
&pivot_x, &pivot_y);
}
g_object_set (grid,
"pivot-x", pivot_x,
"pivot-y", pivot_y,
"inside-function", PIKA_TRANSFORM_FUNCTION_MOVE,
"outside-function", PIKA_TRANSFORM_FUNCTION_ROTATE,
"use-corner-handles", TRUE,
"use-perspective-handles", TRUE,
"use-side-handles", TRUE,
"use-shear-handles", TRUE,
"use-pivot-handle", TRUE,
NULL);
pika_container_add (grids, PIKA_OBJECT (grid));
g_object_unref (grid);
}
pika_tool_widget_set_focus (grid, TRUE);
}
else
{
while (pika_container_get_n_children (grids) > n_transforms)
pika_container_remove (grids, pika_container_get_last_child (grids));
}
for (i = 0; i < n_transforms; i++)
{
pika_matrix3_identity (&matrix);
pika_matrix3_translate (&matrix, -x1, -y1);
pika_matrix3_mult (&transforms[i], &matrix);
pika_matrix3_translate (&matrix, +x1, +y1);
g_object_set (pika_container_get_child_by_index (grids, i),
"transform", &matrix,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
NULL);
}
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_transform_grids_changed,
controller);
}
static void
pika_filter_tool_transform_grids_changed (PikaToolWidget *widget,
Controller *controller)
{
PikaFilterTool *filter_tool = controller->filter_tool;
PikaControllerTransformGridsCallback transform_grids_callback;
PikaContainer *grids;
gint off_x, off_y;
GeglRectangle area;
PikaMatrix3 *transforms;
gint n_transforms;
gint i;
transform_grids_callback =
(PikaControllerTransformGridsCallback) controller->creator_callback;
grids = pika_tool_widget_group_get_children (
PIKA_TOOL_WIDGET_GROUP (controller->widget));
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
n_transforms = pika_container_get_n_children (grids);
transforms = g_new (PikaMatrix3, n_transforms);
for (i = 0; i < n_transforms; i++)
{
PikaMatrix3 *transform;
g_object_get (pika_container_get_child_by_index (grids, i),
"transform", &transform,
NULL);
pika_matrix3_identity (&transforms[i]);
pika_matrix3_translate (&transforms[i],
+(off_x + area.x), +(off_y + area.y));
pika_matrix3_mult (transform, &transforms[i]);
pika_matrix3_translate (&transforms[i],
-(off_x + area.x), -(off_y + area.y));
g_free (transform);
}
transform_grids_callback (controller->creator_data,
&area, transforms, n_transforms);
g_free (transforms);
}
static void
pika_filter_tool_set_gyroscope (Controller *controller,
GeglRectangle *area,
gdouble yaw,
gdouble pitch,
gdouble roll,
gdouble zoom,
gboolean invert)
{
if (! controller->widget)
return;
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_gyroscope_changed,
controller);
g_object_set (controller->widget,
"yaw", yaw,
"pitch", pitch,
"roll", roll,
"zoom", zoom,
"invert", invert,
NULL);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_gyroscope_changed,
controller);
}
static void
pika_filter_tool_gyroscope_changed (PikaToolWidget *widget,
Controller *controller)
{
PikaFilterTool *filter_tool = controller->filter_tool;
PikaControllerGyroscopeCallback gyroscope_callback;
gint off_x, off_y;
GeglRectangle area;
gdouble yaw;
gdouble pitch;
gdouble roll;
gdouble zoom;
gboolean invert;
gyroscope_callback =
(PikaControllerGyroscopeCallback) controller->creator_callback;
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
g_object_get (widget,
"yaw", &yaw,
"pitch", &pitch,
"roll", &roll,
"zoom", &zoom,
"invert", &invert,
NULL);
gyroscope_callback (controller->creator_data,
&area, yaw, pitch, roll, zoom, invert);
}
static void
pika_filter_tool_set_focus (Controller *controller,
GeglRectangle *area,
PikaLimitType type,
gdouble x,
gdouble y,
gdouble radius,
gdouble aspect_ratio,
gdouble angle,
gdouble inner_limit,
gdouble midpoint)
{
PikaTool *tool;
PikaDrawable *drawable;
if (! controller->widget)
return;
tool = PIKA_TOOL (controller->filter_tool);
drawable = tool->drawables->data;
if (drawable)
{
gint off_x, off_y;
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
x += off_x + area->x;
y += off_y + area->y;
}
g_signal_handlers_block_by_func (controller->widget,
pika_filter_tool_focus_changed,
controller);
g_object_set (controller->widget,
"type", type,
"x", x,
"y", y,
"radius", radius,
"aspect-ratio", aspect_ratio,
"angle", angle,
"inner-limit", inner_limit,
"midpoint", midpoint,
NULL);
g_signal_handlers_unblock_by_func (controller->widget,
pika_filter_tool_focus_changed,
controller);
}
static void
pika_filter_tool_focus_changed (PikaToolWidget *widget,
Controller *controller)
{
PikaFilterTool *filter_tool = controller->filter_tool;
PikaControllerFocusCallback focus_callback;
PikaLimitType type;
gdouble x, y;
gdouble radius;
gdouble aspect_ratio;
gdouble angle;
gdouble inner_limit;
gdouble midpoint;
gint off_x, off_y;
GeglRectangle area;
focus_callback = (PikaControllerFocusCallback) controller->creator_callback;
g_object_get (widget,
"type", &type,
"x", &x,
"y", &y,
"radius", &radius,
"aspect-ratio", &aspect_ratio,
"angle", &angle,
"inner-limit", &inner_limit,
"midpoint", &midpoint,
NULL);
pika_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x -= off_x + area.x;
y -= off_y + area.y;
focus_callback (controller->creator_data,
&area,
type,
x,
y,
radius,
aspect_ratio,
angle,
inner_limit,
midpoint);
}

View File

@ -0,0 +1,40 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikafiltertool-widgets.h
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FILTER_TOOL_WIDGETS_H__
#define __PIKA_FILTER_TOOL_WIDGETS_H__
PikaToolWidget * pika_filter_tool_create_widget (PikaFilterTool *filter_tool,
PikaControllerType controller_type,
const gchar *status_title,
GCallback callback,
gpointer callback_data,
GCallback *set_func,
gpointer *set_func_data);
void pika_filter_tool_reset_widget (PikaFilterTool *filter_tool,
PikaToolWidget *widget);
#endif /* __PIKA_FILTER_TOOL_WIDGETS_H__ */

2057
app/tools/pikafiltertool.c Normal file

File diff suppressed because it is too large Load Diff

153
app/tools/pikafiltertool.h Normal file
View File

@ -0,0 +1,153 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FILTER_TOOL_H__
#define __PIKA_FILTER_TOOL_H__
#include "pikacolortool.h"
#define PIKA_TYPE_FILTER_TOOL (pika_filter_tool_get_type ())
#define PIKA_FILTER_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FILTER_TOOL, PikaFilterTool))
#define PIKA_FILTER_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FILTER_TOOL, PikaFilterToolClass))
#define PIKA_IS_FILTER_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FILTER_TOOL))
#define PIKA_IS_FILTER_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FILTER_TOOL))
#define PIKA_FILTER_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FILTER_TOOL, PikaFilterToolClass))
#define PIKA_FILTER_TOOL_GET_OPTIONS(t) (PIKA_FILTER_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaFilterToolClass PikaFilterToolClass;
struct _PikaFilterTool
{
PikaColorTool parent_instance;
GeglNode *operation;
GObject *config;
GObject *default_config;
PikaContainer *settings;
gchar *description;
gboolean has_settings;
PikaDrawableFilter *filter;
PikaGuide *preview_guide;
gpointer pick_identifier;
gboolean pick_abyss;
/* dialog */
gboolean overlay;
PikaToolGui *gui;
GtkWidget *settings_box;
GtkWidget *controller_toggle;
GtkWidget *operation_settings_box;
GtkWidget *clip_combo;
GtkWidget *region_combo;
GtkWidget *active_picker;
/* widget */
PikaToolWidget *widget;
PikaToolWidget *grab_widget;
};
struct _PikaFilterToolClass
{
PikaColorToolClass parent_class;
/* virtual functions */
gchar * (* get_operation) (PikaFilterTool *filter_tool,
gchar **description);
void (* dialog) (PikaFilterTool *filter_tool);
void (* reset) (PikaFilterTool *filter_tool);
void (* set_config) (PikaFilterTool *filter_tool,
PikaConfig *config);
void (* config_notify) (PikaFilterTool *filter_tool,
PikaConfig *config,
const GParamSpec *pspec);
gboolean (* settings_import) (PikaFilterTool *filter_tool,
GInputStream *input,
GError **error);
gboolean (* settings_export) (PikaFilterTool *filter_tool,
GOutputStream *output,
GError **error);
void (* region_changed) (PikaFilterTool *filter_tool);
void (* color_picked) (PikaFilterTool *filter_tool,
gpointer identifier,
gdouble x,
gdouble y,
const Babl *sample_format,
const PikaRGB *color);
};
GType pika_filter_tool_get_type (void) G_GNUC_CONST;
void pika_filter_tool_get_operation (PikaFilterTool *filter_tool);
void pika_filter_tool_set_config (PikaFilterTool *filter_tool,
PikaConfig *config);
void pika_filter_tool_edit_as (PikaFilterTool *filter_tool,
const gchar *new_tool_id,
PikaConfig *config);
gboolean pika_filter_tool_on_guide (PikaFilterTool *filter_tool,
const PikaCoords *coords,
PikaDisplay *display);
GtkWidget * pika_filter_tool_dialog_get_vbox (PikaFilterTool *filter_tool);
void pika_filter_tool_enable_color_picking (PikaFilterTool *filter_tool,
gpointer identifier,
gboolean pick_abyss);
void pika_filter_tool_disable_color_picking (PikaFilterTool *filter_tool);
GtkWidget * pika_filter_tool_add_color_picker (PikaFilterTool *filter_tool,
gpointer identifier,
const gchar *icon_name,
const gchar *tooltip,
gboolean pick_abyss,
PikaPickerCallback callback,
gpointer callback_data);
GCallback pika_filter_tool_add_controller (PikaFilterTool *filter_tool,
PikaControllerType controller_type,
const gchar *status_title,
GCallback callback,
gpointer callback_data,
gpointer *set_func_data);
void pika_filter_tool_set_widget (PikaFilterTool *filter_tool,
PikaToolWidget *widget);
gboolean pika_filter_tool_get_drawable_area (PikaFilterTool *filter_tool,
gint *drawable_offset_x,
gint *drawable_offset_y,
GeglRectangle *drawable_area);
#endif /* __PIKA_FILTER_TOOL_H__ */

167
app/tools/pikaflipoptions.c Normal file
View File

@ -0,0 +1,167 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikawidgets-utils.h"
#include "pikaflipoptions.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_FLIP_TYPE
};
static void pika_flip_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_flip_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaFlipOptions, pika_flip_options,
PIKA_TYPE_TRANSFORM_OPTIONS)
static void
pika_flip_options_class_init (PikaFlipOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_flip_options_set_property;
object_class->get_property = pika_flip_options_get_property;
PIKA_CONFIG_PROP_ENUM (object_class, PROP_FLIP_TYPE,
"flip-type",
_("Flip Type"),
_("Direction of flipping"),
PIKA_TYPE_ORIENTATION_TYPE,
PIKA_ORIENTATION_HORIZONTAL,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_flip_options_init (PikaFlipOptions *options)
{
}
static void
pika_flip_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaFlipOptions *options = PIKA_FLIP_OPTIONS (object);
switch (property_id)
{
case PROP_FLIP_TYPE:
options->flip_type = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_flip_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaFlipOptions *options = PIKA_FLIP_OPTIONS (object);
switch (property_id)
{
case PROP_FLIP_TYPE:
g_value_set_enum (value, options->flip_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
pika_flip_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
PikaFlipOptions *options = PIKA_FLIP_OPTIONS (tool_options);
PikaTransformOptions *tr_options = PIKA_TRANSFORM_OPTIONS (tool_options);
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *combo;
gchar *str;
GtkListStore *clip_model;
GdkModifierType toggle_mask;
vbox = pika_transform_options_gui (tool_options, FALSE, FALSE, FALSE);
toggle_mask = pika_get_toggle_behavior_mask ();
/* tool toggle */
str = g_strdup_printf (_("Direction (%s)"),
pika_get_mod_string (toggle_mask));
frame = pika_prop_enum_radio_frame_new (config, "flip-type",
str,
PIKA_ORIENTATION_HORIZONTAL,
PIKA_ORIENTATION_VERTICAL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
g_free (str);
options->direction_frame = frame;
/* the clipping menu */
clip_model = pika_enum_store_new_with_range (PIKA_TYPE_TRANSFORM_RESIZE,
PIKA_TRANSFORM_RESIZE_ADJUST,
PIKA_TRANSFORM_RESIZE_CLIP);
combo = pika_prop_enum_combo_box_new (config, "clip", 0, 0);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (clip_model));
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (combo), tr_options->clip);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Clipping"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
g_object_unref (clip_model);
return vbox;
}

View File

@ -0,0 +1,56 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FLIP_OPTIONS_H__
#define __PIKA_FLIP_OPTIONS_H__
#include "pikatransformoptions.h"
#define PIKA_TYPE_FLIP_OPTIONS (pika_flip_options_get_type ())
#define PIKA_FLIP_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FLIP_OPTIONS, PikaFlipOptions))
#define PIKA_FLIP_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FLIP_OPTIONS, PikaFlipOptionsClass))
#define PIKA_IS_FLIP_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FLIP_OPTIONS))
#define PIKA_IS_FLIP_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FLIP_OPTIONS))
#define PIKA_FLIP_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FLIP_OPTIONS, PikaFlipOptionsClass))
typedef struct _PikaFlipOptions PikaFlipOptions;
typedef struct _PikaToolOptionsClass PikaFlipOptionsClass;
struct _PikaFlipOptions
{
PikaTransformOptions parent_instance;
PikaOrientationType flip_type;
/* options gui */
GtkWidget *direction_frame;
};
GType pika_flip_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_flip_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_FLIP_OPTIONS_H__ */

454
app/tools/pikafliptool.c Normal file
View File

@ -0,0 +1,454 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "config/pikadisplayconfig.h"
#include "core/pikadrawable-transform.h"
#include "core/pikaguide.h"
#include "core/pikaimage.h"
#include "core/pikaimage-flip.h"
#include "core/pikaimage-item-list.h"
#include "core/pikaimage-pick-item.h"
#include "core/pikalayer.h"
#include "core/pikalayermask.h"
#include "core/pikapickable.h"
#include "core/pikaprogress.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"
#include "display/pikacanvasitem.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikadisplayshell-appearance.h"
#include "pikaflipoptions.h"
#include "pikafliptool.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
/* local function prototypes */
static void pika_flip_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display);
static void pika_flip_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display);
static void pika_flip_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display);
static void pika_flip_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display);
static void pika_flip_tool_draw (PikaDrawTool *draw_tool);
static gchar * pika_flip_tool_get_undo_desc (PikaTransformTool *tr_tool);
static GeglBuffer * pika_flip_tool_transform (PikaTransformTool *tr_tool,
GList *objects,
GeglBuffer *orig_buffer,
gint orig_offset_x,
gint orig_offset_y,
PikaColorProfile **buffer_profile,
gint *new_offset_x,
gint *new_offset_y);
static PikaOrientationType pika_flip_tool_get_flip_type (PikaFlipTool *flip);
G_DEFINE_TYPE (PikaFlipTool, pika_flip_tool, PIKA_TYPE_TRANSFORM_TOOL)
#define parent_class pika_flip_tool_parent_class
void
pika_flip_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_FLIP_TOOL,
PIKA_TYPE_FLIP_OPTIONS,
pika_flip_options_gui,
PIKA_CONTEXT_PROP_MASK_BACKGROUND,
"pika-flip-tool",
_("Flip"),
_("Flip Tool: "
"Reverse the layer, selection or path horizontally or vertically"),
N_("_Flip"), "<shift>F",
NULL, PIKA_HELP_TOOL_FLIP,
PIKA_ICON_TOOL_FLIP,
data);
}
static void
pika_flip_tool_class_init (PikaFlipToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaDrawToolClass *draw_tool_class = PIKA_DRAW_TOOL_CLASS (klass);
PikaTransformToolClass *tr_class = PIKA_TRANSFORM_TOOL_CLASS (klass);
tool_class->button_press = pika_flip_tool_button_press;
tool_class->modifier_key = pika_flip_tool_modifier_key;
tool_class->oper_update = pika_flip_tool_oper_update;
tool_class->cursor_update = pika_flip_tool_cursor_update;
draw_tool_class->draw = pika_flip_tool_draw;
tr_class->get_undo_desc = pika_flip_tool_get_undo_desc;
tr_class->transform = pika_flip_tool_transform;
tr_class->undo_desc = C_("undo-type", "Flip");
tr_class->progress_text = _("Flipping");
}
static void
pika_flip_tool_init (PikaFlipTool *flip_tool)
{
PikaTool *tool = PIKA_TOOL (flip_tool);
pika_tool_control_set_snap_to (tool->control, FALSE);
pika_tool_control_set_precision (tool->control,
PIKA_CURSOR_PRECISION_PIXEL_CENTER);
pika_tool_control_set_cursor (tool->control, PIKA_CURSOR_MOUSE);
pika_tool_control_set_toggle_cursor (tool->control, PIKA_CURSOR_MOUSE);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_FLIP_HORIZONTAL);
pika_tool_control_set_toggle_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_FLIP_VERTICAL);
flip_tool->guide = NULL;
}
static void
pika_flip_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display)
{
PikaTransformTool *tr_tool = PIKA_TRANSFORM_TOOL (tool);
tool->display = display;
pika_transform_tool_transform (tr_tool, display);
pika_tool_control (tool, PIKA_TOOL_ACTION_HALT, display);
}
static void
pika_flip_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display)
{
PikaFlipOptions *options = PIKA_FLIP_TOOL_GET_OPTIONS (tool);
if (key == pika_get_toggle_behavior_mask ())
{
switch (options->flip_type)
{
case PIKA_ORIENTATION_HORIZONTAL:
g_object_set (options,
"flip-type", PIKA_ORIENTATION_VERTICAL,
NULL);
break;
case PIKA_ORIENTATION_VERTICAL:
g_object_set (options,
"flip-type", PIKA_ORIENTATION_HORIZONTAL,
NULL);
break;
default:
break;
}
}
}
static void
pika_flip_tool_oper_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
gboolean proximity,
PikaDisplay *display)
{
PikaFlipTool *flip = PIKA_FLIP_TOOL (tool);
PikaDrawTool *draw_tool = PIKA_DRAW_TOOL (tool);
PikaFlipOptions *options = PIKA_FLIP_TOOL_GET_OPTIONS (tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
PikaGuide *guide = NULL;
if (pika_display_shell_get_show_guides (shell) &&
proximity)
{
gint snap_distance = display->config->snap_distance;
guide = pika_image_pick_guide (image, coords->x, coords->y,
FUNSCALEX (shell, snap_distance),
FUNSCALEY (shell, snap_distance));
}
if (flip->guide != guide ||
(guide && ! pika_draw_tool_is_active (draw_tool)))
{
pika_draw_tool_pause (draw_tool);
if (pika_draw_tool_is_active (draw_tool) &&
draw_tool->display != display)
pika_draw_tool_stop (draw_tool);
flip->guide = guide;
if (! pika_draw_tool_is_active (draw_tool))
pika_draw_tool_start (draw_tool, display);
pika_draw_tool_resume (draw_tool);
}
gtk_widget_set_sensitive (options->direction_frame, guide == NULL);
PIKA_TOOL_CLASS (parent_class)->oper_update (tool,
coords, state, proximity,
display);
}
static void
pika_flip_tool_cursor_update (PikaTool *tool,
const PikaCoords *coords,
GdkModifierType state,
PikaDisplay *display)
{
PikaTransformTool *tr_tool = PIKA_TRANSFORM_TOOL (tool);
PikaFlipTool *flip = PIKA_FLIP_TOOL (tool);
GList *selected_objects;
selected_objects = pika_transform_tool_check_selected_objects (tr_tool, display, NULL);
if (! selected_objects)
{
pika_tool_set_cursor (tool, display,
pika_tool_control_get_cursor (tool->control),
pika_tool_control_get_tool_cursor (tool->control),
PIKA_CURSOR_MODIFIER_BAD);
return;
}
g_list_free (selected_objects);
pika_tool_control_set_toggled (tool->control,
pika_flip_tool_get_flip_type (flip) ==
PIKA_ORIENTATION_VERTICAL);
PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
static void
pika_flip_tool_draw (PikaDrawTool *draw_tool)
{
PikaFlipTool *flip = PIKA_FLIP_TOOL (draw_tool);
if (flip->guide)
{
PikaCanvasItem *item;
PikaGuideStyle style;
style = pika_guide_get_style (flip->guide);
item = pika_draw_tool_add_guide (draw_tool,
pika_guide_get_orientation (flip->guide),
pika_guide_get_position (flip->guide),
style);
pika_canvas_item_set_highlight (item, TRUE);
}
}
static gchar *
pika_flip_tool_get_undo_desc (PikaTransformTool *tr_tool)
{
PikaFlipTool *flip = PIKA_FLIP_TOOL (tr_tool);
switch (pika_flip_tool_get_flip_type (flip))
{
case PIKA_ORIENTATION_HORIZONTAL:
return g_strdup (C_("undo-type", "Flip horizontally"));
case PIKA_ORIENTATION_VERTICAL:
return g_strdup (C_("undo-type", "Flip vertically"));
default:
/* probably this is not actually reached today, but
* could be if someone defined FLIP_DIAGONAL, say...
*/
return PIKA_TRANSFORM_TOOL_CLASS (parent_class)->get_undo_desc (tr_tool);
}
}
static GeglBuffer *
pika_flip_tool_transform (PikaTransformTool *tr_tool,
GList *objects,
GeglBuffer *orig_buffer,
gint orig_offset_x,
gint orig_offset_y,
PikaColorProfile **buffer_profile,
gint *new_offset_x,
gint *new_offset_y)
{
PikaFlipTool *flip = PIKA_FLIP_TOOL (tr_tool);
PikaFlipOptions *options = PIKA_FLIP_TOOL_GET_OPTIONS (tr_tool);
PikaTransformOptions *tr_options = PIKA_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
PikaContext *context = PIKA_CONTEXT (options);
PikaOrientationType flip_type = PIKA_ORIENTATION_UNKNOWN;
gdouble axis = 0.0;
gboolean clip_result = FALSE;
GeglBuffer *ret = NULL;
flip_type = pika_flip_tool_get_flip_type (flip);
if (flip->guide)
{
axis = pika_guide_get_position (flip->guide);
}
else
{
switch (flip_type)
{
case PIKA_ORIENTATION_HORIZONTAL:
axis = ((gdouble) tr_tool->x1 +
(gdouble) (tr_tool->x2 - tr_tool->x1) / 2.0);
break;
case PIKA_ORIENTATION_VERTICAL:
axis = ((gdouble) tr_tool->y1 +
(gdouble) (tr_tool->y2 - tr_tool->y1) / 2.0);
break;
default:
break;
}
}
switch (tr_options->clip)
{
case PIKA_TRANSFORM_RESIZE_ADJUST:
clip_result = FALSE;
break;
case PIKA_TRANSFORM_RESIZE_CLIP:
clip_result = TRUE;
break;
default:
g_return_val_if_reached (NULL);
}
if (orig_buffer)
{
/* this happens when transforming a selection cut out of a
* normal drawable
*/
g_return_val_if_fail (PIKA_IS_DRAWABLE (objects->data), NULL);
ret = pika_drawable_transform_buffer_flip (PIKA_DRAWABLE (objects->data),
context,
orig_buffer,
orig_offset_x,
orig_offset_y,
flip_type, axis,
clip_result,
buffer_profile,
new_offset_x,
new_offset_y);
}
else if (g_list_length (objects) == 1 && PIKA_IS_IMAGE (objects->data))
{
/* this happens for images */
PikaTransformToolClass *tr_class = PIKA_TRANSFORM_TOOL_GET_CLASS (tr_tool);
PikaProgress *progress;
progress = pika_progress_start (PIKA_PROGRESS (tr_tool), FALSE,
"%s", tr_class->progress_text);
pika_image_flip_full (PIKA_IMAGE (objects->data), context,
flip_type, axis, clip_result,
progress);
if (progress)
pika_progress_end (progress);
}
else
{
/* this happens for entire drawables, paths and layer groups */
pika_image_item_list_flip (pika_item_get_image (objects->data),
objects, context,
flip_type, axis, clip_result);
}
return ret;
}
static PikaOrientationType
pika_flip_tool_get_flip_type (PikaFlipTool *flip)
{
PikaFlipOptions *options = PIKA_FLIP_TOOL_GET_OPTIONS (flip);
if (flip->guide)
{
switch (pika_guide_get_orientation (flip->guide))
{
case PIKA_ORIENTATION_HORIZONTAL:
return PIKA_ORIENTATION_VERTICAL;
case PIKA_ORIENTATION_VERTICAL:
return PIKA_ORIENTATION_HORIZONTAL;
default:
return pika_guide_get_orientation (flip->guide);
}
}
else
{
return options->flip_type;
}
}

61
app/tools/pikafliptool.h Normal file
View File

@ -0,0 +1,61 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FLIP_TOOL_H__
#define __PIKA_FLIP_TOOL_H__
#include "pikatransformtool.h"
#define PIKA_TYPE_FLIP_TOOL (pika_flip_tool_get_type ())
#define PIKA_FLIP_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FLIP_TOOL, PikaFlipTool))
#define PIKA_FLIP_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FLIP_TOOL, PikaFlipToolClass))
#define PIKA_IS_FLIP_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FLIP_TOOL))
#define PIKA_IS_FLIP_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FLIP_TOOL))
#define PIKA_FLIP_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FLIP_TOOL, PikaFlipToolClass))
#define PIKA_FLIP_TOOL_GET_OPTIONS(t) (PIKA_FLIP_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaFlipTool PikaFlipTool;
typedef struct _PikaFlipToolClass PikaFlipToolClass;
struct _PikaFlipTool
{
PikaTransformTool parent_instance;
PikaGuide *guide;
};
struct _PikaFlipToolClass
{
PikaTransformToolClass parent_class;
};
void pika_flip_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_flip_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_FLIP_TOOL_H__ */

View File

@ -0,0 +1,395 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikacolorpanel.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-constructors.h"
#include "widgets/pikawidgets-utils.h"
#include "pikaforegroundselectoptions.h"
#include "pikatooloptions-gui.h"
#include "pika-intl.h"
/*
* for matting-global: iterations int
* for matting-levin: levels int, active levels int
*/
enum
{
PROP_0,
PROP_DRAW_MODE,
PROP_PREVIEW_MODE,
PROP_STROKE_WIDTH,
PROP_MASK_COLOR,
PROP_ENGINE,
PROP_ITERATIONS,
PROP_LEVELS,
PROP_ACTIVE_LEVELS
};
static void pika_foreground_select_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_foreground_select_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaForegroundSelectOptions, pika_foreground_select_options,
PIKA_TYPE_SELECTION_OPTIONS)
static void
pika_foreground_select_options_class_init (PikaForegroundSelectOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaRGB blue = {0.0, 0.0, 1.0, 0.5};
object_class->set_property = pika_foreground_select_options_set_property;
object_class->get_property = pika_foreground_select_options_get_property;
/* override the antialias default value from PikaSelectionOptions */
PIKA_CONFIG_PROP_ENUM (object_class, PROP_DRAW_MODE,
"draw-mode",
_("Draw Mode"),
_("Paint over areas to mark color values for "
"inclusion or exclusion from selection"),
PIKA_TYPE_MATTING_DRAW_MODE,
PIKA_MATTING_DRAW_MODE_FOREGROUND,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_PREVIEW_MODE,
"preview-mode",
_("Preview Mode"),
_("Preview Mode"),
PIKA_TYPE_MATTING_PREVIEW_MODE,
PIKA_MATTING_PREVIEW_MODE_ON_COLOR,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_STROKE_WIDTH,
"stroke-width",
_("Stroke width"),
_("Size of the brush used for refinements"),
1, 6000, 10,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_RGB (object_class, PROP_MASK_COLOR,
"mask-color",
_("Preview color"),
_("Color of selection preview mask"),
PIKA_TYPE_RGB,
&blue,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_ENGINE,
"engine",
_("Engine"),
_("Matting engine to use"),
PIKA_TYPE_MATTING_ENGINE,
PIKA_MATTING_ENGINE_LEVIN,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_LEVELS,
"levels",
_("Levels"),
_("Number of downsampled levels to use"),
1, 10, 2,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_ACTIVE_LEVELS,
"active-levels",
_("Active levels"),
_("Number of levels to perform solving"),
1, 10, 2,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_ITERATIONS,
"iterations",
_("Iterations"),
_("Number of iterations to perform"),
1, 10, 2,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_foreground_select_options_init (PikaForegroundSelectOptions *options)
{
}
static void
pika_foreground_select_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaForegroundSelectOptions *options = PIKA_FOREGROUND_SELECT_OPTIONS (object);
PikaRGB *color;
switch (property_id)
{
case PROP_DRAW_MODE:
options->draw_mode = g_value_get_enum (value);
break;
case PROP_PREVIEW_MODE:
options->preview_mode = g_value_get_enum (value);
break;
case PROP_STROKE_WIDTH:
options->stroke_width = g_value_get_int (value);
break;
case PROP_MASK_COLOR:
color = g_value_get_boxed (value);
options->mask_color = *color;
break;
case PROP_ENGINE:
options->engine = g_value_get_enum (value);
if ((options->engine == PIKA_MATTING_ENGINE_LEVIN) &&
!(gegl_has_operation ("gegl:matting-levin")))
{
options->engine = PIKA_MATTING_ENGINE_GLOBAL;
}
break;
case PROP_LEVELS:
options->levels = g_value_get_int (value);
break;
case PROP_ACTIVE_LEVELS:
options->active_levels = g_value_get_int (value);
break;
case PROP_ITERATIONS:
options->iterations = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_foreground_select_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaForegroundSelectOptions *options = PIKA_FOREGROUND_SELECT_OPTIONS (object);
switch (property_id)
{
case PROP_DRAW_MODE:
g_value_set_enum (value, options->draw_mode);
break;
case PROP_PREVIEW_MODE:
g_value_set_enum (value, options->preview_mode);
break;
case PROP_STROKE_WIDTH:
g_value_set_int (value, options->stroke_width);
break;
case PROP_MASK_COLOR:
g_value_set_boxed (value, &options->mask_color);
break;
case PROP_ENGINE:
g_value_set_enum (value, options->engine);
break;
case PROP_LEVELS:
g_value_set_int (value, options->levels);
break;
case PROP_ACTIVE_LEVELS:
g_value_set_int (value, options->active_levels);
break;
case PROP_ITERATIONS:
g_value_set_int (value, options->iterations);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_foreground_select_options_reset_stroke_width (GtkWidget *button,
PikaToolOptions *tool_options)
{
g_object_set (tool_options, "stroke-width", 10, NULL);
}
static gboolean
pika_foreground_select_options_sync_engine (GBinding *binding,
const GValue *source_value,
GValue *target_value,
gpointer user_data)
{
gint type = g_value_get_enum (source_value);
g_value_set_boolean (target_value,
type == GPOINTER_TO_INT (user_data));
return TRUE;
}
GtkWidget *
pika_foreground_select_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_selection_options_gui (tool_options);
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *scale;
GtkWidget *combo;
GtkWidget *inner_vbox;
GtkWidget *antialias_toggle;
antialias_toggle = PIKA_SELECTION_OPTIONS (tool_options)->antialias_toggle;
gtk_widget_hide (antialias_toggle);
frame = pika_prop_enum_radio_frame_new (config, "draw-mode", NULL,
0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* stroke width */
scale = pika_prop_spin_scale_new (config, "stroke-width",
1.0, 10.0, 2);
pika_spin_scale_set_scale_limits (PIKA_SPIN_SCALE (scale), 1.0, 1000.0);
pika_spin_scale_set_gamma (PIKA_SPIN_SCALE (scale), 1.7);
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
button = pika_icon_button_new (PIKA_ICON_RESET, NULL);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_image_set_from_icon_name (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (button))),
PIKA_ICON_RESET, GTK_ICON_SIZE_MENU);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "clicked",
G_CALLBACK (pika_foreground_select_options_reset_stroke_width),
tool_options);
pika_help_set_help_data (button,
_("Reset stroke width native size"), NULL);
/* preview mode */
frame = pika_prop_enum_radio_frame_new (config, "preview-mode", NULL,
0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
/* mask color */
button = pika_prop_color_button_new (config, "mask-color",
NULL,
128, 24,
PIKA_COLOR_AREA_SMALL_CHECKS);
pika_color_panel_set_context (PIKA_COLOR_PANEL (button),
PIKA_CONTEXT (config));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* engine */
frame = pika_frame_new (NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
combo = pika_prop_enum_combo_box_new (config, "engine", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Engine"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_frame_set_label_widget (GTK_FRAME (frame), combo);
if (! gegl_has_operation ("gegl:matting-levin"))
gtk_widget_set_sensitive (combo, FALSE);
inner_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_container_add (GTK_CONTAINER (frame), inner_vbox);
gtk_widget_show (inner_vbox);
/* engine parameters */
scale = pika_prop_spin_scale_new (config, "levels",
1.0, 1.0, 0);
gtk_box_pack_start (GTK_BOX (inner_vbox), scale, FALSE, FALSE, 0);
g_object_bind_property_full (config, "engine",
scale, "visible",
G_BINDING_SYNC_CREATE,
pika_foreground_select_options_sync_engine,
NULL,
GINT_TO_POINTER (PIKA_MATTING_ENGINE_LEVIN),
NULL);
scale = pika_prop_spin_scale_new (config, "active-levels",
1.0, 1.0, 0);
gtk_box_pack_start (GTK_BOX (inner_vbox), scale, FALSE, FALSE, 0);
g_object_bind_property_full (config, "engine",
scale, "visible",
G_BINDING_SYNC_CREATE,
pika_foreground_select_options_sync_engine,
NULL,
GINT_TO_POINTER (PIKA_MATTING_ENGINE_LEVIN),
NULL);
scale = pika_prop_spin_scale_new (config, "iterations",
1.0, 1.0, 0);
gtk_box_pack_start (GTK_BOX (inner_vbox), scale, FALSE, FALSE, 0);
g_object_bind_property_full (config, "engine",
scale, "visible",
G_BINDING_SYNC_CREATE,
pika_foreground_select_options_sync_engine,
NULL,
GINT_TO_POINTER (PIKA_MATTING_ENGINE_GLOBAL),
NULL);
return vbox;
}

View File

@ -0,0 +1,68 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FOREGROUND_SELECT_OPTIONS_H__
#define __PIKA_FOREGROUND_SELECT_OPTIONS_H__
#include "pikaselectionoptions.h"
#define PIKA_TYPE_FOREGROUND_SELECT_OPTIONS (pika_foreground_select_options_get_type ())
#define PIKA_FOREGROUND_SELECT_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FOREGROUND_SELECT_OPTIONS, PikaForegroundSelectOptions))
#define PIKA_FOREGROUND_SELECT_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FOREGROUND_SELECT_OPTIONS, PikaForegroundSelectOptionsClass))
#define PIKA_IS_FOREGROUND_SELECT_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FOREGROUND_SELECT_OPTIONS))
#define PIKA_IS_FOREGROUND_SELECT_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FOREGROUND_SELECT_OPTIONS))
#define PIKA_FOREGROUND_SELECT_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FOREGROUND_SELECT_OPTIONS, PikaForegroundSelectOptionsClass))
typedef struct _PikaForegroundSelectOptions PikaForegroundSelectOptions;
typedef struct _PikaForegroundSelectOptionsClass PikaForegroundSelectOptionsClass;
struct _PikaForegroundSelectOptions
{
PikaSelectionOptions parent_instance;
PikaMattingDrawMode draw_mode;
PikaMattingPreviewMode preview_mode;
gint stroke_width;
PikaRGB mask_color;
PikaMattingEngine engine;
gint levels;
gint active_levels;
gint iterations;
};
struct _PikaForegroundSelectOptionsClass
{
PikaSelectionOptionsClass parent_class;
};
GType pika_foreground_select_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_foreground_select_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_FOREGROUND_SELECT_OPTIONS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FOREGROUND_SELECT_TOOL_H__
#define __PIKA_FOREGROUND_SELECT_TOOL_H__
#include "pikapolygonselecttool.h"
typedef enum
{
MATTING_STATE_FREE_SELECT = 0,
MATTING_STATE_PAINT_TRIMAP,
MATTING_STATE_PREVIEW_MASK,
} MattingState;
#define PIKA_TYPE_FOREGROUND_SELECT_TOOL (pika_foreground_select_tool_get_type ())
#define PIKA_FOREGROUND_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FOREGROUND_SELECT_TOOL, PikaForegroundSelectTool))
#define PIKA_FOREGROUND_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FOREGROUND_SELECT_TOOL, PikaForegroundSelectToolClass))
#define PIKA_IS_FOREGROUND_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FOREGROUND_SELECT_TOOL))
#define PIKA_IS_FOREGROUND_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FOREGROUND_SELECT_TOOL))
#define PIKA_FOREGROUND_SELECT_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FOREGROUND_SELECT_TOOL, PikaForegroundSelectToolClass))
#define PIKA_FOREGROUND_SELECT_TOOL_GET_OPTIONS(t) (PIKA_FOREGROUND_SELECT_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaForegroundSelectTool PikaForegroundSelectTool;
typedef struct _PikaForegroundSelectToolClass PikaForegroundSelectToolClass;
struct _PikaForegroundSelectTool
{
PikaPolygonSelectTool parent_instance;
MattingState state;
PikaCoords last_coords;
GArray *stroke;
GeglBuffer *trimap;
GeglBuffer *mask;
GList *undo_stack;
GList *redo_stack;
PikaToolGui *gui;
GtkWidget *preview_toggle;
PikaCanvasItem *grayscale_preview;
};
struct _PikaForegroundSelectToolClass
{
PikaPolygonSelectToolClass parent_class;
};
void pika_foreground_select_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_foreground_select_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_FOREGROUND_SELECT_TOOL_H__ */

View File

@ -0,0 +1,165 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if 0
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "tools-types.h"
#include "pikaforegroundselecttool.h"
#include "pikaforegroundselecttoolundo.h"
enum
{
PROP_0,
PROP_FOREGROUND_SELECT_TOOL
};
static void pika_foreground_select_tool_undo_constructed (GObject *object);
static void pika_foreground_select_tool_undo_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_foreground_select_tool_undo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_foreground_select_tool_undo_pop (PikaUndo *undo,
PikaUndoMode undo_mode,
PikaUndoAccumulator *accum);
static void pika_foreground_select_tool_undo_free (PikaUndo *undo,
PikaUndoMode undo_mode);
G_DEFINE_TYPE (PikaForegroundSelectToolUndo, pika_foreground_select_tool_undo,
PIKA_TYPE_UNDO)
#define parent_class pika_foreground_select_tool_undo_parent_class
static void
pika_foreground_select_tool_undo_class_init (PikaForegroundSelectToolUndoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaUndoClass *undo_class = PIKA_UNDO_CLASS (klass);
object_class->constructed = pika_foreground_select_tool_undo_constructed;
object_class->set_property = pika_foreground_select_tool_undo_set_property;
object_class->get_property = pika_foreground_select_tool_undo_get_property;
undo_class->pop = pika_foreground_select_tool_undo_pop;
undo_class->free = pika_foreground_select_tool_undo_free;
g_object_class_install_property (object_class, PROP_FOREGROUND_SELECT_TOOL,
g_param_spec_object ("foreground-select-tool",
NULL, NULL,
PIKA_TYPE_FOREGROUND_SELECT_TOOL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
pika_foreground_select_tool_undo_init (PikaForegroundSelectToolUndo *undo)
{
}
static void
pika_foreground_select_tool_undo_constructed (GObject *object)
{
PikaForegroundSelectToolUndo *fg_select_tool_undo;
G_OBJECT_CLASS (parent_class)->constructed (object);
fg_select_tool_undo = PIKA_FOREGROUND_SELECT_TOOL_UNDO (object);
pika_assert (PIKA_IS_FOREGROUND_SELECT_TOOL (fg_select_tool_undo->foreground_select_tool));
}
static void
pika_foreground_select_tool_undo_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaForegroundSelectToolUndo *fg_select_tool_undo =
PIKA_FOREGROUND_SELECT_TOOL_UNDO (object);
switch (property_id)
{
case PROP_FOREGROUND_SELECT_TOOL:
g_set_weak_pointer (&fg_select_tool_undo->foreground_select_tool,
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_foreground_select_tool_undo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaForegroundSelectToolUndo *fg_select_tool_undo =
PIKA_FOREGROUND_SELECT_TOOL_UNDO (object);
switch (property_id)
{
case PROP_FOREGROUND_SELECT_TOOL:
g_value_set_object (value, fg_select_tool_undo->foreground_select_tool);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_foreground_select_tool_undo_pop (PikaUndo *undo,
PikaUndoMode undo_mode,
PikaUndoAccumulator *accum)
{
PIKA_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
}
static void
pika_foreground_select_tool_undo_free (PikaUndo *undo,
PikaUndoMode undo_mode)
{
PikaForegroundSelectToolUndo *fg_select_tool_undo = PIKA_FOREGROUND_SELECT_TOOL_UNDO (undo);
g_clear_weak_pointer (&fg_select_tool_undo->foreground_select_tool);
PIKA_UNDO_CLASS (parent_class)->free (undo, undo_mode);
}
#endif

View File

@ -0,0 +1,60 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if 0
#ifndef __PIKA_FOREGROUND_SELECT_TOOL_UNDO_H__
#define __PIKA_FOREGROUND_SELECT_TOOL_UNDO_H__
#include "core/pikaundo.h"
#define PIKA_TYPE_FOREGROUND_SELECT_TOOL_UNDO (pika_foreground_select_tool_undo_get_type ())
#define PIKA_FOREGROUND_SELECT_TOOL_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FOREGROUND_SELECT_TOOL_UNDO, PikaForegroundSelectToolUndo))
#define PIKA_FOREGROUND_SELECT_TOOL_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FOREGROUND_SELECT_TOOL_UNDO, PikaForegroundSelectToolUndoClass))
#define PIKA_IS_FOREGROUND_SELECT_TOOL_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FOREGROUND_SELECT_TOOL_UNDO))
#define PIKA_IS_FOREGROUND_SELECT_TOOL_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FOREGROUND_SELECT_TOOL_UNDO))
#define PIKA_FOREGROUND_SELECT_TOOL_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FOREGROUND_SELECT_TOOL_UNDO, PikaForegroundSelectToolUndoClass))
typedef struct _PikaForegroundSelectToolUndo PikaForegroundSelectToolUndo;
typedef struct _PikaForegroundSelectToolUndoClass PikaForegroundSelectToolUndoClass;
struct _PikaForegroundSelectToolUndo
{
PikaUndo parent_instance;
PikaForegroundSelectTool *foreground_select_tool;
};
struct _PikaForegroundSelectToolUndoClass
{
PikaUndoClass parent_class;
};
GType pika_foreground_select_tool_undo_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_FOREGROUND_SELECT_TOOL_UNDO_H__ */
#endif

View File

@ -0,0 +1,359 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Major improvement to support polygonal segments
* Copyright (C) 2008 Martin Nordholts
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pikachannel.h"
#include "core/pikachannel-select.h"
#include "core/pikaimage.h"
#include "core/pikalayer-floating-selection.h"
#include "widgets/pikahelp-ids.h"
#include "display/pikadisplay.h"
#include "display/pikatoolpolygon.h"
#include "pikafreeselecttool.h"
#include "pikaselectionoptions.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
struct _PikaFreeSelectToolPrivate
{
gboolean started;
gboolean changed;
/* The selection operation active when the tool was started */
PikaChannelOps operation_at_start;
};
static void pika_free_select_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display);
static void pika_free_select_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display);
static void pika_free_select_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display);
static void pika_free_select_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec);
static gboolean pika_free_select_tool_have_selection (PikaSelectionTool *sel_tool,
PikaDisplay *display);
static void pika_free_select_tool_change_complete (PikaPolygonSelectTool *poly_sel,
PikaDisplay *display);
static void pika_free_select_tool_commit (PikaFreeSelectTool *free_sel,
PikaDisplay *display);
static void pika_free_select_tool_halt (PikaFreeSelectTool *free_sel);
static gboolean pika_free_select_tool_select (PikaFreeSelectTool *free_sel,
PikaDisplay *display);
G_DEFINE_TYPE_WITH_PRIVATE (PikaFreeSelectTool, pika_free_select_tool,
PIKA_TYPE_POLYGON_SELECT_TOOL)
#define parent_class pika_free_select_tool_parent_class
void
pika_free_select_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_FREE_SELECT_TOOL,
PIKA_TYPE_SELECTION_OPTIONS,
pika_selection_options_gui,
0,
"pika-free-select-tool",
_("Free Select"),
_("Free Select Tool: Select a hand-drawn region with free "
"and polygonal segments"),
N_("_Free Select"), "F",
NULL, PIKA_HELP_TOOL_FREE_SELECT,
PIKA_ICON_TOOL_FREE_SELECT,
data);
}
static void
pika_free_select_tool_class_init (PikaFreeSelectToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaSelectionToolClass *sel_class = PIKA_SELECTION_TOOL_CLASS (klass);
PikaPolygonSelectToolClass *poly_sel_class = PIKA_POLYGON_SELECT_TOOL_CLASS (klass);
tool_class->control = pika_free_select_tool_control;
tool_class->button_press = pika_free_select_tool_button_press;
tool_class->button_release = pika_free_select_tool_button_release;
tool_class->options_notify = pika_free_select_tool_options_notify;
sel_class->have_selection = pika_free_select_tool_have_selection;
poly_sel_class->change_complete = pika_free_select_tool_change_complete;
}
static void
pika_free_select_tool_init (PikaFreeSelectTool *free_sel)
{
PikaTool *tool = PIKA_TOOL (free_sel);
PikaSelectionTool *sel_tool = PIKA_SELECTION_TOOL (tool);
free_sel->priv = pika_free_select_tool_get_instance_private (free_sel);
pika_tool_control_set_preserve (tool->control, FALSE);
pika_tool_control_set_dirty_mask (tool->control,
PIKA_DIRTY_SELECTION);
pika_tool_control_set_dirty_action (tool->control,
PIKA_TOOL_ACTION_COMMIT);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_FREE_SELECT);
sel_tool->allow_move = TRUE;
}
static void
pika_free_select_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display)
{
PikaFreeSelectTool *free_sel = PIKA_FREE_SELECT_TOOL (tool);
switch (action)
{
case PIKA_TOOL_ACTION_PAUSE:
case PIKA_TOOL_ACTION_RESUME:
break;
case PIKA_TOOL_ACTION_HALT:
pika_free_select_tool_halt (free_sel);
break;
case PIKA_TOOL_ACTION_COMMIT:
pika_free_select_tool_commit (free_sel, display);
break;
}
PIKA_TOOL_CLASS (parent_class)->control (tool, action, display);
}
static void
pika_free_select_tool_button_press (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonPressType press_type,
PikaDisplay *display)
{
PikaSelectionOptions *options = PIKA_SELECTION_TOOL_GET_OPTIONS (tool);
PikaFreeSelectTool *free_sel = PIKA_FREE_SELECT_TOOL (tool);
PikaPolygonSelectTool *poly_sel = PIKA_POLYGON_SELECT_TOOL (tool);
PikaFreeSelectToolPrivate *priv = free_sel->priv;
if (press_type == PIKA_BUTTON_PRESS_NORMAL &&
pika_selection_tool_start_edit (PIKA_SELECTION_TOOL (poly_sel),
display, coords))
return;
PIKA_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
press_type, display);
if (press_type == PIKA_BUTTON_PRESS_NORMAL &&
pika_polygon_select_tool_is_grabbed (poly_sel))
{
if (! priv->started)
{
priv->started = TRUE;
priv->operation_at_start = options->operation;
}
pika_selection_tool_start_change (
PIKA_SELECTION_TOOL (tool),
! pika_polygon_select_tool_is_closed (poly_sel),
priv->operation_at_start);
priv->changed = FALSE;
}
}
static void
pika_free_select_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display)
{
PikaFreeSelectTool *free_sel = PIKA_FREE_SELECT_TOOL (tool);
PikaPolygonSelectTool *poly_sel = PIKA_POLYGON_SELECT_TOOL (tool);
PikaFreeSelectToolPrivate *priv = free_sel->priv;
if (pika_polygon_select_tool_is_grabbed (poly_sel))
{
pika_selection_tool_end_change (PIKA_SELECTION_TOOL (tool),
! priv->changed);
priv->changed = FALSE;
}
PIKA_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
release_type, display);
}
static void
pika_free_select_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec)
{
if (! strcmp (pspec->name, "antialias") ||
! strcmp (pspec->name, "feather") ||
! strcmp (pspec->name, "feather-radius"))
{
if (tool->display)
{
pika_free_select_tool_change_complete (
PIKA_POLYGON_SELECT_TOOL (tool), tool->display);
}
}
PIKA_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
}
static gboolean
pika_free_select_tool_have_selection (PikaSelectionTool *sel_tool,
PikaDisplay *display)
{
PikaPolygonSelectTool *poly_sel = PIKA_POLYGON_SELECT_TOOL (sel_tool);
PikaTool *tool = PIKA_TOOL (sel_tool);
if (display == tool->display)
{
gint n_points;
pika_polygon_select_tool_get_points (poly_sel, NULL, &n_points);
if (n_points > 2)
return TRUE;
}
return PIKA_SELECTION_TOOL_CLASS (parent_class)->have_selection (sel_tool,
display);
}
static void
pika_free_select_tool_change_complete (PikaPolygonSelectTool *poly_sel,
PikaDisplay *display)
{
PikaFreeSelectTool *free_sel = PIKA_FREE_SELECT_TOOL (poly_sel);
PikaFreeSelectToolPrivate *priv = free_sel->priv;
priv->changed = TRUE;
pika_selection_tool_start_change (PIKA_SELECTION_TOOL (free_sel),
FALSE,
priv->operation_at_start);
if (pika_polygon_select_tool_is_closed (poly_sel))
pika_free_select_tool_select (free_sel, display);
pika_selection_tool_end_change (PIKA_SELECTION_TOOL (free_sel),
FALSE);
}
static void
pika_free_select_tool_halt (PikaFreeSelectTool *free_sel)
{
PikaFreeSelectToolPrivate *priv = free_sel->priv;
priv->started = FALSE;
}
static void
pika_free_select_tool_commit (PikaFreeSelectTool *free_sel,
PikaDisplay *display)
{
PikaPolygonSelectTool *poly_sel = PIKA_POLYGON_SELECT_TOOL (free_sel);
if (! pika_polygon_select_tool_is_closed (poly_sel))
{
if (pika_free_select_tool_select (free_sel, display))
pika_image_flush (pika_display_get_image (display));
}
}
static gboolean
pika_free_select_tool_select (PikaFreeSelectTool *free_sel,
PikaDisplay *display)
{
PikaSelectionOptions *options = PIKA_SELECTION_TOOL_GET_OPTIONS (free_sel);
PikaTool *tool = PIKA_TOOL (free_sel);
PikaFreeSelectToolPrivate *priv = free_sel->priv;
PikaImage *image = pika_display_get_image (display);
const PikaVector2 *points;
gint n_points;
pika_polygon_select_tool_get_points (PIKA_POLYGON_SELECT_TOOL (free_sel),
&points, &n_points);
if (n_points > 2)
{
/* prevent this change from halting the tool */
pika_tool_control_push_preserve (tool->control, TRUE);
pika_channel_select_polygon (pika_image_get_mask (image),
C_("command", "Free Select"),
n_points,
points,
priv->operation_at_start,
options->antialias,
options->feather,
options->feather_radius,
options->feather_radius,
TRUE);
pika_tool_control_pop_preserve (tool->control);
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,60 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FREE_SELECT_TOOL_H__
#define __PIKA_FREE_SELECT_TOOL_H__
#include "pikapolygonselecttool.h"
#define PIKA_TYPE_FREE_SELECT_TOOL (pika_free_select_tool_get_type ())
#define PIKA_FREE_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FREE_SELECT_TOOL, PikaFreeSelectTool))
#define PIKA_FREE_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FREE_SELECT_TOOL, PikaFreeSelectToolClass))
#define PIKA_IS_FREE_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FREE_SELECT_TOOL))
#define PIKA_IS_FREE_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FREE_SELECT_TOOL))
#define PIKA_FREE_SELECT_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FREE_SELECT_TOOL, PikaFreeSelectToolClass))
typedef struct _PikaFreeSelectTool PikaFreeSelectTool;
typedef struct _PikaFreeSelectToolPrivate PikaFreeSelectToolPrivate;
typedef struct _PikaFreeSelectToolClass PikaFreeSelectToolClass;
struct _PikaFreeSelectTool
{
PikaPolygonSelectTool parent_instance;
PikaFreeSelectToolPrivate *priv;
};
struct _PikaFreeSelectToolClass
{
PikaPolygonSelectToolClass parent_class;
};
void pika_free_select_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_free_select_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_FREE_SELECT_TOOL_H__ */

View File

@ -0,0 +1,159 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikafuzzyselecttool.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikaimage.h"
#include "core/pikaimage-new.h"
#include "core/pikaitem.h"
#include "core/pikapickable.h"
#include "core/pikapickable-contiguous-region.h"
#include "widgets/pikahelp-ids.h"
#include "display/pikadisplay.h"
#include "pikafuzzyselecttool.h"
#include "pikaregionselectoptions.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static GeglBuffer * pika_fuzzy_select_tool_get_mask (PikaRegionSelectTool *region_select,
PikaDisplay *display);
G_DEFINE_TYPE (PikaFuzzySelectTool, pika_fuzzy_select_tool,
PIKA_TYPE_REGION_SELECT_TOOL)
#define parent_class pika_fuzzy_select_tool_parent_class
void
pika_fuzzy_select_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_FUZZY_SELECT_TOOL,
PIKA_TYPE_REGION_SELECT_OPTIONS,
pika_region_select_options_gui,
0,
"pika-fuzzy-select-tool",
_("Fuzzy Select"),
_("Fuzzy Select Tool: Select a contiguous region on the basis of color"),
N_("Fu_zzy Select"), "U",
NULL, PIKA_HELP_TOOL_FUZZY_SELECT,
PIKA_ICON_TOOL_FUZZY_SELECT,
data);
}
static void
pika_fuzzy_select_tool_class_init (PikaFuzzySelectToolClass *klass)
{
PikaRegionSelectToolClass *region_class;
region_class = PIKA_REGION_SELECT_TOOL_CLASS (klass);
region_class->undo_desc = C_("command", "Fuzzy Select");
region_class->get_mask = pika_fuzzy_select_tool_get_mask;
}
static void
pika_fuzzy_select_tool_init (PikaFuzzySelectTool *fuzzy_select)
{
PikaTool *tool = PIKA_TOOL (fuzzy_select);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_FUZZY_SELECT);
}
static GeglBuffer *
pika_fuzzy_select_tool_get_mask (PikaRegionSelectTool *region_select,
PikaDisplay *display)
{
PikaTool *tool = PIKA_TOOL (region_select);
PikaSelectionOptions *sel_options = PIKA_SELECTION_TOOL_GET_OPTIONS (tool);
PikaRegionSelectOptions *options = PIKA_REGION_SELECT_TOOL_GET_OPTIONS (tool);
PikaImage *image = pika_display_get_image (display);
PikaImage *select_image = NULL;
GList *drawables = pika_image_get_selected_drawables (image);
PikaPickable *pickable;
GeglBuffer *mask;
gint x, y;
x = region_select->x;
y = region_select->y;
if (! options->sample_merged)
{
if (g_list_length (drawables) == 1)
{
gint off_x, off_y;
pika_item_get_offset (drawables->data, &off_x, &off_y);
x -= off_x;
y -= off_y;
pickable = PIKA_PICKABLE (drawables->data);
}
else
{
select_image = pika_image_new_from_drawables (image->pika, drawables, FALSE, FALSE);
pika_container_remove (image->pika->images, PIKA_OBJECT (select_image));
pickable = PIKA_PICKABLE (select_image);
pika_pickable_flush (pickable);
}
}
else
{
pickable = PIKA_PICKABLE (image);
}
g_list_free (drawables);
mask = pika_pickable_contiguous_region_by_seed (pickable,
sel_options->antialias,
options->threshold / 255.0,
options->select_transparent,
options->select_criterion,
options->diagonal_neighbors,
x, y);
if (select_image)
g_object_unref (select_image);
return mask;
}

View File

@ -0,0 +1,59 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikafuzzyselecttool.h
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_FUZZY_SELECT_TOOL_H__
#define __PIKA_FUZZY_SELECT_TOOL_H__
#include "pikaregionselecttool.h"
#define PIKA_TYPE_FUZZY_SELECT_TOOL (pika_fuzzy_select_tool_get_type ())
#define PIKA_FUZZY_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FUZZY_SELECT_TOOL, PikaFuzzySelectTool))
#define PIKA_FUZZY_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FUZZY_SELECT_TOOL, PikaFuzzySelectToolClass))
#define PIKA_IS_FUZZY_SELECT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FUZZY_SELECT_TOOL))
#define PIKA_IS_FUZZY_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FUZZY_SELECT_TOOL))
#define PIKA_FUZZY_SELECT_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FUZZY_SELECT_TOOL, PikaFuzzySelectToolClass))
typedef struct _PikaFuzzySelectTool PikaFuzzySelectTool;
typedef struct _PikaFuzzySelectToolClass PikaFuzzySelectToolClass;
struct _PikaFuzzySelectTool
{
PikaRegionSelectTool parent_instance;
};
struct _PikaFuzzySelectToolClass
{
PikaRegionSelectToolClass parent_class;
};
void pika_fuzzy_select_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_fuzzy_select_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_FUZZY_SELECT_TOOL_H__ */

302
app/tools/pikagegltool.c Normal file
View File

@ -0,0 +1,302 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gegl-plugin.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "gegl/pika-gegl-utils.h"
#include "core/pika.h"
#include "core/pikatoolinfo.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikapropwidgets.h"
#include "pikafilteroptions.h"
#include "pikagegltool.h"
#include "pika-intl.h"
enum
{
COLUMN_NAME,
COLUMN_LABEL,
COLUMN_ICON_NAME,
N_COLUMNS
};
/* local function prototypes */
static void pika_gegl_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display);
static void pika_gegl_tool_dialog (PikaFilterTool *filter_tool);
static void pika_gegl_tool_halt (PikaGeglTool *gegl_tool);
static void pika_gegl_tool_operation_changed (GtkWidget *widget,
PikaGeglTool *gegl_tool);
G_DEFINE_TYPE (PikaGeglTool, pika_gegl_tool, PIKA_TYPE_OPERATION_TOOL)
#define parent_class pika_gegl_tool_parent_class
void
pika_gegl_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_GEGL_TOOL,
PIKA_TYPE_FILTER_OPTIONS,
pika_color_options_gui,
0,
"pika-gegl-tool",
_("GEGL Operation"),
_("Run an arbitrary GEGL operation"),
N_("_GEGL Operation..."), NULL,
NULL, PIKA_HELP_TOOL_GEGL,
PIKA_ICON_GEGL,
data);
}
static void
pika_gegl_tool_class_init (PikaGeglToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaFilterToolClass *filter_tool_class = PIKA_FILTER_TOOL_CLASS (klass);
tool_class->control = pika_gegl_tool_control;
filter_tool_class->dialog = pika_gegl_tool_dialog;
}
static void
pika_gegl_tool_init (PikaGeglTool *tool)
{
}
static void
pika_gegl_tool_control (PikaTool *tool,
PikaToolAction action,
PikaDisplay *display)
{
PikaGeglTool *gegl_tool = PIKA_GEGL_TOOL (tool);
switch (action)
{
case PIKA_TOOL_ACTION_PAUSE:
case PIKA_TOOL_ACTION_RESUME:
break;
case PIKA_TOOL_ACTION_HALT:
pika_gegl_tool_halt (gegl_tool);
break;
case PIKA_TOOL_ACTION_COMMIT:
break;
}
PIKA_TOOL_CLASS (parent_class)->control (tool, action, display);
}
/*****************/
/* Gegl dialog */
/*****************/
static void
pika_gegl_tool_dialog (PikaFilterTool *filter_tool)
{
PikaGeglTool *tool = PIKA_GEGL_TOOL (filter_tool);
PikaOperationTool *o_tool = PIKA_OPERATION_TOOL (filter_tool);
GtkListStore *store;
GtkCellRenderer *cell;
GtkWidget *main_vbox;
GtkWidget *hbox;
GtkWidget *combo;
GtkWidget *options_gui;
GtkWidget *options_box;
GList *opclasses;
GList *iter;
PIKA_FILTER_TOOL_CLASS (parent_class)->dialog (filter_tool);
options_box = g_weak_ref_get (&o_tool->options_box_ref);
g_return_if_fail (options_box);
main_vbox = pika_filter_tool_dialog_get_vbox (filter_tool);
/* The operation combo box */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (main_vbox), hbox, 0);
gtk_widget_show (hbox);
store = gtk_list_store_new (N_COLUMNS,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
opclasses = pika_gegl_get_op_classes ();
for (iter = opclasses; iter; iter = iter->next)
{
GeglOperationClass *opclass = GEGL_OPERATION_CLASS (iter->data);
const gchar *icon_name = NULL;
const gchar *op_name = opclass->name;
const gchar *title;
gchar *label;
if (g_str_has_prefix (opclass->name, "gegl:"))
icon_name = PIKA_ICON_GEGL;
if (g_str_has_prefix (op_name, "gegl:"))
op_name += strlen ("gegl:");
title = gegl_operation_class_get_key (opclass, "title");
if (title)
label = g_strdup_printf ("%s (%s)", title, op_name);
else
label = g_strdup (op_name);
gtk_list_store_insert_with_values (store, NULL, -1,
COLUMN_NAME, opclass->name,
COLUMN_LABEL, label,
COLUMN_ICON_NAME, icon_name,
-1);
g_free (label);
}
g_list_free (opclasses);
combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
cell = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell,
"icon-name", COLUMN_ICON_NAME);
cell = gtk_cell_renderer_text_new ();
g_object_set (cell,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
NULL);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell,
"text", COLUMN_LABEL);
g_signal_connect (combo, "changed",
G_CALLBACK (pika_gegl_tool_operation_changed),
tool);
tool->operation_combo = combo;
tool->description_label = gtk_label_new ("");
gtk_label_set_line_wrap (GTK_LABEL (tool->description_label), TRUE);
gtk_label_set_xalign (GTK_LABEL (tool->description_label), 0.0);
gtk_box_pack_start (GTK_BOX (main_vbox), tool->description_label,
FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (main_vbox), tool->description_label, 1);
/* The options vbox */
options_gui = gtk_label_new (_("Select an operation from the list above"));
pika_label_set_attributes (GTK_LABEL (options_gui),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
g_object_set (options_gui,
"margin-top", 4,
"margin-bottom", 4,
NULL);
gtk_container_add (GTK_CONTAINER (options_box), options_gui);
g_object_unref (options_box);
g_weak_ref_set (&o_tool->options_gui_ref, options_gui);
gtk_widget_show (options_gui);
}
static void
pika_gegl_tool_halt (PikaGeglTool *gegl_tool)
{
PikaOperationTool *op_tool = PIKA_OPERATION_TOOL (gegl_tool);
pika_operation_tool_set_operation (op_tool, NULL,
NULL, NULL, NULL, NULL, NULL);
}
static void
pika_gegl_tool_operation_changed (GtkWidget *widget,
PikaGeglTool *tool)
{
GtkTreeModel *model;
GtkTreeIter iter;
gchar *operation;
if (! gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
return;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_tree_model_get (model, &iter,
COLUMN_NAME, &operation,
-1);
if (operation)
{
const gchar *description;
description = gegl_operation_get_key (operation, "description");
if (description)
{
gtk_label_set_text (GTK_LABEL (tool->description_label), description);
gtk_widget_show (tool->description_label);
}
else
{
gtk_widget_hide (tool->description_label);
}
pika_operation_tool_set_operation (PIKA_OPERATION_TOOL (tool),
operation,
_("GEGL Operation"),
_("GEGL Operation"),
NULL,
PIKA_ICON_GEGL,
PIKA_HELP_TOOL_GEGL);
g_free (operation);
}
}

61
app/tools/pikagegltool.h Normal file
View File

@ -0,0 +1,61 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_GEGL_TOOL_H__
#define __PIKA_GEGL_TOOL_H__
#include "pikaoperationtool.h"
#define PIKA_TYPE_GEGL_TOOL (pika_gegl_tool_get_type ())
#define PIKA_GEGL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_GEGL_TOOL, PikaGeglTool))
#define PIKA_GEGL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_GEGL_TOOL, PikaGeglToolClass))
#define PIKA_IS_GEGL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_GEGL_TOOL))
#define PIKA_IS_GEGL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_GEGL_TOOL))
#define PIKA_GEGL_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_GEGL_TOOL, PikaGeglToolClass))
typedef struct _PikaGeglTool PikaGeglTool;
typedef struct _PikaGeglToolClass PikaGeglToolClass;
struct _PikaGeglTool
{
PikaOperationTool parent_instance;
/* dialog */
GtkWidget *operation_combo;
GtkWidget *description_label;
};
struct _PikaGeglToolClass
{
PikaOperationToolClass parent_class;
};
void pika_gegl_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_gegl_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_GEGL_TOOL_H__ */

View File

@ -0,0 +1,174 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika-transform-utils.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"
#include "display/pikadisplay.h"
#include "display/pikatoolgui.h"
#include "pikagenerictransformtool.h"
#include "pikatoolcontrol.h"
#include "pikatransformgridoptions.h"
#include "pika-intl.h"
/* local function prototypes */
static gboolean pika_generic_transform_tool_info_to_matrix (PikaTransformGridTool *tg_tool,
PikaMatrix3 *transform);
static void pika_generic_transform_tool_dialog (PikaTransformGridTool *tg_tool);
static void pika_generic_transform_tool_dialog_update (PikaTransformGridTool *tg_tool);
static void pika_generic_transform_tool_prepare (PikaTransformGridTool *tg_tool);
G_DEFINE_TYPE (PikaGenericTransformTool, pika_generic_transform_tool,
PIKA_TYPE_TRANSFORM_GRID_TOOL)
#define parent_class pika_generic_transform_tool_parent_class
static void
pika_generic_transform_tool_class_init (PikaGenericTransformToolClass *klass)
{
PikaTransformGridToolClass *tg_class = PIKA_TRANSFORM_GRID_TOOL_CLASS (klass);
tg_class->info_to_matrix = pika_generic_transform_tool_info_to_matrix;
tg_class->dialog = pika_generic_transform_tool_dialog;
tg_class->dialog_update = pika_generic_transform_tool_dialog_update;
tg_class->prepare = pika_generic_transform_tool_prepare;
}
static void
pika_generic_transform_tool_init (PikaGenericTransformTool *unified_tool)
{
}
static gboolean
pika_generic_transform_tool_info_to_matrix (PikaTransformGridTool *tg_tool,
PikaMatrix3 *transform)
{
PikaGenericTransformTool *generic = PIKA_GENERIC_TRANSFORM_TOOL (tg_tool);
if (PIKA_GENERIC_TRANSFORM_TOOL_GET_CLASS (generic)->info_to_points)
PIKA_GENERIC_TRANSFORM_TOOL_GET_CLASS (generic)->info_to_points (generic);
pika_matrix3_identity (transform);
return pika_transform_matrix_generic (transform,
generic->input_points,
generic->output_points);
}
static void
pika_generic_transform_tool_dialog (PikaTransformGridTool *tg_tool)
{
PikaGenericTransformTool *generic = PIKA_GENERIC_TRANSFORM_TOOL (tg_tool);
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *label;
GtkSizeGroup *size_group;
frame = pika_frame_new (_("Transform Matrix"));
gtk_box_pack_start (GTK_BOX (pika_tool_gui_get_vbox (tg_tool->gui)), frame,
FALSE, FALSE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
label = generic->matrix_label = gtk_label_new (" ");
gtk_size_group_add_widget (size_group, label);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
pika_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_widget_show (label);
label = generic->invalid_label = gtk_label_new (_("Invalid transform"));
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_size_group_add_widget (size_group, label);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
g_object_unref (size_group);
}
static void
pika_generic_transform_tool_dialog_update (PikaTransformGridTool *tg_tool)
{
PikaGenericTransformTool *generic = PIKA_GENERIC_TRANSFORM_TOOL (tg_tool);
PikaMatrix3 transform;
gboolean transform_valid;
transform_valid = pika_transform_grid_tool_info_to_matrix (tg_tool,
&transform);
if (transform_valid)
{
gchar buf[256];
gtk_widget_show (generic->matrix_label);
gtk_widget_hide (generic->invalid_label);
g_snprintf (buf, sizeof (buf), "<tt>% 11.4f\t% 11.4f\t% 11.4f\n% 11.4f\t% 11.4f"
"\t% 11.4f\n% 11.4f\t% 11.4f\t% 11.4f</tt>",
transform.coeff[0][0], transform.coeff[0][1], transform.coeff[0][2],
transform.coeff[1][0], transform.coeff[1][1], transform.coeff[1][2],
transform.coeff[2][0], transform.coeff[2][1], transform.coeff[2][2]);
gtk_label_set_markup (GTK_LABEL (generic->matrix_label), buf);
}
else
{
gtk_widget_show (generic->invalid_label);
gtk_widget_hide (generic->matrix_label);
}
}
static void
pika_generic_transform_tool_prepare (PikaTransformGridTool *tg_tool)
{
PikaTransformTool *tr_tool = PIKA_TRANSFORM_TOOL (tg_tool);
PikaGenericTransformTool *generic = PIKA_GENERIC_TRANSFORM_TOOL (tg_tool);
generic->input_points[0] = (PikaVector2) {tr_tool->x1, tr_tool->y1};
generic->input_points[1] = (PikaVector2) {tr_tool->x2, tr_tool->y1};
generic->input_points[2] = (PikaVector2) {tr_tool->x1, tr_tool->y2};
generic->input_points[3] = (PikaVector2) {tr_tool->x2, tr_tool->y2};
memcpy (generic->output_points, generic->input_points,
sizeof (generic->input_points));
}

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_GENERIC_TRANSFORM_TOOL_H__
#define __PIKA_GENERIC_TRANSFORM_TOOL_H__
#include "pikatransformgridtool.h"
#define PIKA_TYPE_GENERIC_TRANSFORM_TOOL (pika_generic_transform_tool_get_type ())
#define PIKA_GENERIC_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_GENERIC_TRANSFORM_TOOL, PikaGenericTransformTool))
#define PIKA_GENERIC_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_GENERIC_TRANSFORM_TOOL, PikaGenericTransformToolClass))
#define PIKA_IS_GENERIC_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_GENERIC_TRANSFORM_TOOL))
#define PIKA_IS_GENERIC_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_GENERIC_TRANSFORM_TOOL))
#define PIKA_GENERIC_TRANSFORM_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_GENERIC_TRANSFORM_TOOL, PikaGenericTransformToolClass))
typedef struct _PikaGenericTransformToolClass PikaGenericTransformToolClass;
struct _PikaGenericTransformTool
{
PikaTransformGridTool parent_instance;
PikaVector2 input_points[4];
PikaVector2 output_points[4];
GtkWidget *matrix_label;
GtkWidget *invalid_label;
};
struct _PikaGenericTransformToolClass
{
PikaTransformGridToolClass parent_class;
/* virtual functions */
void (* info_to_points) (PikaGenericTransformTool *generic);
};
GType pika_generic_transform_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_GENERIC_TRANSFORM_TOOL_H__ */

View File

@ -0,0 +1,407 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pikadata.h"
#include "core/pikadatafactory.h"
#include "core/pika-gradients.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikaviewablebox.h"
#include "widgets/pikawidgets-utils.h"
#include "pikagradientoptions.h"
#include "pikapaintoptions-gui.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_OFFSET,
PROP_GRADIENT_TYPE,
PROP_DISTANCE_METRIC,
PROP_SUPERSAMPLE,
PROP_SUPERSAMPLE_DEPTH,
PROP_SUPERSAMPLE_THRESHOLD,
PROP_DITHER,
PROP_INSTANT,
PROP_MODIFY_ACTIVE
};
static void pika_gradient_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_gradient_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gradient_options_repeat_gradient_type_notify (PikaGradientOptions *options,
GParamSpec *pspec,
GtkWidget *repeat_combo);
static void gradient_options_metric_gradient_type_notify (PikaGradientOptions *options,
GParamSpec *pspec,
GtkWidget *repeat_combo);
G_DEFINE_TYPE (PikaGradientOptions, pika_gradient_options,
PIKA_TYPE_PAINT_OPTIONS)
static void
pika_gradient_options_class_init (PikaGradientOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_gradient_options_set_property;
object_class->get_property = pika_gradient_options_get_property;
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_OFFSET,
"offset",
_("Offset"),
NULL,
0.0, 100.0, 0.0,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_GRADIENT_TYPE,
"gradient-type",
_("Shape"),
NULL,
PIKA_TYPE_GRADIENT_TYPE,
PIKA_GRADIENT_LINEAR,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PROP_DISTANCE_METRIC,
"distance-metric",
_("Metric"),
_("Metric to use for the distance calculation"),
GEGL_TYPE_DISTANCE_METRIC,
GEGL_DISTANCE_METRIC_EUCLIDEAN,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_SUPERSAMPLE,
"supersample",
_("Adaptive Supersampling"),
NULL,
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_INT (object_class, PROP_SUPERSAMPLE_DEPTH,
"supersample-depth",
_("Max depth"),
NULL,
1, 9, 3,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_SUPERSAMPLE_THRESHOLD,
"supersample-threshold",
_("Threshold"),
NULL,
0.0, 4.0, 0.2,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_DITHER,
"dither",
_("Dithering"),
NULL,
TRUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_INSTANT,
"instant",
_("Instant mode"),
_("Commit gradient instantly"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_MODIFY_ACTIVE,
"modify-active",
_("Modify active gradient"),
_("Modify the active gradient in-place"),
FALSE,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_gradient_options_init (PikaGradientOptions *options)
{
}
static void
pika_gradient_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaGradientOptions *options = PIKA_GRADIENT_OPTIONS (object);
switch (property_id)
{
case PROP_OFFSET:
options->offset = g_value_get_double (value);
break;
case PROP_GRADIENT_TYPE:
options->gradient_type = g_value_get_enum (value);
break;
case PROP_DISTANCE_METRIC:
options->distance_metric = g_value_get_enum (value);
break;
case PROP_SUPERSAMPLE:
options->supersample = g_value_get_boolean (value);
break;
case PROP_SUPERSAMPLE_DEPTH:
options->supersample_depth = g_value_get_int (value);
break;
case PROP_SUPERSAMPLE_THRESHOLD:
options->supersample_threshold = g_value_get_double (value);
break;
case PROP_DITHER:
options->dither = g_value_get_boolean (value);
break;
case PROP_INSTANT:
options->instant = g_value_get_boolean (value);
break;
case PROP_MODIFY_ACTIVE:
options->modify_active = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_gradient_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaGradientOptions *options = PIKA_GRADIENT_OPTIONS (object);
switch (property_id)
{
case PROP_OFFSET:
g_value_set_double (value, options->offset);
break;
case PROP_GRADIENT_TYPE:
g_value_set_enum (value, options->gradient_type);
break;
case PROP_DISTANCE_METRIC:
g_value_set_enum (value, options->distance_metric);
break;
case PROP_SUPERSAMPLE:
g_value_set_boolean (value, options->supersample);
break;
case PROP_SUPERSAMPLE_DEPTH:
g_value_set_int (value, options->supersample_depth);
break;
case PROP_SUPERSAMPLE_THRESHOLD:
g_value_set_double (value, options->supersample_threshold);
break;
case PROP_DITHER:
g_value_set_boolean (value, options->dither);
break;
case PROP_INSTANT:
g_value_set_boolean (value, options->instant);
break;
case PROP_MODIFY_ACTIVE:
g_value_set_boolean (value, options->modify_active);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
pika_gradient_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
PikaContext *context = PIKA_CONTEXT (tool_options);
PikaGradientOptions *options = PIKA_GRADIENT_OPTIONS (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *vbox2;
GtkWidget *frame;
GtkWidget *scale;
GtkWidget *combo;
GtkWidget *button;
GtkWidget *label;
gchar *str;
GdkModifierType extend_mask;
PikaGradient *gradient;
extend_mask = pika_get_extend_selection_mask ();
/* the gradient */
button = pika_prop_gradient_box_new (NULL, PIKA_CONTEXT (tool_options),
_("Gradient"), 2,
"gradient-view-type",
"gradient-view-size",
"gradient-reverse",
"gradient-blend-color-space",
"pika-gradient-editor",
_("Edit this gradient"));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* the blend color space */
combo = pika_prop_enum_combo_box_new (config, "gradient-blend-color-space",
0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo),
_("Blend Color Space"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (vbox), combo, TRUE, TRUE, 0);
/* the gradient type menu */
combo = pika_prop_enum_combo_box_new (config, "gradient-type", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Shape"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
pika_enum_combo_box_set_icon_prefix (PIKA_ENUM_COMBO_BOX (combo),
"pika-gradient");
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
/* the distance metric menu */
combo = pika_prop_enum_combo_box_new (config, "distance-metric", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Metric"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
g_signal_connect (config, "notify::gradient-type",
G_CALLBACK (gradient_options_metric_gradient_type_notify),
combo);
gradient_options_metric_gradient_type_notify (options, NULL, combo);
/* the repeat option */
combo = pika_prop_enum_combo_box_new (config, "gradient-repeat", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Repeat"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
g_signal_connect (config, "notify::gradient-type",
G_CALLBACK (gradient_options_repeat_gradient_type_notify),
combo);
gradient_options_repeat_gradient_type_notify (options, NULL, combo);
/* the offset scale */
scale = pika_prop_spin_scale_new (config, "offset",
1.0, 10.0, 1);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
/* the dither toggle */
button = pika_prop_check_button_new (config, "dither", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* supersampling options */
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
frame = pika_prop_expanding_frame_new (config, "supersample", NULL,
vbox2, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
/* max depth scale */
scale = pika_prop_spin_scale_new (config, "supersample-depth",
1.0, 1.0, 0);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* threshold scale */
scale = pika_prop_spin_scale_new (config, "supersample-threshold",
0.01, 0.1, 2);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* the instant toggle */
str = g_strdup_printf (_("Instant mode (%s)"),
pika_get_mod_string (extend_mask));
button = pika_prop_check_button_new (config, "instant", str);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
g_free (str);
options->instant_toggle = button;
/* the modify active toggle */
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
frame = pika_prop_expanding_frame_new (config, "modify-active", NULL,
vbox2, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
options->modify_active_frame = frame;
label = gtk_label_new (_("The active gradient is non-writable "
"and cannot be edited directly. "
"Uncheck this option "
"to edit a copy of it."));
gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_width_chars (GTK_LABEL (label), 24);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
options->modify_active_hint = label;
gradient = pika_context_get_gradient (PIKA_CONTEXT (options));
gtk_widget_set_sensitive (options->modify_active_frame,
gradient !=
pika_gradients_get_custom (context->pika));
gtk_widget_set_visible (options->modify_active_hint,
gradient &&
! pika_data_is_writable (PIKA_DATA (gradient)));
return vbox;
}
static void
gradient_options_repeat_gradient_type_notify (PikaGradientOptions *options,
GParamSpec *pspec,
GtkWidget *repeat_combo)
{
gtk_widget_set_sensitive (repeat_combo,
options->gradient_type < PIKA_GRADIENT_SHAPEBURST_ANGULAR);
}
static void
gradient_options_metric_gradient_type_notify (PikaGradientOptions *options,
GParamSpec *pspec,
GtkWidget *repeat_combo)
{
gtk_widget_set_sensitive (repeat_combo,
options->gradient_type >= PIKA_GRADIENT_SHAPEBURST_ANGULAR &&
options->gradient_type <= PIKA_GRADIENT_SHAPEBURST_DIMPLED);
}

View File

@ -0,0 +1,69 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_GRADIENT_OPTIONS_H__
#define __PIKA_GRADIENT_OPTIONS_H__
#include "paint/pikapaintoptions.h"
#define PIKA_TYPE_GRADIENT_OPTIONS (pika_gradient_options_get_type ())
#define PIKA_GRADIENT_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_GRADIENT_OPTIONS, PikaGradientOptions))
#define PIKA_GRADIENT_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_GRADIENT_OPTIONS, PikaGradientOptionsClass))
#define PIKA_IS_GRADIENT_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_GRADIENT_OPTIONS))
#define PIKA_IS_GRADIENT_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_GRADIENT_OPTIONS))
#define PIKA_GRADIENT_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_GRADIENT_OPTIONS, PikaGradientOptionsClass))
typedef struct _PikaGradientOptions PikaGradientOptions;
typedef struct _PikaPaintOptionsClass PikaGradientOptionsClass;
struct _PikaGradientOptions
{
PikaPaintOptions paint_options;
gdouble offset;
PikaGradientType gradient_type;
GeglDistanceMetric distance_metric;
gboolean supersample;
gint supersample_depth;
gdouble supersample_threshold;
gboolean dither;
gboolean instant;
gboolean modify_active;
/* options gui */
GtkWidget *instant_toggle;
GtkWidget *modify_active_frame;
GtkWidget *modify_active_hint;
};
GType pika_gradient_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_gradient_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_GRADIENT_OPTIONS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_GRADIENT_TOOL_EDITOR_H__
#define __PIKA_GRADIENT_TOOL_EDITOR_H__
void pika_gradient_tool_editor_options_notify (PikaGradientTool *gradient_tool,
PikaToolOptions *options,
const GParamSpec *pspec);
void pika_gradient_tool_editor_start (PikaGradientTool *gradient_tool);
void pika_gradient_tool_editor_halt (PikaGradientTool *gradient_tool);
gboolean pika_gradient_tool_editor_line_changed (PikaGradientTool *gradient_tool);
void pika_gradient_tool_editor_fg_bg_changed (PikaGradientTool *gradient_tool);
void pika_gradient_tool_editor_gradient_dirty (PikaGradientTool *gradient_tool);
void pika_gradient_tool_editor_gradient_changed (PikaGradientTool *gradient_tool);
const gchar * pika_gradient_tool_editor_can_undo (PikaGradientTool *gradient_tool);
const gchar * pika_gradient_tool_editor_can_redo (PikaGradientTool *gradient_tool);
gboolean pika_gradient_tool_editor_undo (PikaGradientTool *gradient_tool);
gboolean pika_gradient_tool_editor_redo (PikaGradientTool *gradient_tool);
void pika_gradient_tool_editor_start_edit (PikaGradientTool *gradient_tool);
void pika_gradient_tool_editor_end_edit (PikaGradientTool *gradient_tool,
gboolean cancel);
#endif /* __PIKA_GRADIENT_TOOL_EDITOR_H__ */

1139
app/tools/pikagradienttool.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_GRADIENT_TOOL_H__
#define __PIKA_GRADIENT_TOOL_H__
#include "pikadrawtool.h"
#define PIKA_TYPE_GRADIENT_TOOL (pika_gradient_tool_get_type ())
#define PIKA_GRADIENT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_GRADIENT_TOOL, PikaGradientTool))
#define PIKA_GRADIENT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_GRADIENT_TOOL, PikaGradientToolClass))
#define PIKA_IS_GRADIENT_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_GRADIENT_TOOL))
#define PIKA_IS_GRADIENT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_GRADIENT_TOOL))
#define PIKA_GRADIENT_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_GRADIENT_TOOL, PikaGradientToolClass))
#define PIKA_GRADIENT_TOOL_GET_OPTIONS(t) (PIKA_GRADIENT_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaGradientTool PikaGradientTool;
typedef struct _PikaGradientToolClass PikaGradientToolClass;
struct _PikaGradientTool
{
PikaDrawTool parent_instance;
PikaGradient *gradient;
PikaGradient *tentative_gradient;
gdouble start_x; /* starting x coord */
gdouble start_y; /* starting y coord */
gdouble end_x; /* ending x coord */
gdouble end_y; /* ending y coord */
PikaToolWidget *widget;
PikaToolWidget *grab_widget;
GeglNode *graph;
GeglNode *render_node;
#if 0
GeglNode *subtract_node;
GeglNode *divide_node;
#endif
GeglNode *dist_node;
GeglBuffer *dist_buffer;
PikaDrawableFilter *filter;
/* editor */
gint block_handlers_count;
gint edit_count;
GSList *undo_stack;
GSList *redo_stack;
guint flush_idle_id;
PikaToolGui *gui;
GtkWidget *endpoint_editor;
GtkWidget *endpoint_se;
GtkWidget *endpoint_color_panel;
GtkWidget *endpoint_type_combo;
GtkWidget *stop_editor;
GtkWidget *stop_se;
GtkWidget *stop_left_color_panel;
GtkWidget *stop_left_type_combo;
GtkWidget *stop_right_color_panel;
GtkWidget *stop_right_type_combo;
GtkWidget *stop_chain_button;
GtkWidget *midpoint_editor;
GtkWidget *midpoint_se;
GtkWidget *midpoint_type_combo;
GtkWidget *midpoint_color_combo;
GtkWidget *midpoint_new_stop_button;
GtkWidget *midpoint_center_button;
};
struct _PikaGradientToolClass
{
PikaDrawToolClass parent_class;
};
void pika_gradient_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_gradient_tool_get_type (void) G_GNUC_CONST;
/* protected functions */
void pika_gradient_tool_set_tentative_gradient (PikaGradientTool *gradient_tool,
PikaGradient *gradient);
#endif /* __PIKA_GRADIENT_TOOL_H__ */

542
app/tools/pikaguidetool.c Normal file
View File

@ -0,0 +1,542 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikaguide.h"
#include "core/pikaimage.h"
#include "core/pikaimage-guides.h"
#include "core/pikaimage-undo.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikadisplayshell-selection.h"
#include "display/pikadisplayshell-transform.h"
#include "pikaguidetool.h"
#include "pikatoolcontrol.h"
#include "tool_manager.h"
#include "pika-intl.h"
#define SWAP_ORIENT(orient) ((orient) == PIKA_ORIENTATION_HORIZONTAL ? \
PIKA_ORIENTATION_VERTICAL : \
PIKA_ORIENTATION_HORIZONTAL)
/* local function prototypes */
static void pika_guide_tool_finalize (GObject *object);
static void pika_guide_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display);
static void pika_guide_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display);
static void pika_guide_tool_draw (PikaDrawTool *draw_tool);
static void pika_guide_tool_start (PikaTool *parent_tool,
PikaDisplay *display,
GList *guides,
PikaOrientationType orientation);
static void pika_guide_tool_push_status (PikaGuideTool *guide_tool,
PikaDisplay *display,
gboolean remove_guides);
G_DEFINE_TYPE (PikaGuideTool, pika_guide_tool, PIKA_TYPE_DRAW_TOOL)
#define parent_class pika_guide_tool_parent_class
static void
pika_guide_tool_class_init (PikaGuideToolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaDrawToolClass *draw_tool_class = PIKA_DRAW_TOOL_CLASS (klass);
object_class->finalize = pika_guide_tool_finalize;
tool_class->button_release = pika_guide_tool_button_release;
tool_class->motion = pika_guide_tool_motion;
draw_tool_class->draw = pika_guide_tool_draw;
}
static void
pika_guide_tool_init (PikaGuideTool *guide_tool)
{
PikaTool *tool = PIKA_TOOL (guide_tool);
pika_tool_control_set_snap_to (tool->control, FALSE);
pika_tool_control_set_handle_empty_image (tool->control, TRUE);
pika_tool_control_set_tool_cursor (tool->control,
PIKA_TOOL_CURSOR_MOVE);
pika_tool_control_set_scroll_lock (tool->control, TRUE);
pika_tool_control_set_precision (tool->control,
PIKA_CURSOR_PRECISION_PIXEL_BORDER);
guide_tool->guides = NULL;
guide_tool->n_guides = 0;
}
static void
pika_guide_tool_finalize (GObject *object)
{
PikaGuideTool *guide_tool = PIKA_GUIDE_TOOL (object);
gint i;
for (i = 0; i < guide_tool->n_guides; i++)
g_clear_object (&guide_tool->guides[i].guide);
g_free (guide_tool->guides);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_guide_tool_button_release (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaButtonReleaseType release_type,
PikaDisplay *display)
{
PikaGuideTool *guide_tool = PIKA_GUIDE_TOOL (tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
gint i;
pika_tool_pop_status (tool, display);
pika_tool_control_halt (tool->control);
pika_draw_tool_stop (PIKA_DRAW_TOOL (tool));
if (release_type == PIKA_BUTTON_RELEASE_CANCEL)
{
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuideToolGuide *guide = &guide_tool->guides[i];
/* custom guides are moved live */
if (guide->custom)
{
pika_image_move_guide (image, guide->guide, guide->old_position,
TRUE);
}
}
}
else
{
gint n_non_custom_guides = 0;
gboolean remove_guides = FALSE;
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuideToolGuide *guide = &guide_tool->guides[i];
n_non_custom_guides += ! guide->custom;
if (guide->position == PIKA_GUIDE_POSITION_UNDEFINED)
{
remove_guides = TRUE;
}
}
if (n_non_custom_guides > 1)
{
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_GUIDE,
remove_guides ?
C_("undo-type", "Remove Guides") :
C_("undo-type", "Move Guides"));
}
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuideToolGuide *guide = &guide_tool->guides[i];
if (remove_guides)
{
/* removing a guide can cause other guides to be removed as well
* (in particular, in case of symmetry guides). these guides
* will be kept alive, since we hold a reference on them, but we
* need to make sure that they're still part of the image.
*/
if (g_list_find (pika_image_get_guides (image), guide->guide))
pika_image_remove_guide (image, guide->guide, TRUE);
}
else
{
if (guide->guide)
{
/* custom guides are moved live */
if (! guide->custom)
{
pika_image_move_guide (image, guide->guide,
guide->position, TRUE);
}
}
else
{
switch (guide->orientation)
{
case PIKA_ORIENTATION_HORIZONTAL:
pika_image_add_hguide (image,
guide->position,
TRUE);
break;
case PIKA_ORIENTATION_VERTICAL:
pika_image_add_vguide (image,
guide->position,
TRUE);
break;
default:
pika_assert_not_reached ();
}
}
}
}
if (n_non_custom_guides > 1)
pika_image_undo_group_end (image);
pika_image_flush (image);
}
pika_display_shell_selection_resume (shell);
tool_manager_pop_tool (display->pika);
g_object_unref (guide_tool);
{
PikaTool *active_tool = tool_manager_get_active (display->pika);
if (PIKA_IS_DRAW_TOOL (active_tool))
pika_draw_tool_pause (PIKA_DRAW_TOOL (active_tool));
tool_manager_oper_update_active (display->pika, coords, state,
TRUE, display);
tool_manager_cursor_update_active (display->pika, coords, state,
display);
if (PIKA_IS_DRAW_TOOL (active_tool))
pika_draw_tool_resume (PIKA_DRAW_TOOL (active_tool));
}
}
static void
pika_guide_tool_motion (PikaTool *tool,
const PikaCoords *coords,
guint32 time,
GdkModifierType state,
PikaDisplay *display)
{
PikaGuideTool *guide_tool = PIKA_GUIDE_TOOL (tool);
PikaDisplayShell *shell = pika_display_get_shell (display);
PikaImage *image = pika_display_get_image (display);
gboolean remove_guides = FALSE;
gint tx, ty;
gint i;
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
pika_display_shell_transform_xy (shell,
coords->x, coords->y,
&tx, &ty);
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuideToolGuide *guide = &guide_tool->guides[i];
gint max_position;
gint position;
if (guide->orientation == PIKA_ORIENTATION_HORIZONTAL)
max_position = pika_image_get_height (image);
else
max_position = pika_image_get_width (image);
if (guide->orientation == PIKA_ORIENTATION_HORIZONTAL)
guide->position = RINT (coords->y);
else
guide->position = RINT (coords->x);
position = CLAMP (guide->position, 0, max_position);
if (tx < 0 || tx >= shell->disp_width ||
ty < 0 || ty >= shell->disp_height)
{
guide->position = PIKA_GUIDE_POSITION_UNDEFINED;
remove_guides = TRUE;
}
else
{
if (guide->position < 0 || guide->position > max_position)
remove_guides = TRUE;
}
/* custom guides are moved live */
if (guide->custom)
pika_image_move_guide (image, guide->guide, position, TRUE);
}
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
pika_tool_pop_status (tool, display);
pika_guide_tool_push_status (guide_tool, display, remove_guides);
}
static void
pika_guide_tool_draw (PikaDrawTool *draw_tool)
{
PikaGuideTool *guide_tool = PIKA_GUIDE_TOOL (draw_tool);
gint i;
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuideToolGuide *guide = &guide_tool->guides[i];
if (guide->position != PIKA_GUIDE_POSITION_UNDEFINED)
{
/* custom guides are moved live */
if (! guide->custom)
{
pika_draw_tool_add_guide (draw_tool,
guide->orientation,
guide->position,
PIKA_GUIDE_STYLE_NONE);
}
}
}
}
static void
pika_guide_tool_start (PikaTool *parent_tool,
PikaDisplay *display,
GList *guides,
PikaOrientationType orientation)
{
PikaGuideTool *guide_tool;
PikaTool *tool;
guide_tool = g_object_new (PIKA_TYPE_GUIDE_TOOL,
"tool-info", parent_tool->tool_info,
NULL);
tool = PIKA_TOOL (guide_tool);
pika_display_shell_selection_pause (pika_display_get_shell (display));
if (guides)
{
gint i;
guide_tool->n_guides = g_list_length (guides);
guide_tool->guides = g_new (PikaGuideToolGuide, guide_tool->n_guides);
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuide *guide = guides->data;
guide_tool->guides[i].guide = g_object_ref (guide);
guide_tool->guides[i].old_position = pika_guide_get_position (guide);
guide_tool->guides[i].position = pika_guide_get_position (guide);
guide_tool->guides[i].orientation = pika_guide_get_orientation (guide);
guide_tool->guides[i].custom = pika_guide_is_custom (guide);
guides = g_list_next (guides);
}
}
else
{
guide_tool->n_guides = 1;
guide_tool->guides = g_new (PikaGuideToolGuide, 1);
guide_tool->guides[0].guide = NULL;
guide_tool->guides[0].old_position = 0;
guide_tool->guides[0].position = PIKA_GUIDE_POSITION_UNDEFINED;
guide_tool->guides[0].orientation = orientation;
guide_tool->guides[0].custom = FALSE;
}
pika_tool_set_cursor (tool, display,
PIKA_CURSOR_MOUSE,
PIKA_TOOL_CURSOR_HAND,
PIKA_CURSOR_MODIFIER_MOVE);
tool_manager_push_tool (display->pika, tool);
tool->display = display;
pika_tool_control_activate (tool->control);
pika_draw_tool_start (PIKA_DRAW_TOOL (guide_tool), display);
pika_guide_tool_push_status (guide_tool, display, FALSE);
}
static void
pika_guide_tool_push_status (PikaGuideTool *guide_tool,
PikaDisplay *display,
gboolean remove_guides)
{
PikaTool *tool = PIKA_TOOL (guide_tool);
if (remove_guides)
{
pika_tool_push_status (tool, display,
guide_tool->n_guides > 1 ? _("Remove Guides") :
guide_tool->guides[0].guide ? _("Remove Guide") :
_("Cancel Guide"));
}
else
{
PikaGuideToolGuide *guides[2] = { 0, };
gint n_guides = 0;
gint i;
for (i = 0; i < guide_tool->n_guides; i++)
{
PikaGuideToolGuide *guide = &guide_tool->guides[i];
if (guide_tool->guides[i].guide)
{
if (n_guides == 0 || guide->orientation != guides[0]->orientation)
{
guides[n_guides++] = guide;
if (n_guides == 2)
break;
}
}
}
if (n_guides == 2 &&
guides[0]->orientation == PIKA_ORIENTATION_HORIZONTAL)
{
PikaGuideToolGuide *temp;
temp = guides[0];
guides[0] = guides[1];
guides[1] = temp;
}
if (n_guides == 1)
{
pika_tool_push_status_length (tool, display,
_("Move Guide: "),
SWAP_ORIENT (guides[0]->orientation),
guides[0]->position -
guides[0]->old_position,
NULL);
}
else if (n_guides == 2)
{
pika_tool_push_status_coords (tool, display,
PIKA_CURSOR_PRECISION_PIXEL_BORDER,
_("Move Guides: "),
guides[0]->position -
guides[0]->old_position,
", ",
guides[1]->position -
guides[1]->old_position,
NULL);
}
else
{
pika_tool_push_status_length (tool, display,
_("Add Guide: "),
SWAP_ORIENT (guide_tool->guides[0].orientation),
guide_tool->guides[0].position,
NULL);
}
}
}
/* public functions */
void
pika_guide_tool_start_new (PikaTool *parent_tool,
PikaDisplay *display,
PikaOrientationType orientation)
{
g_return_if_fail (PIKA_IS_TOOL (parent_tool));
g_return_if_fail (PIKA_IS_DISPLAY (display));
g_return_if_fail (orientation != PIKA_ORIENTATION_UNKNOWN);
pika_guide_tool_start (parent_tool, display,
NULL, orientation);
}
void
pika_guide_tool_start_edit (PikaTool *parent_tool,
PikaDisplay *display,
PikaGuide *guide)
{
GList *guides = NULL;
g_return_if_fail (PIKA_IS_TOOL (parent_tool));
g_return_if_fail (PIKA_IS_DISPLAY (display));
g_return_if_fail (PIKA_IS_GUIDE (guide));
guides = g_list_append (guides, guide);
pika_guide_tool_start (parent_tool, display,
guides, PIKA_ORIENTATION_UNKNOWN);
g_list_free (guides);
}
void
pika_guide_tool_start_edit_many (PikaTool *parent_tool,
PikaDisplay *display,
GList *guides)
{
g_return_if_fail (PIKA_IS_TOOL (parent_tool));
g_return_if_fail (PIKA_IS_DISPLAY (display));
g_return_if_fail (guides != NULL);
pika_guide_tool_start (parent_tool, display,
guides, PIKA_ORIENTATION_UNKNOWN);
}

78
app/tools/pikaguidetool.h Normal file
View File

@ -0,0 +1,78 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_GUIDE_TOOL_H__
#define __PIKA_GUIDE_TOOL_H__
#include "pikadrawtool.h"
#define PIKA_TYPE_GUIDE_TOOL (pika_guide_tool_get_type ())
#define PIKA_GUIDE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_GUIDE_TOOL, PikaGuideTool))
#define PIKA_GUIDE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_GUIDE_TOOL, PikaGuideToolClass))
#define PIKA_IS_GUIDE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_GUIDE_TOOL))
#define PIKA_IS_GUIDE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_GUIDE_TOOL))
#define PIKA_GUIDE_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_GUIDE_TOOL, PikaGuideToolClass))
typedef struct _PikaGuideToolGuide PikaGuideToolGuide;
typedef struct _PikaGuideTool PikaGuideTool;
typedef struct _PikaGuideToolClass PikaGuideToolClass;
struct _PikaGuideToolGuide
{
PikaGuide *guide;
gint old_position;
gint position;
PikaOrientationType orientation;
gboolean custom;
};
struct _PikaGuideTool
{
PikaDrawTool parent_instance;
PikaGuideToolGuide *guides;
gint n_guides;
};
struct _PikaGuideToolClass
{
PikaDrawToolClass parent_class;
};
GType pika_guide_tool_get_type (void) G_GNUC_CONST;
void pika_guide_tool_start_new (PikaTool *parent_tool,
PikaDisplay *display,
PikaOrientationType orientation);
void pika_guide_tool_start_edit (PikaTool *parent_tool,
PikaDisplay *display,
PikaGuide *guide);
void pika_guide_tool_start_edit_many (PikaTool *parent_tool,
PikaDisplay *display,
GList *guides);
#endif /* __PIKA_GUIDE_TOOL_H__ */

View File

@ -0,0 +1,205 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "core/pika.h"
#include "core/pikatoolinfo.h"
#include "widgets/pikapropwidgets.h"
#include "widgets/pikawidgets-utils.h"
#include "pikahandletransformoptions.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_HANDLE_MODE
};
static void pika_handle_transform_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_handle_transform_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaHandleTransformOptions, pika_handle_transform_options,
PIKA_TYPE_TRANSFORM_GRID_OPTIONS)
#define parent_class pika_handle_transform_options_parent_class
static void
pika_handle_transform_options_class_init (PikaHandleTransformOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_handle_transform_options_set_property;
object_class->get_property = pika_handle_transform_options_get_property;
PIKA_CONFIG_PROP_ENUM (object_class, PROP_HANDLE_MODE,
"handle-mode",
_("Handle mode"),
_("Handle mode"),
PIKA_TYPE_TRANSFORM_HANDLE_MODE,
PIKA_HANDLE_MODE_ADD_TRANSFORM,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_handle_transform_options_init (PikaHandleTransformOptions *options)
{
}
static void
pika_handle_transform_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaHandleTransformOptions *options = PIKA_HANDLE_TRANSFORM_OPTIONS (object);
switch (property_id)
{
case PROP_HANDLE_MODE:
options->handle_mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_handle_transform_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaHandleTransformOptions *options = PIKA_HANDLE_TRANSFORM_OPTIONS (object);
switch (property_id)
{
case PROP_HANDLE_MODE:
g_value_set_enum (value, options->handle_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* pika_handle_transform_options_gui:
* @tool_options: a #PikaToolOptions
*
* Build the Transform Tool Options.
*
* Returns: a container holding the transform tool options
**/
GtkWidget *
pika_handle_transform_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_transform_grid_options_gui (tool_options);
GtkWidget *frame;
GtkWidget *button;
gint i;
frame = pika_prop_enum_radio_frame_new (config, "handle-mode", NULL,
0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
/* add modifier to name, add tooltip */
button = g_object_get_data (G_OBJECT (frame), "radio-button");
if (GTK_IS_RADIO_BUTTON (button))
{
GSList *list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
for (i = g_slist_length (list) - 1 ; list; list = list->next, i--)
{
GdkModifierType shift = pika_get_extend_selection_mask ();
GdkModifierType ctrl = pika_get_constrain_behavior_mask ();
GdkModifierType modifier = 0;
gchar *tooltip = "";
gchar *tip;
gchar *label;
switch (i)
{
case PIKA_HANDLE_MODE_ADD_TRANSFORM:
modifier = 0;
tooltip = _("Add handles and transform the image");
break;
case PIKA_HANDLE_MODE_MOVE:
modifier = shift;
tooltip = _("Move transform handles");
break;
case PIKA_HANDLE_MODE_REMOVE:
modifier = ctrl;
tooltip = _("Remove transform handles");
break;
}
if (modifier)
{
label = g_strdup_printf ("%s (%s)",
gtk_button_get_label (GTK_BUTTON (list->data)),
pika_get_mod_string (modifier));
gtk_button_set_label (GTK_BUTTON (list->data), label);
g_free (label);
tip = g_strdup_printf ("%s (%s)",
tooltip, pika_get_mod_string (modifier));
pika_help_set_help_data (list->data, tip, NULL);
g_free (tip);
}
else
{
pika_help_set_help_data (list->data, tooltip, NULL);
}
}
}
return vbox;
}

View File

@ -0,0 +1,58 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_HANDLE_TRANSFORM_OPTIONS_H__
#define __PIKA_HANDLE_TRANSFORM_OPTIONS_H__
#include "pikatransformgridoptions.h"
#define PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS (pika_handle_transform_options_get_type ())
#define PIKA_HANDLE_TRANSFORM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS, PikaHandleTransformOptions))
#define PIKA_HANDLE_TRANSFORM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS, PikaHandleTransformOptionsClass))
#define PIKA_IS_HANDLE_TRANSFORM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS))
#define PIKA_IS_HANDLE_TRANSFORM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS))
#define PIKA_HANDLE_TRANSFORM_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS, PikaHandleTransformOptionsClass))
typedef struct _PikaHandleTransformOptions PikaHandleTransformOptions;
typedef struct _PikaHandleTransformOptionsClass PikaHandleTransformOptionsClass;
struct _PikaHandleTransformOptions
{
PikaTransformGridOptions parent_instance;
PikaTransformHandleMode handle_mode;
};
struct _PikaHandleTransformOptionsClass
{
PikaTransformGridOptionsClass parent_class;
};
GType pika_handle_transform_options_get_type (void) G_GNUC_CONST;
GtkWidget * pika_handle_transform_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_HANDLE_TRANSFORM_OPTIONS_H__ */

View File

@ -0,0 +1,388 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"
#include "display/pikadisplay.h"
#include "display/pikatoolhandlegrid.h"
#include "display/pikatoolgui.h"
#include "pikahandletransformoptions.h"
#include "pikahandletransformtool.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
/* the transformation is defined by 8 points:
*
* 4 points on the original image and 4 corresponding points on the
* transformed image. The first N_HANDLES points on the transformed
* image are visible as handles.
*
* For these handles, the constants TRANSFORM_HANDLE_N,
* TRANSFORM_HANDLE_S, TRANSFORM_HANDLE_E and TRANSFORM_HANDLE_W are
* used. Actually, it makes no sense to name the handles with north,
* south, east, and west. But this way, we don't need to define even
* more enum constants.
*/
/* index into trans_info array */
enum
{
X0,
Y0,
X1,
Y1,
X2,
Y2,
X3,
Y3,
OX0,
OY0,
OX1,
OY1,
OX2,
OY2,
OX3,
OY3,
N_HANDLES
};
/* local function prototypes */
static void pika_handle_transform_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display);
static void pika_handle_transform_tool_matrix_to_info (PikaTransformGridTool *tg_tool,
const PikaMatrix3 *transform);
static void pika_handle_transform_tool_prepare (PikaTransformGridTool *tg_tool);
static PikaToolWidget * pika_handle_transform_tool_get_widget (PikaTransformGridTool *tg_tool);
static void pika_handle_transform_tool_update_widget (PikaTransformGridTool *tg_tool);
static void pika_handle_transform_tool_widget_changed (PikaTransformGridTool *tg_tool);
static void pika_handle_transform_tool_info_to_points (PikaGenericTransformTool *generic);
G_DEFINE_TYPE (PikaHandleTransformTool, pika_handle_transform_tool,
PIKA_TYPE_GENERIC_TRANSFORM_TOOL)
#define parent_class pika_handle_transform_tool_parent_class
void
pika_handle_transform_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_HANDLE_TRANSFORM_TOOL,
PIKA_TYPE_HANDLE_TRANSFORM_OPTIONS,
pika_handle_transform_options_gui,
PIKA_CONTEXT_PROP_MASK_BACKGROUND,
"pika-handle-transform-tool",
_("Handle Transform"),
_("Handle Transform Tool: "
"Deform the layer, selection or path with handles"),
N_("_Handle Transform"), "<shift>L",
NULL, PIKA_HELP_TOOL_HANDLE_TRANSFORM,
PIKA_ICON_TOOL_HANDLE_TRANSFORM,
data);
}
static void
pika_handle_transform_tool_class_init (PikaHandleTransformToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaTransformToolClass *tr_class = PIKA_TRANSFORM_TOOL_CLASS (klass);
PikaTransformGridToolClass *tg_class = PIKA_TRANSFORM_GRID_TOOL_CLASS (klass);
PikaGenericTransformToolClass *generic_class = PIKA_GENERIC_TRANSFORM_TOOL_CLASS (klass);
tool_class->modifier_key = pika_handle_transform_tool_modifier_key;
tg_class->matrix_to_info = pika_handle_transform_tool_matrix_to_info;
tg_class->prepare = pika_handle_transform_tool_prepare;
tg_class->get_widget = pika_handle_transform_tool_get_widget;
tg_class->update_widget = pika_handle_transform_tool_update_widget;
tg_class->widget_changed = pika_handle_transform_tool_widget_changed;
generic_class->info_to_points = pika_handle_transform_tool_info_to_points;
tr_class->undo_desc = C_("undo-type", "Handle transform");
tr_class->progress_text = _("Handle transformation");
}
static void
pika_handle_transform_tool_init (PikaHandleTransformTool *ht_tool)
{
ht_tool->saved_handle_mode = PIKA_HANDLE_MODE_ADD_TRANSFORM;
}
static void
pika_handle_transform_tool_modifier_key (PikaTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
PikaDisplay *display)
{
PikaHandleTransformTool *ht_tool = PIKA_HANDLE_TRANSFORM_TOOL (tool);
PikaHandleTransformOptions *options;
GdkModifierType shift = pika_get_extend_selection_mask ();
GdkModifierType ctrl = pika_get_constrain_behavior_mask ();
PikaTransformHandleMode handle_mode;
options = PIKA_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tool);
handle_mode = options->handle_mode;
if (press)
{
if (key == (state & (shift | ctrl)))
{
/* first modifier pressed */
ht_tool->saved_handle_mode = options->handle_mode;
}
}
else
{
if (! (state & (shift | ctrl)))
{
/* last modifier released */
handle_mode = ht_tool->saved_handle_mode;
}
}
if (state & shift)
{
handle_mode = PIKA_HANDLE_MODE_MOVE;
}
else if (state & ctrl)
{
handle_mode = PIKA_HANDLE_MODE_REMOVE;
}
if (handle_mode != options->handle_mode)
{
g_object_set (options,
"handle-mode", handle_mode,
NULL);
}
PIKA_TOOL_CLASS (parent_class)->modifier_key (tool, key, press,
state, display);
}
static void
pika_handle_transform_tool_matrix_to_info (PikaTransformGridTool *tg_tool,
const PikaMatrix3 *transform)
{
pika_matrix3_transform_point (transform,
tg_tool->trans_info[OX0],
tg_tool->trans_info[OY0],
&tg_tool->trans_info[X0],
&tg_tool->trans_info[Y0]);
pika_matrix3_transform_point (transform,
tg_tool->trans_info[OX1],
tg_tool->trans_info[OY1],
&tg_tool->trans_info[X1],
&tg_tool->trans_info[Y1]);
pika_matrix3_transform_point (transform,
tg_tool->trans_info[OX2],
tg_tool->trans_info[OY2],
&tg_tool->trans_info[X2],
&tg_tool->trans_info[Y2]);
pika_matrix3_transform_point (transform,
tg_tool->trans_info[OX3],
tg_tool->trans_info[OY3],
&tg_tool->trans_info[X3],
&tg_tool->trans_info[Y3]);
}
static void
pika_handle_transform_tool_prepare (PikaTransformGridTool *tg_tool)
{
PikaTransformTool *tr_tool = PIKA_TRANSFORM_TOOL (tg_tool);
PIKA_TRANSFORM_GRID_TOOL_CLASS (parent_class)->prepare (tg_tool);
tg_tool->trans_info[X0] = (gdouble) tr_tool->x1;
tg_tool->trans_info[Y0] = (gdouble) tr_tool->y1;
tg_tool->trans_info[X1] = (gdouble) tr_tool->x2;
tg_tool->trans_info[Y1] = (gdouble) tr_tool->y1;
tg_tool->trans_info[X2] = (gdouble) tr_tool->x1;
tg_tool->trans_info[Y2] = (gdouble) tr_tool->y2;
tg_tool->trans_info[X3] = (gdouble) tr_tool->x2;
tg_tool->trans_info[Y3] = (gdouble) tr_tool->y2;
tg_tool->trans_info[OX0] = (gdouble) tr_tool->x1;
tg_tool->trans_info[OY0] = (gdouble) tr_tool->y1;
tg_tool->trans_info[OX1] = (gdouble) tr_tool->x2;
tg_tool->trans_info[OY1] = (gdouble) tr_tool->y1;
tg_tool->trans_info[OX2] = (gdouble) tr_tool->x1;
tg_tool->trans_info[OY2] = (gdouble) tr_tool->y2;
tg_tool->trans_info[OX3] = (gdouble) tr_tool->x2;
tg_tool->trans_info[OY3] = (gdouble) tr_tool->y2;
tg_tool->trans_info[N_HANDLES] = 0;
}
static PikaToolWidget *
pika_handle_transform_tool_get_widget (PikaTransformGridTool *tg_tool)
{
PikaTool *tool = PIKA_TOOL (tg_tool);
PikaTransformTool *tr_tool = PIKA_TRANSFORM_TOOL (tg_tool);
PikaHandleTransformOptions *options;
PikaDisplayShell *shell = pika_display_get_shell (tool->display);
PikaToolWidget *widget;
options = PIKA_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tg_tool);
widget = pika_tool_handle_grid_new (shell,
tr_tool->x1,
tr_tool->y1,
tr_tool->x2,
tr_tool->y2);
g_object_set (widget,
"n-handles", (gint) tg_tool->trans_info[N_HANDLES],
"orig-x1", tg_tool->trans_info[OX0],
"orig-y1", tg_tool->trans_info[OY0],
"orig-x2", tg_tool->trans_info[OX1],
"orig-y2", tg_tool->trans_info[OY1],
"orig-x3", tg_tool->trans_info[OX2],
"orig-y3", tg_tool->trans_info[OY2],
"orig-x4", tg_tool->trans_info[OX3],
"orig-y4", tg_tool->trans_info[OY3],
"trans-x1", tg_tool->trans_info[X0],
"trans-y1", tg_tool->trans_info[Y0],
"trans-x2", tg_tool->trans_info[X1],
"trans-y2", tg_tool->trans_info[Y1],
"trans-x3", tg_tool->trans_info[X2],
"trans-y3", tg_tool->trans_info[Y2],
"trans-x4", tg_tool->trans_info[X3],
"trans-y4", tg_tool->trans_info[Y3],
NULL);
g_object_bind_property (G_OBJECT (options), "handle-mode",
G_OBJECT (widget), "handle-mode",
G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
return widget;
}
static void
pika_handle_transform_tool_update_widget (PikaTransformGridTool *tg_tool)
{
PikaMatrix3 transform;
gboolean transform_valid;
PIKA_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
transform_valid = pika_transform_grid_tool_info_to_matrix (tg_tool,
&transform);
g_object_set (tg_tool->widget,
"show-guides", transform_valid,
"n-handles", (gint) tg_tool->trans_info[N_HANDLES],
"orig-x1", tg_tool->trans_info[OX0],
"orig-y1", tg_tool->trans_info[OY0],
"orig-x2", tg_tool->trans_info[OX1],
"orig-y2", tg_tool->trans_info[OY1],
"orig-x3", tg_tool->trans_info[OX2],
"orig-y3", tg_tool->trans_info[OY2],
"orig-x4", tg_tool->trans_info[OX3],
"orig-y4", tg_tool->trans_info[OY3],
"trans-x1", tg_tool->trans_info[X0],
"trans-y1", tg_tool->trans_info[Y0],
"trans-x2", tg_tool->trans_info[X1],
"trans-y2", tg_tool->trans_info[Y1],
"trans-x3", tg_tool->trans_info[X2],
"trans-y3", tg_tool->trans_info[Y2],
"trans-x4", tg_tool->trans_info[X3],
"trans-y4", tg_tool->trans_info[Y3],
NULL);
}
static void
pika_handle_transform_tool_widget_changed (PikaTransformGridTool *tg_tool)
{
gint n_handles;
g_object_get (tg_tool->widget,
"n-handles", &n_handles,
"orig-x1", &tg_tool->trans_info[OX0],
"orig-y1", &tg_tool->trans_info[OY0],
"orig-x2", &tg_tool->trans_info[OX1],
"orig-y2", &tg_tool->trans_info[OY1],
"orig-x3", &tg_tool->trans_info[OX2],
"orig-y3", &tg_tool->trans_info[OY2],
"orig-x4", &tg_tool->trans_info[OX3],
"orig-y4", &tg_tool->trans_info[OY3],
"trans-x1", &tg_tool->trans_info[X0],
"trans-y1", &tg_tool->trans_info[Y0],
"trans-x2", &tg_tool->trans_info[X1],
"trans-y2", &tg_tool->trans_info[Y1],
"trans-x3", &tg_tool->trans_info[X2],
"trans-y3", &tg_tool->trans_info[Y2],
"trans-x4", &tg_tool->trans_info[X3],
"trans-y4", &tg_tool->trans_info[Y3],
NULL);
tg_tool->trans_info[N_HANDLES] = n_handles;
PIKA_TRANSFORM_GRID_TOOL_CLASS (parent_class)->widget_changed (tg_tool);
}
static void
pika_handle_transform_tool_info_to_points (PikaGenericTransformTool *generic)
{
PikaTransformGridTool *tg_tool = PIKA_TRANSFORM_GRID_TOOL (generic);
generic->input_points[0] = (PikaVector2) {tg_tool->trans_info[OX0],
tg_tool->trans_info[OY0]};
generic->input_points[1] = (PikaVector2) {tg_tool->trans_info[OX1],
tg_tool->trans_info[OY1]};
generic->input_points[2] = (PikaVector2) {tg_tool->trans_info[OX2],
tg_tool->trans_info[OY2]};
generic->input_points[3] = (PikaVector2) {tg_tool->trans_info[OX3],
tg_tool->trans_info[OY3]};
generic->output_points[0] = (PikaVector2) {tg_tool->trans_info[X0],
tg_tool->trans_info[Y0]};
generic->output_points[1] = (PikaVector2) {tg_tool->trans_info[X1],
tg_tool->trans_info[Y1]};
generic->output_points[2] = (PikaVector2) {tg_tool->trans_info[X2],
tg_tool->trans_info[Y2]};
generic->output_points[3] = (PikaVector2) {tg_tool->trans_info[X3],
tg_tool->trans_info[Y3]};
}

View File

@ -0,0 +1,61 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_HANDLE_TRANSFORM_TOOL_H__
#define __PIKA_HANDLE_TRANSFORM_TOOL_H__
#include "pikagenerictransformtool.h"
#define PIKA_TYPE_HANDLE_TRANSFORM_TOOL (pika_handle_transform_tool_get_type ())
#define PIKA_HANDLE_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_HANDLE_TRANSFORM_TOOL, PikaHandleTransformTool))
#define PIKA_HANDLE_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_HANDLE_TRANSFORM_TOOL, PikaHandleTransformToolClass))
#define PIKA_IS_HANDLE_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_HANDLE_TRANSFORM_TOOL))
#define PIKA_IS_HANDLE_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_HANDLE_TRANSFORM_TOOL))
#define PIKA_HANDLE_TRANSFORM_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_HANDLE_TRANSFORM_TOOL, PikaHandleTransformToolClass))
#define PIKA_HANDLE_TRANSFORM_TOOL_GET_OPTIONS(t) (PIKA_HANDLE_TRANSFORM_OPTIONS (pika_tool_get_options (PIKA_TOOL (t))))
typedef struct _PikaHandleTransformTool PikaHandleTransformTool;
typedef struct _PikaHandleTransformToolClass PikaHandleTransformToolClass;
struct _PikaHandleTransformTool
{
PikaGenericTransformTool parent_instance;
PikaTransformHandleMode saved_handle_mode;
};
struct _PikaHandleTransformToolClass
{
PikaGenericTransformToolClass parent_class;
};
void pika_handle_transform_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_handle_transform_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_HANDLE_TRANSFORM_TOOL_H__ */

113
app/tools/pikahealtool.c Normal file
View File

@ -0,0 +1,113 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "paint/pikasourceoptions.h"
#include "widgets/pikahelp-ids.h"
#include "pikahealtool.h"
#include "pikapaintoptions-gui.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static GtkWidget * pika_heal_options_gui (PikaToolOptions *tool_options);
G_DEFINE_TYPE (PikaHealTool, pika_heal_tool, PIKA_TYPE_SOURCE_TOOL)
void
pika_heal_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_HEAL_TOOL,
PIKA_TYPE_SOURCE_OPTIONS,
pika_heal_options_gui,
PIKA_PAINT_OPTIONS_CONTEXT_MASK,
"pika-heal-tool",
_("Healing"),
_("Healing Tool: Heal image irregularities"),
N_("_Heal"),
"H",
NULL,
PIKA_HELP_TOOL_HEAL,
PIKA_ICON_TOOL_HEAL,
data);
}
static void
pika_heal_tool_class_init (PikaHealToolClass *klass)
{
}
static void
pika_heal_tool_init (PikaHealTool *heal)
{
PikaTool *tool = PIKA_TOOL (heal);
PikaPaintTool *paint_tool = PIKA_PAINT_TOOL (tool);
PikaSourceTool *source_tool = PIKA_SOURCE_TOOL (tool);
pika_tool_control_set_tool_cursor (tool->control, PIKA_TOOL_CURSOR_HEAL);
paint_tool->status = _("Click to heal");
paint_tool->status_ctrl = _("%s to set a new heal source");
source_tool->status_paint = _("Click to heal");
/* Translators: the translation of "Click" must be the first word */
source_tool->status_set_source = _("Click to set a new heal source");
source_tool->status_set_source_ctrl = _("%s to set a new heal source");
}
/* tool options stuff */
static GtkWidget *
pika_heal_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *button;
GtkWidget *combo;
/* the sample merged checkbox */
button = pika_prop_check_button_new (config, "sample-merged",
_("Sample merged"));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* the alignment combo */
combo = pika_prop_enum_combo_box_new (config, "align-mode", 0, 0);
pika_int_combo_box_set_label (PIKA_INT_COMBO_BOX (combo), _("Alignment"));
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
gtk_box_pack_start (GTK_BOX (vbox), combo, TRUE, TRUE, 0);
return vbox;
}

57
app/tools/pikahealtool.h Normal file
View File

@ -0,0 +1,57 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_HEAL_TOOL_H__
#define __PIKA_HEAL_TOOL_H__
#include "pikasourcetool.h"
#define PIKA_TYPE_HEAL_TOOL (pika_heal_tool_get_type ())
#define PIKA_HEAL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_HEAL_TOOL, PikaHealTool))
#define PIKA_HEAL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_HEAL_TOOL, PikaHealToolClass))
#define PIKA_IS_HEAL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_HEAL_TOOL))
#define PIKA_IS_HEAL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_HEAL_TOOL))
#define PIKA_HEAL_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_HEAL_TOOL, PikaHealToolClass))
typedef struct _PikaHealTool PikaHealTool;
typedef struct _PikaHealToolClass PikaHealToolClass;
struct _PikaHealTool
{
PikaSourceTool parent_instance;
};
struct _PikaHealToolClass
{
PikaSourceToolClass parent_class;
};
void pika_heal_tool_register (PikaToolRegisterCallback callback,
gpointer data);
GType pika_heal_tool_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_HEAL_TOOL_H__ */

View File

@ -0,0 +1,118 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "tools-types.h"
#include "pikahistogramoptions.h"
#include "pika-intl.h"
enum
{
PROP_0,
PROP_SCALE
};
static void pika_histogram_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_histogram_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaHistogramOptions, pika_histogram_options,
PIKA_TYPE_FILTER_OPTIONS)
static void
pika_histogram_options_class_init (PikaHistogramOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_histogram_options_set_property;
object_class->get_property = pika_histogram_options_get_property;
PIKA_CONFIG_PROP_ENUM (object_class, PROP_SCALE,
"histogram-scale",
_("Histogram Scale"),
NULL,
PIKA_TYPE_HISTOGRAM_SCALE,
PIKA_HISTOGRAM_SCALE_LINEAR,
PIKA_PARAM_STATIC_STRINGS);
}
static void
pika_histogram_options_init (PikaHistogramOptions *options)
{
}
static void
pika_histogram_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaHistogramOptions *options = PIKA_HISTOGRAM_OPTIONS (object);
switch (property_id)
{
case PROP_SCALE:
options->scale = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_histogram_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaHistogramOptions *options = PIKA_HISTOGRAM_OPTIONS (object);
switch (property_id)
{
case PROP_SCALE:
g_value_set_enum (value, options->scale);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}

View File

@ -0,0 +1,56 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_HISTOGRAM_OPTIONS_H__
#define __PIKA_HISTOGRAM_OPTIONS_H__
#include "pikafilteroptions.h"
#define PIKA_TYPE_HISTOGRAM_OPTIONS (pika_histogram_options_get_type ())
#define PIKA_HISTOGRAM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_HISTOGRAM_OPTIONS, PikaHistogramOptions))
#define PIKA_HISTOGRAM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_HISTOGRAM_OPTIONS, PikaHistogramOptionsClass))
#define PIKA_IS_HISTOGRAM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_HISTOGRAM_OPTIONS))
#define PIKA_IS_HISTOGRAM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_HISTOGRAM_OPTIONS))
#define PIKA_HISTOGRAM_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_HISTOGRAM_OPTIONS, PikaHistogramOptionsClass))
typedef struct _PikaHistogramOptions PikaHistogramOptions;
typedef struct _PikaHistogramOptionsClass PikaHistogramOptionsClass;
struct _PikaHistogramOptions
{
PikaFilterOptions parent_instance;
PikaHistogramScale scale;
};
struct _PikaHistogramOptionsClass
{
PikaFilterOptionsClass parent_class;
};
GType pika_histogram_options_get_type (void) G_GNUC_CONST;
#endif /* __PIKA_HISTOGRAM_OPTIONS_H__ */

View File

@ -0,0 +1,141 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "config/pikaconfig-utils.h"
#include "paint/pikainkoptions.h"
#include "widgets/pikablobeditor.h"
#include "widgets/pikapropwidgets.h"
#include "pikainkoptions-gui.h"
#include "pikapaintoptions-gui.h"
#include "pika-intl.h"
GtkWidget *
pika_ink_options_gui (PikaToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
PikaInkOptions *ink_options = PIKA_INK_OPTIONS (tool_options);
GtkWidget *vbox = pika_paint_options_gui (tool_options);
GtkWidget *frame;
GtkWidget *vbox2;
GtkWidget *scale;
GtkWidget *blob_box;
GtkWidget *hbox;
GtkWidget *editor;
GtkSizeGroup *size_group;
/* adjust sliders */
frame = pika_frame_new (_("Adjustment"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
gtk_widget_show (frame);
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_container_add (GTK_CONTAINER (frame), vbox2);
gtk_widget_show (vbox2);
/* size slider */
scale = pika_prop_spin_scale_new (config, "size",
1.0, 2.0, 1);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* angle adjust slider */
scale = pika_prop_spin_scale_new (config, "tilt-angle",
1.0, 10.0, 1);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* sens sliders */
frame = pika_frame_new (_("Sensitivity"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
gtk_widget_show (frame);
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_container_add (GTK_CONTAINER (frame), vbox2);
gtk_widget_show (vbox2);
/* size sens slider */
scale = pika_prop_spin_scale_new (config, "size-sensitivity",
0.01, 0.1, 2);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* tilt sens slider */
scale = pika_prop_spin_scale_new (config, "tilt-sensitivity",
0.01, 0.1, 2);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* velocity sens slider */
scale = pika_prop_spin_scale_new (config, "vel-sensitivity",
0.01, 0.1, 2);
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
/* Blob shape widgets */
frame = pika_frame_new (_("Shape"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_container_add (GTK_CONTAINER (frame), hbox);
gtk_widget_show (hbox);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
/* Blob type radiobuttons */
blob_box = pika_prop_enum_icon_box_new (config, "blob-type",
"pika-shape", 0, 0);
gtk_orientable_set_orientation (GTK_ORIENTABLE (blob_box),
GTK_ORIENTATION_VERTICAL);
gtk_box_pack_start (GTK_BOX (hbox), blob_box, FALSE, FALSE, 0);
gtk_size_group_add_widget (size_group, blob_box);
g_object_unref (size_group);
/* Blob editor */
frame = gtk_aspect_frame_new (NULL, 0.0, 0.5, 1.0, FALSE);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
gtk_size_group_add_widget (size_group, frame);
editor = pika_blob_editor_new (ink_options->blob_type,
ink_options->blob_aspect,
ink_options->blob_angle);
gtk_container_add (GTK_CONTAINER (frame), editor);
gtk_widget_show (editor);
pika_config_connect (config, G_OBJECT (editor), "blob-type");
pika_config_connect (config, G_OBJECT (editor), "blob-aspect");
pika_config_connect (config, G_OBJECT (editor), "blob-angle");
return vbox;
}

View File

@ -0,0 +1,29 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_INK_OPTIONS_GUI_H__
#define __PIKA_INK_OPTIONS_GUI_H__
GtkWidget * pika_ink_options_gui (PikaToolOptions *tool_options);
#endif /* __PIKA_INK_OPTIONS_GUI_H__ */

153
app/tools/pikainktool.c Normal file
View File

@ -0,0 +1,153 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikawidgets/pikawidgets.h"
#include "tools-types.h"
#include "operations/layer-modes/pika-layer-modes.h"
#include "paint/pikainkoptions.h"
#include "widgets/pikahelp-ids.h"
#include "pikainkoptions-gui.h"
#include "pikainktool.h"
#include "pikatoolcontrol.h"
#include "pika-intl.h"
static PikaCanvasItem * pika_ink_tool_get_outline (PikaPaintTool *paint_tool,
PikaDisplay *display,
gdouble x,
gdouble y);
static gboolean pika_ink_tool_is_alpha_only (PikaPaintTool *paint_tool,
PikaDrawable *drawable);
static void pika_ink_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec);
G_DEFINE_TYPE (PikaInkTool, pika_ink_tool, PIKA_TYPE_PAINT_TOOL)
#define parent_class pika_ink_tool_parent_class
void
pika_ink_tool_register (PikaToolRegisterCallback callback,
gpointer data)
{
(* callback) (PIKA_TYPE_INK_TOOL,
PIKA_TYPE_INK_OPTIONS,
pika_ink_options_gui,
PIKA_CONTEXT_PROP_MASK_FOREGROUND |
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
PIKA_CONTEXT_PROP_MASK_OPACITY |
PIKA_CONTEXT_PROP_MASK_PAINT_MODE,
"pika-ink-tool",
_("Ink"),
_("Ink Tool: Calligraphy-style painting"),
N_("In_k"), "K",
NULL, PIKA_HELP_TOOL_INK,
PIKA_ICON_TOOL_INK,
data);
}
static void
pika_ink_tool_class_init (PikaInkToolClass *klass)
{
PikaToolClass *tool_class = PIKA_TOOL_CLASS (klass);
PikaPaintToolClass *paint_tool_class = PIKA_PAINT_TOOL_CLASS (klass);
tool_class->options_notify = pika_ink_tool_options_notify;
paint_tool_class->get_outline = pika_ink_tool_get_outline;
paint_tool_class->is_alpha_only = pika_ink_tool_is_alpha_only;
}
static void
pika_ink_tool_init (PikaInkTool *ink_tool)
{
PikaTool *tool = PIKA_TOOL (ink_tool);
pika_tool_control_set_tool_cursor (tool->control, PIKA_TOOL_CURSOR_INK);
pika_tool_control_set_action_pixel_size (tool->control,
"tools-ink-blob-pixel-size-set");
pika_tool_control_set_action_size (tool->control,
"tools-ink-blob-size-set");
pika_tool_control_set_action_aspect (tool->control,
"tools-ink-blob-aspect-set");
pika_tool_control_set_action_angle (tool->control,
"tools-ink-blob-angle-set");
pika_paint_tool_enable_color_picker (PIKA_PAINT_TOOL (ink_tool),
PIKA_COLOR_PICK_TARGET_FOREGROUND);
}
static void
pika_ink_tool_options_notify (PikaTool *tool,
PikaToolOptions *options,
const GParamSpec *pspec)
{
PIKA_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
if (g_strcmp0 (pspec->name, "size") == 0 &&
PIKA_PAINT_TOOL (tool)->draw_brush)
{
/* This triggers a redraw of the tool pointer, especially useful
* here when we change the pen size with on-canvas interaction.
*/
pika_draw_tool_pause (PIKA_DRAW_TOOL (tool));
pika_draw_tool_resume (PIKA_DRAW_TOOL (tool));
}
}
static PikaCanvasItem *
pika_ink_tool_get_outline (PikaPaintTool *paint_tool,
PikaDisplay *display,
gdouble x,
gdouble y)
{
PikaInkOptions *options = PIKA_INK_TOOL_GET_OPTIONS (paint_tool);
pika_paint_tool_set_draw_circle (paint_tool, TRUE,
options->size);
return NULL;
}
static gboolean
pika_ink_tool_is_alpha_only (PikaPaintTool *paint_tool,
PikaDrawable *drawable)
{
PikaPaintOptions *paint_options = PIKA_PAINT_TOOL_GET_OPTIONS (paint_tool);
PikaContext *context = PIKA_CONTEXT (paint_options);
PikaLayerMode paint_mode = pika_context_get_paint_mode (context);
return pika_layer_mode_is_alpha_only (paint_mode);
}

Some files were not shown because too many files have changed in this diff Show More