PIKApp/app/core/pikacontext.c

3887 lines
124 KiB
C
Raw Normal View History

2023-09-26 00:35:21 +02:00
/* 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
*
* pikacontext.c
* Copyright (C) 1999-2010 Michael Natterer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "core-types.h"
#include "config/pikacoreconfig.h"
#include "pika.h"
#include "pika-memsize.h"
#include "pikabrush.h"
#include "pikabuffer.h"
#include "pikacontainer.h"
#include "pikacontext.h"
#include "pikadatafactory.h"
#include "pikadisplay.h"
#include "pikadynamics.h"
#include "pikaimagefile.h"
#include "pikagradient.h"
#include "pikaimage.h"
#include "pikalineart.h"
#include "pikamybrush.h"
#include "pikapaintinfo.h"
#include "pikapalette.h"
#include "pikapattern.h"
#include "pikatemplate.h"
#include "pikatoolinfo.h"
#include "pikatoolpreset.h"
#include "text/pikafont.h"
#include "pika-intl.h"
#define RGBA_EPSILON 1e-10
typedef void (* PikaContextCopyPropFunc) (PikaContext *src,
PikaContext *dest);
#define context_find_defined(context, prop) \
while (!(((context)->defined_props) & (1 << (prop))) && (context)->parent) \
(context) = (context)->parent
#define COPY_NAME(src, dest, member) \
g_free (dest->member); \
dest->member = g_strdup (src->member)
/* local function prototypes */
static void pika_context_config_iface_init (PikaConfigInterface *iface);
static void pika_context_constructed (GObject *object);
static void pika_context_dispose (GObject *object);
static void pika_context_finalize (GObject *object);
static void pika_context_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_context_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gint64 pika_context_get_memsize (PikaObject *object,
gint64 *gui_size);
static gboolean pika_context_serialize (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data);
static gboolean pika_context_deserialize (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data);
static gboolean pika_context_serialize_property (PikaConfig *config,
guint property_id,
const GValue *value,
GParamSpec *pspec,
PikaConfigWriter *writer);
static gboolean pika_context_deserialize_property (PikaConfig *config,
guint property_id,
GValue *value,
GParamSpec *pspec,
GScanner *scanner,
GTokenType *expected);
static PikaConfig * pika_context_duplicate (PikaConfig *config);
static gboolean pika_context_copy (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags);
/* image */
static void pika_context_image_removed (PikaContainer *container,
PikaImage *image,
PikaContext *context);
static void pika_context_real_set_image (PikaContext *context,
PikaImage *image);
/* display */
static void pika_context_display_removed (PikaContainer *container,
PikaDisplay *display,
PikaContext *context);
static void pika_context_real_set_display (PikaContext *context,
PikaDisplay *display);
/* tool */
static void pika_context_tool_dirty (PikaToolInfo *tool_info,
PikaContext *context);
static void pika_context_tool_removed (PikaContainer *container,
PikaToolInfo *tool_info,
PikaContext *context);
static void pika_context_tool_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_tool (PikaContext *context,
PikaToolInfo *tool_info);
/* paint info */
static void pika_context_paint_info_dirty (PikaPaintInfo *paint_info,
PikaContext *context);
static void pika_context_paint_info_removed (PikaContainer *container,
PikaPaintInfo *paint_info,
PikaContext *context);
static void pika_context_paint_info_list_thaw(PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_paint_info (PikaContext *context,
PikaPaintInfo *paint_info);
/* foreground */
static void pika_context_real_set_foreground (PikaContext *context,
const PikaRGB *color);
/* background */
static void pika_context_real_set_background (PikaContext *context,
const PikaRGB *color);
/* opacity */
static void pika_context_real_set_opacity (PikaContext *context,
gdouble opacity);
/* paint mode */
static void pika_context_real_set_paint_mode (PikaContext *context,
PikaLayerMode paint_mode);
/* brush */
static void pika_context_brush_dirty (PikaBrush *brush,
PikaContext *context);
static void pika_context_brush_removed (PikaContainer *brush_list,
PikaBrush *brush,
PikaContext *context);
static void pika_context_brush_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_brush (PikaContext *context,
PikaBrush *brush);
/* dynamics */
static void pika_context_dynamics_dirty (PikaDynamics *dynamics,
PikaContext *context);
static void pika_context_dynamics_removed (PikaContainer *container,
PikaDynamics *dynamics,
PikaContext *context);
static void pika_context_dynamics_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_dynamics (PikaContext *context,
PikaDynamics *dynamics);
/* mybrush */
static void pika_context_mybrush_dirty (PikaMybrush *brush,
PikaContext *context);
static void pika_context_mybrush_removed (PikaContainer *brush_list,
PikaMybrush *brush,
PikaContext *context);
static void pika_context_mybrush_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_mybrush (PikaContext *context,
PikaMybrush *brush);
/* pattern */
static void pika_context_pattern_dirty (PikaPattern *pattern,
PikaContext *context);
static void pika_context_pattern_removed (PikaContainer *container,
PikaPattern *pattern,
PikaContext *context);
static void pika_context_pattern_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_pattern (PikaContext *context,
PikaPattern *pattern);
/* gradient */
static void pika_context_gradient_dirty (PikaGradient *gradient,
PikaContext *context);
static void pika_context_gradient_removed (PikaContainer *container,
PikaGradient *gradient,
PikaContext *context);
static void pika_context_gradient_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_gradient (PikaContext *context,
PikaGradient *gradient);
/* palette */
static void pika_context_palette_dirty (PikaPalette *palette,
PikaContext *context);
static void pika_context_palette_removed (PikaContainer *container,
PikaPalette *palette,
PikaContext *context);
static void pika_context_palette_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_palette (PikaContext *context,
PikaPalette *palette);
/* font */
static void pika_context_font_dirty (PikaFont *font,
PikaContext *context);
static void pika_context_font_removed (PikaContainer *container,
PikaFont *font,
PikaContext *context);
static void pika_context_font_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_font (PikaContext *context,
PikaFont *font);
/* tool preset */
static void pika_context_tool_preset_dirty (PikaToolPreset *tool_preset,
PikaContext *context);
static void pika_context_tool_preset_removed (PikaContainer *container,
PikaToolPreset *tool_preset,
PikaContext *context);
static void pika_context_tool_preset_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_tool_preset (PikaContext *context,
PikaToolPreset *tool_preset);
/* buffer */
static void pika_context_buffer_dirty (PikaBuffer *buffer,
PikaContext *context);
static void pika_context_buffer_removed (PikaContainer *container,
PikaBuffer *buffer,
PikaContext *context);
static void pika_context_buffer_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_buffer (PikaContext *context,
PikaBuffer *buffer);
/* imagefile */
static void pika_context_imagefile_dirty (PikaImagefile *imagefile,
PikaContext *context);
static void pika_context_imagefile_removed (PikaContainer *container,
PikaImagefile *imagefile,
PikaContext *context);
static void pika_context_imagefile_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_imagefile (PikaContext *context,
PikaImagefile *imagefile);
/* template */
static void pika_context_template_dirty (PikaTemplate *template,
PikaContext *context);
static void pika_context_template_removed (PikaContainer *container,
PikaTemplate *template,
PikaContext *context);
static void pika_context_template_list_thaw (PikaContainer *container,
PikaContext *context);
static void pika_context_real_set_template (PikaContext *context,
PikaTemplate *template);
/* line art */
static gboolean pika_context_free_line_art (PikaContext *context);
/* utilities */
static gpointer pika_context_find_object (PikaContext *context,
PikaContainer *container,
const gchar *object_name,
gpointer standard_object);
/* properties & signals */
enum
{
PIKA_CONTEXT_PROP_0,
PIKA_CONTEXT_PROP_PIKA
/* remaining values are in core-enums.h (PikaContextPropType) */
};
enum
{
DUMMY_0,
DUMMY_1,
IMAGE_CHANGED,
DISPLAY_CHANGED,
TOOL_CHANGED,
PAINT_INFO_CHANGED,
FOREGROUND_CHANGED,
BACKGROUND_CHANGED,
OPACITY_CHANGED,
PAINT_MODE_CHANGED,
BRUSH_CHANGED,
DYNAMICS_CHANGED,
MYBRUSH_CHANGED,
PATTERN_CHANGED,
GRADIENT_CHANGED,
PALETTE_CHANGED,
FONT_CHANGED,
TOOL_PRESET_CHANGED,
BUFFER_CHANGED,
IMAGEFILE_CHANGED,
TEMPLATE_CHANGED,
PROP_NAME_CHANGED,
LAST_SIGNAL
};
static const gchar * const pika_context_prop_names[] =
{
NULL, /* PROP_0 */
"pika",
"image",
"display",
"tool",
"paint-info",
"foreground",
"background",
"opacity",
"paint-mode",
"brush",
"dynamics",
"mybrush",
"pattern",
"gradient",
"palette",
"font",
"tool-preset",
"buffer",
"imagefile",
"template"
};
static GType pika_context_prop_types[] =
{
G_TYPE_NONE, /* PROP_0 */
G_TYPE_NONE, /* PROP_PIKA */
0,
G_TYPE_NONE,
0,
0,
G_TYPE_NONE,
G_TYPE_NONE,
G_TYPE_NONE,
G_TYPE_NONE,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
G_DEFINE_TYPE_WITH_CODE (PikaContext, pika_context, PIKA_TYPE_VIEWABLE,
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
pika_context_config_iface_init))
#define parent_class pika_context_parent_class
static PikaConfigInterface *parent_config_iface = NULL;
static guint pika_context_signals[LAST_SIGNAL] = { 0 };
static void
pika_context_class_init (PikaContextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
PikaRGB black;
PikaRGB white;
pika_rgba_set (&black, 0.0, 0.0, 0.0, PIKA_OPACITY_OPAQUE);
pika_rgba_set (&white, 1.0, 1.0, 1.0, PIKA_OPACITY_OPAQUE);
pika_context_signals[IMAGE_CHANGED] =
g_signal_new ("image-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, image_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_IMAGE);
pika_context_signals[DISPLAY_CHANGED] =
g_signal_new ("display-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, display_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_DISPLAY);
pika_context_signals[TOOL_CHANGED] =
g_signal_new ("tool-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, tool_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_TOOL_INFO);
pika_context_signals[PAINT_INFO_CHANGED] =
g_signal_new ("paint-info-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, paint_info_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_PAINT_INFO);
pika_context_signals[FOREGROUND_CHANGED] =
g_signal_new ("foreground-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, foreground_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_RGB | G_SIGNAL_TYPE_STATIC_SCOPE);
pika_context_signals[BACKGROUND_CHANGED] =
g_signal_new ("background-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, background_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_RGB | G_SIGNAL_TYPE_STATIC_SCOPE);
pika_context_signals[OPACITY_CHANGED] =
g_signal_new ("opacity-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, opacity_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_DOUBLE);
pika_context_signals[PAINT_MODE_CHANGED] =
g_signal_new ("paint-mode-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, paint_mode_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_LAYER_MODE);
pika_context_signals[BRUSH_CHANGED] =
g_signal_new ("brush-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, brush_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_BRUSH);
pika_context_signals[DYNAMICS_CHANGED] =
g_signal_new ("dynamics-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, dynamics_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_DYNAMICS);
pika_context_signals[MYBRUSH_CHANGED] =
g_signal_new ("mybrush-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, mybrush_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_MYBRUSH);
pika_context_signals[PATTERN_CHANGED] =
g_signal_new ("pattern-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, pattern_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_PATTERN);
pika_context_signals[GRADIENT_CHANGED] =
g_signal_new ("gradient-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, gradient_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_GRADIENT);
pika_context_signals[PALETTE_CHANGED] =
g_signal_new ("palette-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, palette_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_PALETTE);
pika_context_signals[FONT_CHANGED] =
g_signal_new ("font-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, font_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_FONT);
pika_context_signals[TOOL_PRESET_CHANGED] =
g_signal_new ("tool-preset-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, tool_preset_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_TOOL_PRESET);
pika_context_signals[BUFFER_CHANGED] =
g_signal_new ("buffer-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, buffer_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_BUFFER);
pika_context_signals[IMAGEFILE_CHANGED] =
g_signal_new ("imagefile-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, imagefile_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_IMAGEFILE);
pika_context_signals[TEMPLATE_CHANGED] =
g_signal_new ("template-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, template_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_TEMPLATE);
pika_context_signals[PROP_NAME_CHANGED] =
g_signal_new ("prop-name-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaContextClass, prop_name_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_INT);
object_class->constructed = pika_context_constructed;
object_class->set_property = pika_context_set_property;
object_class->get_property = pika_context_get_property;
object_class->dispose = pika_context_dispose;
object_class->finalize = pika_context_finalize;
pika_object_class->get_memsize = pika_context_get_memsize;
klass->image_changed = NULL;
klass->display_changed = NULL;
klass->tool_changed = NULL;
klass->paint_info_changed = NULL;
klass->foreground_changed = NULL;
klass->background_changed = NULL;
klass->opacity_changed = NULL;
klass->paint_mode_changed = NULL;
klass->brush_changed = NULL;
klass->dynamics_changed = NULL;
klass->mybrush_changed = NULL;
klass->pattern_changed = NULL;
klass->gradient_changed = NULL;
klass->palette_changed = NULL;
klass->font_changed = NULL;
klass->tool_preset_changed = NULL;
klass->buffer_changed = NULL;
klass->imagefile_changed = NULL;
klass->template_changed = NULL;
klass->prop_name_changed = NULL;
pika_context_prop_types[PIKA_CONTEXT_PROP_IMAGE] = PIKA_TYPE_IMAGE;
pika_context_prop_types[PIKA_CONTEXT_PROP_TOOL] = PIKA_TYPE_TOOL_INFO;
pika_context_prop_types[PIKA_CONTEXT_PROP_PAINT_INFO] = PIKA_TYPE_PAINT_INFO;
pika_context_prop_types[PIKA_CONTEXT_PROP_BRUSH] = PIKA_TYPE_BRUSH;
pika_context_prop_types[PIKA_CONTEXT_PROP_DYNAMICS] = PIKA_TYPE_DYNAMICS;
pika_context_prop_types[PIKA_CONTEXT_PROP_MYBRUSH] = PIKA_TYPE_MYBRUSH;
pika_context_prop_types[PIKA_CONTEXT_PROP_PATTERN] = PIKA_TYPE_PATTERN;
pika_context_prop_types[PIKA_CONTEXT_PROP_GRADIENT] = PIKA_TYPE_GRADIENT;
pika_context_prop_types[PIKA_CONTEXT_PROP_PALETTE] = PIKA_TYPE_PALETTE;
pika_context_prop_types[PIKA_CONTEXT_PROP_FONT] = PIKA_TYPE_FONT;
pika_context_prop_types[PIKA_CONTEXT_PROP_TOOL_PRESET] = PIKA_TYPE_TOOL_PRESET;
pika_context_prop_types[PIKA_CONTEXT_PROP_BUFFER] = PIKA_TYPE_BUFFER;
pika_context_prop_types[PIKA_CONTEXT_PROP_IMAGEFILE] = PIKA_TYPE_IMAGEFILE;
pika_context_prop_types[PIKA_CONTEXT_PROP_TEMPLATE] = PIKA_TYPE_TEMPLATE;
g_object_class_install_property (object_class, PIKA_CONTEXT_PROP_PIKA,
g_param_spec_object ("pika",
NULL, NULL,
PIKA_TYPE_PIKA,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PIKA_CONTEXT_PROP_IMAGE,
g_param_spec_object (pika_context_prop_names[PIKA_CONTEXT_PROP_IMAGE],
NULL, NULL,
PIKA_TYPE_IMAGE,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PIKA_CONTEXT_PROP_DISPLAY,
g_param_spec_object (pika_context_prop_names[PIKA_CONTEXT_PROP_DISPLAY],
NULL, NULL,
PIKA_TYPE_DISPLAY,
PIKA_PARAM_READWRITE));
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_TOOL,
pika_context_prop_names[PIKA_CONTEXT_PROP_TOOL],
NULL, NULL,
PIKA_TYPE_TOOL_INFO,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_PAINT_INFO,
pika_context_prop_names[PIKA_CONTEXT_PROP_PAINT_INFO],
NULL, NULL,
PIKA_TYPE_PAINT_INFO,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_RGB (object_class, PIKA_CONTEXT_PROP_FOREGROUND,
pika_context_prop_names[PIKA_CONTEXT_PROP_FOREGROUND],
_("Foreground"),
_("Foreground color"),
FALSE, &black,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_RGB (object_class, PIKA_CONTEXT_PROP_BACKGROUND,
pika_context_prop_names[PIKA_CONTEXT_PROP_BACKGROUND],
_("Background"),
_("Background color"),
FALSE, &white,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_DOUBLE (object_class, PIKA_CONTEXT_PROP_OPACITY,
pika_context_prop_names[PIKA_CONTEXT_PROP_OPACITY],
_("Opacity"),
_("Opacity"),
PIKA_OPACITY_TRANSPARENT,
PIKA_OPACITY_OPAQUE,
PIKA_OPACITY_OPAQUE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_ENUM (object_class, PIKA_CONTEXT_PROP_PAINT_MODE,
pika_context_prop_names[PIKA_CONTEXT_PROP_PAINT_MODE],
_("Paint Mode"),
_("Paint Mode"),
PIKA_TYPE_LAYER_MODE,
PIKA_LAYER_MODE_NORMAL,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_BRUSH,
pika_context_prop_names[PIKA_CONTEXT_PROP_BRUSH],
_("Brush"),
_("Brush"),
PIKA_TYPE_BRUSH,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_DYNAMICS,
pika_context_prop_names[PIKA_CONTEXT_PROP_DYNAMICS],
_("Dynamics"),
_("Paint dynamics"),
PIKA_TYPE_DYNAMICS,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_MYBRUSH,
pika_context_prop_names[PIKA_CONTEXT_PROP_MYBRUSH],
_("MyPaint Brush"),
_("MyPaint Brush"),
PIKA_TYPE_MYBRUSH,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_PATTERN,
pika_context_prop_names[PIKA_CONTEXT_PROP_PATTERN],
_("Pattern"),
_("Pattern"),
PIKA_TYPE_PATTERN,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_GRADIENT,
pika_context_prop_names[PIKA_CONTEXT_PROP_GRADIENT],
_("Gradient"),
_("Gradient"),
PIKA_TYPE_GRADIENT,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_PALETTE,
pika_context_prop_names[PIKA_CONTEXT_PROP_PALETTE],
_("Palette"),
_("Palette"),
PIKA_TYPE_PALETTE,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_FONT,
pika_context_prop_names[PIKA_CONTEXT_PROP_FONT],
_("Font"),
_("Font"),
PIKA_TYPE_FONT,
PIKA_PARAM_STATIC_STRINGS);
PIKA_CONFIG_PROP_OBJECT (object_class, PIKA_CONTEXT_PROP_TOOL_PRESET,
pika_context_prop_names[PIKA_CONTEXT_PROP_TOOL_PRESET],
_("Tool Preset"),
_("Tool Preset"),
PIKA_TYPE_TOOL_PRESET,
PIKA_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PIKA_CONTEXT_PROP_BUFFER,
g_param_spec_object (pika_context_prop_names[PIKA_CONTEXT_PROP_BUFFER],
NULL, NULL,
PIKA_TYPE_BUFFER,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PIKA_CONTEXT_PROP_IMAGEFILE,
g_param_spec_object (pika_context_prop_names[PIKA_CONTEXT_PROP_IMAGEFILE],
NULL, NULL,
PIKA_TYPE_IMAGEFILE,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PIKA_CONTEXT_PROP_TEMPLATE,
g_param_spec_object (pika_context_prop_names[PIKA_CONTEXT_PROP_TEMPLATE],
NULL, NULL,
PIKA_TYPE_TEMPLATE,
PIKA_PARAM_READWRITE));
}
static void
pika_context_init (PikaContext *context)
{
context->pika = NULL;
context->parent = NULL;
context->defined_props = PIKA_CONTEXT_PROP_MASK_ALL;
context->serialize_props = PIKA_CONTEXT_PROP_MASK_ALL;
context->image = NULL;
context->display = NULL;
context->tool_info = NULL;
context->tool_name = NULL;
context->paint_info = NULL;
context->paint_name = NULL;
context->brush = NULL;
context->brush_name = NULL;
context->dynamics = NULL;
context->dynamics_name = NULL;
context->mybrush = NULL;
context->mybrush_name = NULL;
context->pattern = NULL;
context->pattern_name = NULL;
context->gradient = NULL;
context->gradient_name = NULL;
context->palette = NULL;
context->palette_name = NULL;
context->font = NULL;
context->font_name = NULL;
context->tool_preset = NULL;
context->tool_preset_name = NULL;
context->buffer = NULL;
context->buffer_name = NULL;
context->imagefile = NULL;
context->imagefile_name = NULL;
context->template = NULL;
context->template_name = NULL;
context->line_art = NULL;
context->line_art_timeout_id = 0;
}
static void
pika_context_config_iface_init (PikaConfigInterface *iface)
{
parent_config_iface = g_type_interface_peek_parent (iface);
if (! parent_config_iface)
parent_config_iface = g_type_default_interface_peek (PIKA_TYPE_CONFIG);
iface->serialize = pika_context_serialize;
iface->deserialize = pika_context_deserialize;
iface->serialize_property = pika_context_serialize_property;
iface->deserialize_property = pika_context_deserialize_property;
iface->duplicate = pika_context_duplicate;
iface->copy = pika_context_copy;
}
static void
pika_context_constructed (GObject *object)
{
Pika *pika;
PikaContainer *container;
G_OBJECT_CLASS (parent_class)->constructed (object);
pika = PIKA_CONTEXT (object)->pika;
pika_assert (PIKA_IS_PIKA (pika));
pika->context_list = g_list_prepend (pika->context_list, object);
g_signal_connect_object (pika->images, "remove",
G_CALLBACK (pika_context_image_removed),
object, 0);
g_signal_connect_object (pika->displays, "remove",
G_CALLBACK (pika_context_display_removed),
object, 0);
g_signal_connect_object (pika->tool_info_list, "remove",
G_CALLBACK (pika_context_tool_removed),
object, 0);
g_signal_connect_object (pika->tool_info_list, "thaw",
G_CALLBACK (pika_context_tool_list_thaw),
object, 0);
g_signal_connect_object (pika->paint_info_list, "remove",
G_CALLBACK (pika_context_paint_info_removed),
object, 0);
g_signal_connect_object (pika->paint_info_list, "thaw",
G_CALLBACK (pika_context_paint_info_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->brush_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_brush_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_brush_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->dynamics_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_dynamics_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_dynamics_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->mybrush_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_mybrush_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_mybrush_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->pattern_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_pattern_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_pattern_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->gradient_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_gradient_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_gradient_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->palette_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_palette_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_palette_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->font_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_font_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_font_list_thaw),
object, 0);
container = pika_data_factory_get_container (pika->tool_preset_factory);
g_signal_connect_object (container, "remove",
G_CALLBACK (pika_context_tool_preset_removed),
object, 0);
g_signal_connect_object (container, "thaw",
G_CALLBACK (pika_context_tool_preset_list_thaw),
object, 0);
g_signal_connect_object (pika->named_buffers, "remove",
G_CALLBACK (pika_context_buffer_removed),
object, 0);
g_signal_connect_object (pika->named_buffers, "thaw",
G_CALLBACK (pika_context_buffer_list_thaw),
object, 0);
g_signal_connect_object (pika->documents, "remove",
G_CALLBACK (pika_context_imagefile_removed),
object, 0);
g_signal_connect_object (pika->documents, "thaw",
G_CALLBACK (pika_context_imagefile_list_thaw),
object, 0);
g_signal_connect_object (pika->templates, "remove",
G_CALLBACK (pika_context_template_removed),
object, 0);
g_signal_connect_object (pika->templates, "thaw",
G_CALLBACK (pika_context_template_list_thaw),
object, 0);
pika_context_set_paint_info (PIKA_CONTEXT (object),
pika_paint_info_get_standard (pika));
}
static void
pika_context_dispose (GObject *object)
{
PikaContext *context = PIKA_CONTEXT (object);
pika_context_set_parent (context, NULL);
if (context->pika)
{
context->pika->context_list = g_list_remove (context->pika->context_list,
context);
context->pika = NULL;
}
g_clear_object (&context->tool_info);
g_clear_object (&context->paint_info);
g_clear_object (&context->brush);
g_clear_object (&context->dynamics);
g_clear_object (&context->mybrush);
g_clear_object (&context->pattern);
g_clear_object (&context->gradient);
g_clear_object (&context->palette);
g_clear_object (&context->font);
g_clear_object (&context->tool_preset);
g_clear_object (&context->buffer);
g_clear_object (&context->imagefile);
g_clear_object (&context->template);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_context_finalize (GObject *object)
{
PikaContext *context = PIKA_CONTEXT (object);
context->parent = NULL;
context->image = NULL;
context->display = NULL;
g_clear_pointer (&context->tool_name, g_free);
g_clear_pointer (&context->paint_name, g_free);
g_clear_pointer (&context->brush_name, g_free);
g_clear_pointer (&context->dynamics_name, g_free);
g_clear_pointer (&context->mybrush_name, g_free);
g_clear_pointer (&context->pattern_name, g_free);
g_clear_pointer (&context->gradient_name, g_free);
g_clear_pointer (&context->palette_name, g_free);
g_clear_pointer (&context->font_name, g_free);
g_clear_pointer (&context->tool_preset_name, g_free);
g_clear_pointer (&context->buffer_name, g_free);
g_clear_pointer (&context->imagefile_name, g_free);
g_clear_pointer (&context->template_name, g_free);
g_clear_object (&context->line_art);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_context_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaContext *context = PIKA_CONTEXT (object);
switch (property_id)
{
case PIKA_CONTEXT_PROP_PIKA:
context->pika = g_value_get_object (value);
break;
case PIKA_CONTEXT_PROP_IMAGE:
pika_context_set_image (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_DISPLAY:
pika_context_set_display (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_TOOL:
pika_context_set_tool (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_PAINT_INFO:
pika_context_set_paint_info (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_FOREGROUND:
pika_context_set_foreground (context, g_value_get_boxed (value));
break;
case PIKA_CONTEXT_PROP_BACKGROUND:
pika_context_set_background (context, g_value_get_boxed (value));
break;
case PIKA_CONTEXT_PROP_OPACITY:
pika_context_set_opacity (context, g_value_get_double (value));
break;
case PIKA_CONTEXT_PROP_PAINT_MODE:
pika_context_set_paint_mode (context, g_value_get_enum (value));
break;
case PIKA_CONTEXT_PROP_BRUSH:
pika_context_set_brush (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_DYNAMICS:
pika_context_set_dynamics (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_MYBRUSH:
pika_context_set_mybrush (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_PATTERN:
pika_context_set_pattern (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_GRADIENT:
pika_context_set_gradient (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_PALETTE:
pika_context_set_palette (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_FONT:
pika_context_set_font (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_TOOL_PRESET:
pika_context_set_tool_preset (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_BUFFER:
pika_context_set_buffer (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_IMAGEFILE:
pika_context_set_imagefile (context, g_value_get_object (value));
break;
case PIKA_CONTEXT_PROP_TEMPLATE:
pika_context_set_template (context, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_context_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaContext *context = PIKA_CONTEXT (object);
switch (property_id)
{
case PIKA_CONTEXT_PROP_PIKA:
g_value_set_object (value, context->pika);
break;
case PIKA_CONTEXT_PROP_IMAGE:
g_value_set_object (value, pika_context_get_image (context));
break;
case PIKA_CONTEXT_PROP_DISPLAY:
g_value_set_object (value, pika_context_get_display (context));
break;
case PIKA_CONTEXT_PROP_TOOL:
g_value_set_object (value, pika_context_get_tool (context));
break;
case PIKA_CONTEXT_PROP_PAINT_INFO:
g_value_set_object (value, pika_context_get_paint_info (context));
break;
case PIKA_CONTEXT_PROP_FOREGROUND:
{
PikaRGB color;
pika_context_get_foreground (context, &color);
g_value_set_boxed (value, &color);
}
break;
case PIKA_CONTEXT_PROP_BACKGROUND:
{
PikaRGB color;
pika_context_get_background (context, &color);
g_value_set_boxed (value, &color);
}
break;
case PIKA_CONTEXT_PROP_OPACITY:
g_value_set_double (value, pika_context_get_opacity (context));
break;
case PIKA_CONTEXT_PROP_PAINT_MODE:
g_value_set_enum (value, pika_context_get_paint_mode (context));
break;
case PIKA_CONTEXT_PROP_BRUSH:
g_value_set_object (value, pika_context_get_brush (context));
break;
case PIKA_CONTEXT_PROP_DYNAMICS:
g_value_set_object (value, pika_context_get_dynamics (context));
break;
case PIKA_CONTEXT_PROP_MYBRUSH:
g_value_set_object (value, pika_context_get_mybrush (context));
break;
case PIKA_CONTEXT_PROP_PATTERN:
g_value_set_object (value, pika_context_get_pattern (context));
break;
case PIKA_CONTEXT_PROP_GRADIENT:
g_value_set_object (value, pika_context_get_gradient (context));
break;
case PIKA_CONTEXT_PROP_PALETTE:
g_value_set_object (value, pika_context_get_palette (context));
break;
case PIKA_CONTEXT_PROP_FONT:
g_value_set_object (value, pika_context_get_font (context));
break;
case PIKA_CONTEXT_PROP_TOOL_PRESET:
g_value_set_object (value, pika_context_get_tool_preset (context));
break;
case PIKA_CONTEXT_PROP_BUFFER:
g_value_set_object (value, pika_context_get_buffer (context));
break;
case PIKA_CONTEXT_PROP_IMAGEFILE:
g_value_set_object (value, pika_context_get_imagefile (context));
break;
case PIKA_CONTEXT_PROP_TEMPLATE:
g_value_set_object (value, pika_context_get_template (context));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static gint64
pika_context_get_memsize (PikaObject *object,
gint64 *gui_size)
{
PikaContext *context = PIKA_CONTEXT (object);
gint64 memsize = 0;
memsize += pika_string_get_memsize (context->tool_name);
memsize += pika_string_get_memsize (context->paint_name);
memsize += pika_string_get_memsize (context->brush_name);
memsize += pika_string_get_memsize (context->dynamics_name);
memsize += pika_string_get_memsize (context->mybrush_name);
memsize += pika_string_get_memsize (context->pattern_name);
memsize += pika_string_get_memsize (context->palette_name);
memsize += pika_string_get_memsize (context->font_name);
memsize += pika_string_get_memsize (context->tool_preset_name);
memsize += pika_string_get_memsize (context->buffer_name);
memsize += pika_string_get_memsize (context->imagefile_name);
memsize += pika_string_get_memsize (context->template_name);
return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
static gboolean
pika_context_serialize (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data)
{
return pika_config_serialize_changed_properties (config, writer);
}
static gboolean
pika_context_deserialize (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data)
{
PikaContext *context = PIKA_CONTEXT (config);
PikaLayerMode old_paint_mode = context->paint_mode;
gboolean success;
success = pika_config_deserialize_properties (config, scanner, nest_level);
if (context->paint_mode != old_paint_mode)
{
if (context->paint_mode == PIKA_LAYER_MODE_OVERLAY_LEGACY)
g_object_set (context,
"paint-mode", PIKA_LAYER_MODE_SOFTLIGHT_LEGACY,
NULL);
}
return success;
}
static gboolean
pika_context_serialize_property (PikaConfig *config,
guint property_id,
const GValue *value,
GParamSpec *pspec,
PikaConfigWriter *writer)
{
PikaContext *context = PIKA_CONTEXT (config);
PikaObject *serialize_obj;
/* serialize nothing if the property is not in serialize_props */
if (! ((1 << property_id) & context->serialize_props))
return TRUE;
switch (property_id)
{
case PIKA_CONTEXT_PROP_TOOL:
case PIKA_CONTEXT_PROP_PAINT_INFO:
case PIKA_CONTEXT_PROP_BRUSH:
case PIKA_CONTEXT_PROP_DYNAMICS:
case PIKA_CONTEXT_PROP_MYBRUSH:
case PIKA_CONTEXT_PROP_PATTERN:
case PIKA_CONTEXT_PROP_GRADIENT:
case PIKA_CONTEXT_PROP_PALETTE:
case PIKA_CONTEXT_PROP_FONT:
case PIKA_CONTEXT_PROP_TOOL_PRESET:
serialize_obj = g_value_get_object (value);
break;
default:
return FALSE;
}
pika_config_writer_open (writer, pspec->name);
if (serialize_obj)
pika_config_writer_string (writer, pika_object_get_name (serialize_obj));
else
pika_config_writer_print (writer, "NULL", 4);
pika_config_writer_close (writer);
return TRUE;
}
static gboolean
pika_context_deserialize_property (PikaConfig *object,
guint property_id,
GValue *value,
GParamSpec *pspec,
GScanner *scanner,
GTokenType *expected)
{
PikaContext *context = PIKA_CONTEXT (object);
PikaContainer *container;
gpointer standard;
gchar **name_loc;
gchar *object_name;
switch (property_id)
{
case PIKA_CONTEXT_PROP_TOOL:
container = context->pika->tool_info_list;
standard = pika_tool_info_get_standard (context->pika);
name_loc = &context->tool_name;
break;
case PIKA_CONTEXT_PROP_PAINT_INFO:
container = context->pika->paint_info_list;
standard = pika_paint_info_get_standard (context->pika);
name_loc = &context->paint_name;
break;
case PIKA_CONTEXT_PROP_BRUSH:
container = pika_data_factory_get_container (context->pika->brush_factory);
standard = pika_brush_get_standard (context);
name_loc = &context->brush_name;
break;
case PIKA_CONTEXT_PROP_DYNAMICS:
container = pika_data_factory_get_container (context->pika->dynamics_factory);
standard = pika_dynamics_get_standard (context);
name_loc = &context->dynamics_name;
break;
case PIKA_CONTEXT_PROP_MYBRUSH:
container = pika_data_factory_get_container (context->pika->mybrush_factory);
standard = pika_mybrush_get_standard (context);
name_loc = &context->mybrush_name;
break;
case PIKA_CONTEXT_PROP_PATTERN:
container = pika_data_factory_get_container (context->pika->pattern_factory);
standard = pika_pattern_get_standard (context);
name_loc = &context->pattern_name;
break;
case PIKA_CONTEXT_PROP_GRADIENT:
container = pika_data_factory_get_container (context->pika->gradient_factory);
standard = pika_gradient_get_standard (context);
name_loc = &context->gradient_name;
break;
case PIKA_CONTEXT_PROP_PALETTE:
container = pika_data_factory_get_container (context->pika->palette_factory);
standard = pika_palette_get_standard (context);
name_loc = &context->palette_name;
break;
case PIKA_CONTEXT_PROP_FONT:
container = pika_data_factory_get_container (context->pika->font_factory);
standard = pika_font_get_standard ();
name_loc = &context->font_name;
break;
case PIKA_CONTEXT_PROP_TOOL_PRESET:
container = pika_data_factory_get_container (context->pika->tool_preset_factory);
standard = NULL;
name_loc = &context->tool_preset_name;
break;
default:
return FALSE;
}
if (pika_scanner_parse_identifier (scanner, "NULL"))
{
g_value_set_object (value, NULL);
}
else if (pika_scanner_parse_string (scanner, &object_name))
{
PikaObject *deserialize_obj;
if (! object_name)
object_name = g_strdup ("");
deserialize_obj = pika_container_get_child_by_name (container,
object_name);
if (! deserialize_obj)
{
g_value_set_object (value, standard);
g_free (*name_loc);
*name_loc = g_strdup (object_name);
}
else
{
g_value_set_object (value, deserialize_obj);
}
g_free (object_name);
}
else
{
*expected = G_TOKEN_STRING;
}
return TRUE;
}
static PikaConfig *
pika_context_duplicate (PikaConfig *config)
{
PikaContext *context = PIKA_CONTEXT (config);
PikaContext *new;
new = PIKA_CONTEXT (parent_config_iface->duplicate (config));
COPY_NAME (context, new, tool_name);
COPY_NAME (context, new, paint_name);
COPY_NAME (context, new, brush_name);
COPY_NAME (context, new, dynamics_name);
COPY_NAME (context, new, mybrush_name);
COPY_NAME (context, new, pattern_name);
COPY_NAME (context, new, gradient_name);
COPY_NAME (context, new, palette_name);
COPY_NAME (context, new, font_name);
COPY_NAME (context, new, tool_preset_name);
COPY_NAME (context, new, buffer_name);
COPY_NAME (context, new, imagefile_name);
COPY_NAME (context, new, template_name);
return PIKA_CONFIG (new);
}
static gboolean
pika_context_copy (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags)
{
PikaContext *src_context = PIKA_CONTEXT (src);
PikaContext *dest_context = PIKA_CONTEXT (dest);
gboolean success = parent_config_iface->copy (src, dest, flags);
COPY_NAME (src_context, dest_context, tool_name);
COPY_NAME (src_context, dest_context, paint_name);
COPY_NAME (src_context, dest_context, brush_name);
COPY_NAME (src_context, dest_context, dynamics_name);
COPY_NAME (src_context, dest_context, mybrush_name);
COPY_NAME (src_context, dest_context, pattern_name);
COPY_NAME (src_context, dest_context, gradient_name);
COPY_NAME (src_context, dest_context, palette_name);
COPY_NAME (src_context, dest_context, font_name);
COPY_NAME (src_context, dest_context, tool_preset_name);
COPY_NAME (src_context, dest_context, buffer_name);
COPY_NAME (src_context, dest_context, imagefile_name);
COPY_NAME (src_context, dest_context, template_name);
return success;
}
/*****************************************************************************/
/* public functions ********************************************************/
PikaContext *
pika_context_new (Pika *pika,
const gchar *name,
PikaContext *template)
{
PikaContext *context;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (template == NULL || PIKA_IS_CONTEXT (template), NULL);
context = g_object_new (PIKA_TYPE_CONTEXT,
"name", name,
"pika", pika,
NULL);
if (template)
{
context->defined_props = template->defined_props;
pika_context_copy_properties (template, context,
PIKA_CONTEXT_PROP_MASK_ALL);
}
return context;
}
PikaContext *
pika_context_get_parent (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->parent;
}
static void
pika_context_parent_notify (PikaContext *parent,
GParamSpec *pspec,
PikaContext *context)
{
if (pspec->owner_type == PIKA_TYPE_CONTEXT)
{
PikaContextPropType prop = pspec->param_id;
/* copy from parent if the changed property is undefined;
* ignore properties that are not context properties, for
* example notifications on the context's "pika" property
*/
if ((prop >= PIKA_CONTEXT_PROP_FIRST) &&
(prop <= PIKA_CONTEXT_PROP_LAST) &&
! ((1 << prop) & context->defined_props))
{
pika_context_copy_property (parent, context, prop);
}
}
}
void
pika_context_set_parent (PikaContext *context,
PikaContext *parent)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (parent == NULL || PIKA_IS_CONTEXT (parent));
g_return_if_fail (parent == NULL || parent->parent != context);
g_return_if_fail (context != parent);
if (context->parent == parent)
return;
if (context->parent)
{
g_signal_handlers_disconnect_by_func (context->parent,
pika_context_parent_notify,
context);
}
g_set_weak_pointer (&context->parent, parent);
if (parent)
{
/* copy all undefined properties from the new parent */
pika_context_copy_properties (parent, context,
~context->defined_props &
PIKA_CONTEXT_PROP_MASK_ALL);
g_signal_connect_object (parent, "notify",
G_CALLBACK (pika_context_parent_notify),
context,
0);
}
}
/* define / undefinine context properties */
void
pika_context_define_property (PikaContext *context,
PikaContextPropType prop,
gboolean defined)
{
PikaContextPropMask mask;
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail ((prop >= PIKA_CONTEXT_PROP_FIRST) &&
(prop <= PIKA_CONTEXT_PROP_LAST));
mask = (1 << prop);
if (defined)
{
if (! (context->defined_props & mask))
{
context->defined_props |= mask;
}
}
else
{
if (context->defined_props & mask)
{
context->defined_props &= ~mask;
if (context->parent)
pika_context_copy_property (context->parent, context, prop);
}
}
}
gboolean
pika_context_property_defined (PikaContext *context,
PikaContextPropType prop)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE);
return (context->defined_props & (1 << prop)) ? TRUE : FALSE;
}
void
pika_context_define_properties (PikaContext *context,
PikaContextPropMask prop_mask,
gboolean defined)
{
PikaContextPropType prop;
g_return_if_fail (PIKA_IS_CONTEXT (context));
for (prop = PIKA_CONTEXT_PROP_FIRST; prop <= PIKA_CONTEXT_PROP_LAST; prop++)
if ((1 << prop) & prop_mask)
pika_context_define_property (context, prop, defined);
}
/* specify which context properties will be serialized */
void
pika_context_set_serialize_properties (PikaContext *context,
PikaContextPropMask props_mask)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
context->serialize_props = props_mask;
}
PikaContextPropMask
pika_context_get_serialize_properties (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), 0);
return context->serialize_props;
}
/* copying context properties */
void
pika_context_copy_property (PikaContext *src,
PikaContext *dest,
PikaContextPropType prop)
{
g_return_if_fail (PIKA_IS_CONTEXT (src));
g_return_if_fail (PIKA_IS_CONTEXT (dest));
g_return_if_fail ((prop >= PIKA_CONTEXT_PROP_FIRST) &&
(prop <= PIKA_CONTEXT_PROP_LAST));
switch (prop)
{
case PIKA_CONTEXT_PROP_IMAGE:
pika_context_real_set_image (dest, src->image);
break;
case PIKA_CONTEXT_PROP_DISPLAY:
pika_context_real_set_display (dest, src->display);
break;
case PIKA_CONTEXT_PROP_TOOL:
pika_context_real_set_tool (dest, src->tool_info);
COPY_NAME (src, dest, tool_name);
break;
case PIKA_CONTEXT_PROP_PAINT_INFO:
pika_context_real_set_paint_info (dest, src->paint_info);
COPY_NAME (src, dest, paint_name);
break;
case PIKA_CONTEXT_PROP_FOREGROUND:
pika_context_real_set_foreground (dest, &src->foreground);
break;
case PIKA_CONTEXT_PROP_BACKGROUND:
pika_context_real_set_background (dest, &src->background);
break;
case PIKA_CONTEXT_PROP_OPACITY:
pika_context_real_set_opacity (dest, src->opacity);
break;
case PIKA_CONTEXT_PROP_PAINT_MODE:
pika_context_real_set_paint_mode (dest, src->paint_mode);
break;
case PIKA_CONTEXT_PROP_BRUSH:
pika_context_real_set_brush (dest, src->brush);
COPY_NAME (src, dest, brush_name);
break;
case PIKA_CONTEXT_PROP_DYNAMICS:
pika_context_real_set_dynamics (dest, src->dynamics);
COPY_NAME (src, dest, dynamics_name);
break;
case PIKA_CONTEXT_PROP_MYBRUSH:
pika_context_real_set_mybrush (dest, src->mybrush);
COPY_NAME (src, dest, mybrush_name);
break;
case PIKA_CONTEXT_PROP_PATTERN:
pika_context_real_set_pattern (dest, src->pattern);
COPY_NAME (src, dest, pattern_name);
break;
case PIKA_CONTEXT_PROP_GRADIENT:
pika_context_real_set_gradient (dest, src->gradient);
COPY_NAME (src, dest, gradient_name);
break;
case PIKA_CONTEXT_PROP_PALETTE:
pika_context_real_set_palette (dest, src->palette);
COPY_NAME (src, dest, palette_name);
break;
case PIKA_CONTEXT_PROP_FONT:
pika_context_real_set_font (dest, src->font);
COPY_NAME (src, dest, font_name);
break;
case PIKA_CONTEXT_PROP_TOOL_PRESET:
pika_context_real_set_tool_preset (dest, src->tool_preset);
COPY_NAME (src, dest, tool_preset_name);
break;
case PIKA_CONTEXT_PROP_BUFFER:
pika_context_real_set_buffer (dest, src->buffer);
COPY_NAME (src, dest, buffer_name);
break;
case PIKA_CONTEXT_PROP_IMAGEFILE:
pika_context_real_set_imagefile (dest, src->imagefile);
COPY_NAME (src, dest, imagefile_name);
break;
case PIKA_CONTEXT_PROP_TEMPLATE:
pika_context_real_set_template (dest, src->template);
COPY_NAME (src, dest, template_name);
break;
default:
break;
}
}
void
pika_context_copy_properties (PikaContext *src,
PikaContext *dest,
PikaContextPropMask prop_mask)
{
PikaContextPropType prop;
g_return_if_fail (PIKA_IS_CONTEXT (src));
g_return_if_fail (PIKA_IS_CONTEXT (dest));
for (prop = PIKA_CONTEXT_PROP_FIRST; prop <= PIKA_CONTEXT_PROP_LAST; prop++)
if ((1 << prop) & prop_mask)
pika_context_copy_property (src, dest, prop);
}
/* attribute access functions */
/*****************************************************************************/
/* manipulate by GType *****************************************************/
PikaContextPropType
pika_context_type_to_property (GType type)
{
PikaContextPropType prop;
for (prop = PIKA_CONTEXT_PROP_FIRST; prop <= PIKA_CONTEXT_PROP_LAST; prop++)
{
if (g_type_is_a (type, pika_context_prop_types[prop]))
return prop;
}
return -1;
}
const gchar *
pika_context_type_to_prop_name (GType type)
{
PikaContextPropType prop;
for (prop = PIKA_CONTEXT_PROP_FIRST; prop <= PIKA_CONTEXT_PROP_LAST; prop++)
{
if (g_type_is_a (type, pika_context_prop_types[prop]))
return pika_context_prop_names[prop];
}
return NULL;
}
const gchar *
pika_context_type_to_signal_name (GType type)
{
PikaContextPropType prop;
for (prop = PIKA_CONTEXT_PROP_FIRST; prop <= PIKA_CONTEXT_PROP_LAST; prop++)
{
if (g_type_is_a (type, pika_context_prop_types[prop]))
return g_signal_name (pika_context_signals[prop]);
}
return NULL;
}
PikaObject *
pika_context_get_by_type (PikaContext *context,
GType type)
{
PikaContextPropType prop;
PikaObject *object = NULL;
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
prop = pika_context_type_to_property (type);
g_return_val_if_fail (prop != -1, NULL);
g_object_get (context,
pika_context_prop_names[prop], &object,
NULL);
/* g_object_get() refs the object, this function however is a getter,
* which usually doesn't ref it's return value
*/
if (object)
g_object_unref (object);
return object;
}
void
pika_context_set_by_type (PikaContext *context,
GType type,
PikaObject *object)
{
PikaContextPropType prop;
GParamSpec *pspec;
GValue value = G_VALUE_INIT;
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (object == NULL || G_IS_OBJECT (object));
prop = pika_context_type_to_property (type);
g_return_if_fail (prop != -1);
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (context),
pika_context_prop_names[prop]);
g_return_if_fail (pspec != NULL);
g_value_init (&value, pspec->value_type);
g_value_set_object (&value, object);
/* we use pika_context_set_property() (which in turn only calls
* pika_context_set_foo() functions) instead of the much more obvious
* g_object_set(); this avoids g_object_freeze_notify()/thaw_notify()
* around the g_object_set() and makes PikaContext callbacks being
* called in a much more predictable order. See bug #731279.
*/
pika_context_set_property (G_OBJECT (context),
pspec->param_id,
(const GValue *) &value,
pspec);
g_value_unset (&value);
}
void
pika_context_changed_by_type (PikaContext *context,
GType type)
{
PikaContextPropType prop;
PikaObject *object;
g_return_if_fail (PIKA_IS_CONTEXT (context));
prop = pika_context_type_to_property (type);
g_return_if_fail (prop != -1);
object = pika_context_get_by_type (context, type);
g_signal_emit (context,
pika_context_signals[prop], 0,
object);
}
/*****************************************************************************/
/* image *******************************************************************/
PikaImage *
pika_context_get_image (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->image;
}
void
pika_context_set_image (PikaContext *context,
PikaImage *image)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (image == NULL || PIKA_IS_IMAGE (image));
context_find_defined (context, PIKA_CONTEXT_PROP_IMAGE);
pika_context_real_set_image (context, image);
}
void
pika_context_image_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[IMAGE_CHANGED], 0,
context->image);
}
static void
pika_context_image_removed (PikaContainer *container,
PikaImage *image,
PikaContext *context)
{
if (context->image == image)
pika_context_real_set_image (context, NULL);
}
static void
pika_context_real_set_image (PikaContext *context,
PikaImage *image)
{
if (context->image == image)
return;
context->image = image;
g_object_notify (G_OBJECT (context), "image");
pika_context_image_changed (context);
}
/*****************************************************************************/
/* display *****************************************************************/
PikaDisplay *
pika_context_get_display (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->display;
}
void
pika_context_set_display (PikaContext *context,
PikaDisplay *display)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (display == NULL || PIKA_IS_DISPLAY (display));
context_find_defined (context, PIKA_CONTEXT_PROP_DISPLAY);
pika_context_real_set_display (context, display);
}
void
pika_context_display_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[DISPLAY_CHANGED], 0,
context->display);
}
static void
pika_context_display_removed (PikaContainer *container,
PikaDisplay *display,
PikaContext *context)
{
if (context->display == display)
pika_context_real_set_display (context, NULL);
}
static void
pika_context_real_set_display (PikaContext *context,
PikaDisplay *display)
{
PikaDisplay *old_display;
if (context->display == display)
{
/* make sure that setting a display *always* sets the image
* to that display's image, even if the display already
* matches
*/
if (display)
{
PikaImage *image;
g_object_get (display, "image", &image, NULL);
pika_context_real_set_image (context, image);
if (image)
g_object_unref (image);
}
return;
}
old_display = context->display;
context->display = display;
if (context->display)
{
PikaImage *image;
g_object_get (display, "image", &image, NULL);
pika_context_real_set_image (context, image);
if (image)
g_object_unref (image);
}
else if (old_display)
{
pika_context_real_set_image (context, NULL);
}
g_object_notify (G_OBJECT (context), "display");
pika_context_display_changed (context);
}
/*****************************************************************************/
/* tool ********************************************************************/
PikaToolInfo *
pika_context_get_tool (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->tool_info;
}
void
pika_context_set_tool (PikaContext *context,
PikaToolInfo *tool_info)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (tool_info == NULL || PIKA_IS_TOOL_INFO (tool_info));
context_find_defined (context, PIKA_CONTEXT_PROP_TOOL);
pika_context_real_set_tool (context, tool_info);
}
void
pika_context_tool_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[TOOL_CHANGED], 0,
context->tool_info);
}
static void
pika_context_tool_dirty (PikaToolInfo *tool_info,
PikaContext *context)
{
g_free (context->tool_name);
context->tool_name = g_strdup (pika_object_get_name (tool_info));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_TOOL);
}
static void
pika_context_tool_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaToolInfo *tool_info;
if (! context->tool_name)
context->tool_name = g_strdup ("pika-paintbrush-tool");
tool_info = pika_context_find_object (context, container,
context->tool_name,
pika_tool_info_get_standard (context->pika));
pika_context_real_set_tool (context, tool_info);
}
static void
pika_context_tool_removed (PikaContainer *container,
PikaToolInfo *tool_info,
PikaContext *context)
{
if (tool_info == context->tool_info)
{
g_signal_handlers_disconnect_by_func (context->tool_info,
pika_context_tool_dirty,
context);
g_clear_object (&context->tool_info);
if (! pika_container_frozen (container))
pika_context_tool_list_thaw (container, context);
}
}
static void
pika_context_real_set_tool (PikaContext *context,
PikaToolInfo *tool_info)
{
if (context->tool_info == tool_info)
return;
if (context->tool_name &&
tool_info != pika_tool_info_get_standard (context->pika))
{
g_clear_pointer (&context->tool_name, g_free);
}
if (context->tool_info)
g_signal_handlers_disconnect_by_func (context->tool_info,
pika_context_tool_dirty,
context);
g_set_object (&context->tool_info, tool_info);
if (tool_info)
{
g_signal_connect_object (tool_info, "name-changed",
G_CALLBACK (pika_context_tool_dirty),
context,
0);
if (tool_info != pika_tool_info_get_standard (context->pika))
context->tool_name = g_strdup (pika_object_get_name (tool_info));
if (tool_info->paint_info)
pika_context_real_set_paint_info (context, tool_info->paint_info);
}
g_object_notify (G_OBJECT (context), "tool");
pika_context_tool_changed (context);
}
/*****************************************************************************/
/* paint info **************************************************************/
PikaPaintInfo *
pika_context_get_paint_info (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->paint_info;
}
void
pika_context_set_paint_info (PikaContext *context,
PikaPaintInfo *paint_info)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (paint_info == NULL || PIKA_IS_PAINT_INFO (paint_info));
context_find_defined (context, PIKA_CONTEXT_PROP_PAINT_INFO);
pika_context_real_set_paint_info (context, paint_info);
}
void
pika_context_paint_info_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[PAINT_INFO_CHANGED], 0,
context->paint_info);
}
static void
pika_context_paint_info_dirty (PikaPaintInfo *paint_info,
PikaContext *context)
{
g_free (context->paint_name);
context->paint_name = g_strdup (pika_object_get_name (paint_info));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_PAINT_INFO);
}
/* the global paint info list is there again after refresh */
static void
pika_context_paint_info_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaPaintInfo *paint_info;
if (! context->paint_name)
context->paint_name = g_strdup ("pika-paintbrush");
paint_info = pika_context_find_object (context, container,
context->paint_name,
pika_paint_info_get_standard (context->pika));
pika_context_real_set_paint_info (context, paint_info);
}
static void
pika_context_paint_info_removed (PikaContainer *container,
PikaPaintInfo *paint_info,
PikaContext *context)
{
if (paint_info == context->paint_info)
{
g_signal_handlers_disconnect_by_func (context->paint_info,
pika_context_paint_info_dirty,
context);
g_clear_object (&context->paint_info);
if (! pika_container_frozen (container))
pika_context_paint_info_list_thaw (container, context);
}
}
static void
pika_context_real_set_paint_info (PikaContext *context,
PikaPaintInfo *paint_info)
{
if (context->paint_info == paint_info)
return;
if (context->paint_name &&
paint_info != pika_paint_info_get_standard (context->pika))
{
g_clear_pointer (&context->paint_name, g_free);
}
if (context->paint_info)
g_signal_handlers_disconnect_by_func (context->paint_info,
pika_context_paint_info_dirty,
context);
g_set_object (&context->paint_info, paint_info);
if (paint_info)
{
g_signal_connect_object (paint_info, "name-changed",
G_CALLBACK (pika_context_paint_info_dirty),
context,
0);
if (paint_info != pika_paint_info_get_standard (context->pika))
context->paint_name = g_strdup (pika_object_get_name (paint_info));
}
g_object_notify (G_OBJECT (context), "paint-info");
pika_context_paint_info_changed (context);
}
/*****************************************************************************/
/* foreground color ********************************************************/
void
pika_context_get_foreground (PikaContext *context,
PikaRGB *color)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (color != NULL);
*color = context->foreground;
}
void
pika_context_set_foreground (PikaContext *context,
const PikaRGB *color)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (color != NULL);
context_find_defined (context, PIKA_CONTEXT_PROP_FOREGROUND);
pika_context_real_set_foreground (context, color);
}
void
pika_context_foreground_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[FOREGROUND_CHANGED], 0,
&context->foreground);
}
static void
pika_context_real_set_foreground (PikaContext *context,
const PikaRGB *color)
{
if (pika_rgba_distance (&context->foreground, color) < RGBA_EPSILON)
return;
context->foreground = *color;
pika_rgb_set_alpha (&context->foreground, PIKA_OPACITY_OPAQUE);
g_object_notify (G_OBJECT (context), "foreground");
pika_context_foreground_changed (context);
}
/*****************************************************************************/
/* background color ********************************************************/
void
pika_context_get_background (PikaContext *context,
PikaRGB *color)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (color != NULL);
*color = context->background;
}
void
pika_context_set_background (PikaContext *context,
const PikaRGB *color)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (color != NULL);
context_find_defined (context, PIKA_CONTEXT_PROP_BACKGROUND);
pika_context_real_set_background (context, color);
}
void
pika_context_background_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[BACKGROUND_CHANGED], 0,
&context->background);
}
static void
pika_context_real_set_background (PikaContext *context,
const PikaRGB *color)
{
if (pika_rgba_distance (&context->background, color) < RGBA_EPSILON)
return;
context->background = *color;
pika_rgb_set_alpha (&context->background, PIKA_OPACITY_OPAQUE);
g_object_notify (G_OBJECT (context), "background");
pika_context_background_changed (context);
}
/*****************************************************************************/
/* color utility functions *************************************************/
void
pika_context_set_default_colors (PikaContext *context)
{
PikaContext *bg_context;
PikaRGB fg;
PikaRGB bg;
g_return_if_fail (PIKA_IS_CONTEXT (context));
bg_context = context;
context_find_defined (context, PIKA_CONTEXT_PROP_FOREGROUND);
context_find_defined (bg_context, PIKA_CONTEXT_PROP_BACKGROUND);
pika_rgba_set (&fg, 0.0, 0.0, 0.0, PIKA_OPACITY_OPAQUE);
pika_rgba_set (&bg, 1.0, 1.0, 1.0, PIKA_OPACITY_OPAQUE);
pika_context_real_set_foreground (context, &fg);
pika_context_real_set_background (bg_context, &bg);
}
void
pika_context_swap_colors (PikaContext *context)
{
PikaContext *bg_context;
PikaRGB fg;
PikaRGB bg;
g_return_if_fail (PIKA_IS_CONTEXT (context));
bg_context = context;
context_find_defined (context, PIKA_CONTEXT_PROP_FOREGROUND);
context_find_defined (bg_context, PIKA_CONTEXT_PROP_BACKGROUND);
pika_context_get_foreground (context, &fg);
pika_context_get_background (bg_context, &bg);
pika_context_real_set_foreground (context, &bg);
pika_context_real_set_background (bg_context, &fg);
}
/*****************************************************************************/
/* opacity *****************************************************************/
gdouble
pika_context_get_opacity (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), PIKA_OPACITY_OPAQUE);
return context->opacity;
}
void
pika_context_set_opacity (PikaContext *context,
gdouble opacity)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
context_find_defined (context, PIKA_CONTEXT_PROP_OPACITY);
pika_context_real_set_opacity (context, opacity);
}
void
pika_context_opacity_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[OPACITY_CHANGED], 0,
context->opacity);
}
static void
pika_context_real_set_opacity (PikaContext *context,
gdouble opacity)
{
if (context->opacity == opacity)
return;
context->opacity = opacity;
g_object_notify (G_OBJECT (context), "opacity");
pika_context_opacity_changed (context);
}
/*****************************************************************************/
/* paint mode **************************************************************/
PikaLayerMode
pika_context_get_paint_mode (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), PIKA_LAYER_MODE_NORMAL);
return context->paint_mode;
}
void
pika_context_set_paint_mode (PikaContext *context,
PikaLayerMode paint_mode)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
context_find_defined (context, PIKA_CONTEXT_PROP_PAINT_MODE);
pika_context_real_set_paint_mode (context, paint_mode);
}
void
pika_context_paint_mode_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[PAINT_MODE_CHANGED], 0,
context->paint_mode);
}
static void
pika_context_real_set_paint_mode (PikaContext *context,
PikaLayerMode paint_mode)
{
if (context->paint_mode == paint_mode)
return;
context->paint_mode = paint_mode;
g_object_notify (G_OBJECT (context), "paint-mode");
pika_context_paint_mode_changed (context);
}
/*****************************************************************************/
/* brush *******************************************************************/
PikaBrush *
pika_context_get_brush (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->brush;
}
void
pika_context_set_brush (PikaContext *context,
PikaBrush *brush)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (brush == NULL || PIKA_IS_BRUSH (brush));
context_find_defined (context, PIKA_CONTEXT_PROP_BRUSH);
pika_context_real_set_brush (context, brush);
}
void
pika_context_brush_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[BRUSH_CHANGED], 0,
context->brush);
}
static void
pika_context_brush_dirty (PikaBrush *brush,
PikaContext *context)
{
g_free (context->brush_name);
context->brush_name = g_strdup (pika_object_get_name (brush));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_BRUSH);
}
static void
pika_context_brush_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaBrush *brush;
if (! context->brush_name)
context->brush_name = g_strdup (context->pika->config->default_brush);
brush = pika_context_find_object (context, container,
context->brush_name,
pika_brush_get_standard (context));
pika_context_real_set_brush (context, brush);
}
/* the active brush disappeared */
static void
pika_context_brush_removed (PikaContainer *container,
PikaBrush *brush,
PikaContext *context)
{
if (brush == context->brush)
{
g_signal_handlers_disconnect_by_func (context->brush,
pika_context_brush_dirty,
context);
g_clear_object (&context->brush);
if (! pika_container_frozen (container))
pika_context_brush_list_thaw (container, context);
}
}
static void
pika_context_real_set_brush (PikaContext *context,
PikaBrush *brush)
{
if (context->brush == brush)
return;
if (context->brush_name &&
brush != PIKA_BRUSH (pika_brush_get_standard (context)))
{
g_clear_pointer (&context->brush_name, g_free);
}
if (context->brush)
g_signal_handlers_disconnect_by_func (context->brush,
pika_context_brush_dirty,
context);
g_set_object (&context->brush, brush);
if (brush)
{
g_signal_connect_object (brush, "name-changed",
G_CALLBACK (pika_context_brush_dirty),
context,
0);
if (brush != PIKA_BRUSH (pika_brush_get_standard (context)))
context->brush_name = g_strdup (pika_object_get_name (brush));
}
g_object_notify (G_OBJECT (context), "brush");
pika_context_brush_changed (context);
}
/*****************************************************************************/
/* dynamics *****************************************************************/
PikaDynamics *
pika_context_get_dynamics (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->dynamics;
}
void
pika_context_set_dynamics (PikaContext *context,
PikaDynamics *dynamics)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (dynamics == NULL || PIKA_IS_DYNAMICS (dynamics));
context_find_defined (context, PIKA_CONTEXT_PROP_DYNAMICS);
pika_context_real_set_dynamics (context, dynamics);
}
void
pika_context_dynamics_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[DYNAMICS_CHANGED], 0,
context->dynamics);
}
static void
pika_context_dynamics_dirty (PikaDynamics *dynamics,
PikaContext *context)
{
g_free (context->dynamics_name);
context->dynamics_name = g_strdup (pika_object_get_name (dynamics));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_DYNAMICS);
}
static void
pika_context_dynamics_removed (PikaContainer *container,
PikaDynamics *dynamics,
PikaContext *context)
{
if (dynamics == context->dynamics)
{
g_signal_handlers_disconnect_by_func (context->dynamics,
pika_context_dynamics_dirty,
context);
g_clear_object (&context->dynamics);
if (! pika_container_frozen (container))
pika_context_dynamics_list_thaw (container, context);
}
}
static void
pika_context_dynamics_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaDynamics *dynamics;
if (! context->dynamics_name)
context->dynamics_name = g_strdup (context->pika->config->default_dynamics);
dynamics = pika_context_find_object (context, container,
context->dynamics_name,
pika_dynamics_get_standard (context));
pika_context_real_set_dynamics (context, dynamics);
}
static void
pika_context_real_set_dynamics (PikaContext *context,
PikaDynamics *dynamics)
{
if (context->dynamics == dynamics)
return;
if (context->dynamics_name &&
dynamics != PIKA_DYNAMICS (pika_dynamics_get_standard (context)))
{
g_clear_pointer (&context->dynamics_name, g_free);
}
if (context->dynamics)
g_signal_handlers_disconnect_by_func (context->dynamics,
pika_context_dynamics_dirty,
context);
g_set_object (&context->dynamics, dynamics);
if (dynamics)
{
g_signal_connect_object (dynamics, "name-changed",
G_CALLBACK (pika_context_dynamics_dirty),
context,
0);
if (dynamics != PIKA_DYNAMICS (pika_dynamics_get_standard (context)))
context->dynamics_name = g_strdup (pika_object_get_name (dynamics));
}
g_object_notify (G_OBJECT (context), "dynamics");
pika_context_dynamics_changed (context);
}
/*****************************************************************************/
/* mybrush *****************************************************************/
PikaMybrush *
pika_context_get_mybrush (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->mybrush;
}
void
pika_context_set_mybrush (PikaContext *context,
PikaMybrush *brush)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (brush == NULL || PIKA_IS_MYBRUSH (brush));
context_find_defined (context, PIKA_CONTEXT_PROP_MYBRUSH);
pika_context_real_set_mybrush (context, brush);
}
void
pika_context_mybrush_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[MYBRUSH_CHANGED], 0,
context->mybrush);
}
static void
pika_context_mybrush_dirty (PikaMybrush *brush,
PikaContext *context)
{
g_free (context->mybrush_name);
context->mybrush_name = g_strdup (pika_object_get_name (brush));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_MYBRUSH);
}
static void
pika_context_mybrush_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaMybrush *brush;
if (! context->mybrush_name)
context->mybrush_name = g_strdup (context->pika->config->default_mypaint_brush);
brush = pika_context_find_object (context, container,
context->mybrush_name,
pika_mybrush_get_standard (context));
pika_context_real_set_mybrush (context, brush);
}
static void
pika_context_mybrush_removed (PikaContainer *container,
PikaMybrush *brush,
PikaContext *context)
{
if (brush == context->mybrush)
{
g_signal_handlers_disconnect_by_func (context->mybrush,
pika_context_mybrush_dirty,
context);
g_clear_object (&context->mybrush);
if (! pika_container_frozen (container))
pika_context_mybrush_list_thaw (container, context);
}
}
static void
pika_context_real_set_mybrush (PikaContext *context,
PikaMybrush *brush)
{
if (context->mybrush == brush)
return;
if (context->mybrush_name &&
brush != PIKA_MYBRUSH (pika_mybrush_get_standard (context)))
{
g_clear_pointer (&context->mybrush_name, g_free);
}
if (context->mybrush)
g_signal_handlers_disconnect_by_func (context->mybrush,
pika_context_mybrush_dirty,
context);
g_set_object (&context->mybrush, brush);
if (brush)
{
g_signal_connect_object (brush, "name-changed",
G_CALLBACK (pika_context_mybrush_dirty),
context,
0);
if (brush != PIKA_MYBRUSH (pika_mybrush_get_standard (context)))
context->mybrush_name = g_strdup (pika_object_get_name (brush));
}
g_object_notify (G_OBJECT (context), "mybrush");
pika_context_mybrush_changed (context);
}
/*****************************************************************************/
/* pattern *****************************************************************/
PikaPattern *
pika_context_get_pattern (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->pattern;
}
void
pika_context_set_pattern (PikaContext *context,
PikaPattern *pattern)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (pattern == NULL || PIKA_IS_PATTERN (pattern));
context_find_defined (context, PIKA_CONTEXT_PROP_PATTERN);
pika_context_real_set_pattern (context, pattern);
}
void
pika_context_pattern_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[PATTERN_CHANGED], 0,
context->pattern);
}
static void
pika_context_pattern_dirty (PikaPattern *pattern,
PikaContext *context)
{
g_free (context->pattern_name);
context->pattern_name = g_strdup (pika_object_get_name (pattern));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_PATTERN);
}
static void
pika_context_pattern_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaPattern *pattern;
if (! context->pattern_name)
context->pattern_name = g_strdup (context->pika->config->default_pattern);
pattern = pika_context_find_object (context, container,
context->pattern_name,
pika_pattern_get_standard (context));
pika_context_real_set_pattern (context, pattern);
}
static void
pika_context_pattern_removed (PikaContainer *container,
PikaPattern *pattern,
PikaContext *context)
{
if (pattern == context->pattern)
{
g_signal_handlers_disconnect_by_func (context->pattern,
pika_context_pattern_dirty,
context);
g_clear_object (&context->pattern);
if (! pika_container_frozen (container))
pika_context_pattern_list_thaw (container, context);
}
}
static void
pika_context_real_set_pattern (PikaContext *context,
PikaPattern *pattern)
{
if (context->pattern == pattern)
return;
if (context->pattern_name &&
pattern != PIKA_PATTERN (pika_pattern_get_standard (context)))
{
g_clear_pointer (&context->pattern_name, g_free);
}
if (context->pattern)
g_signal_handlers_disconnect_by_func (context->pattern,
pika_context_pattern_dirty,
context);
g_set_object (&context->pattern, pattern);
if (pattern)
{
g_signal_connect_object (pattern, "name-changed",
G_CALLBACK (pika_context_pattern_dirty),
context,
0);
if (pattern != PIKA_PATTERN (pika_pattern_get_standard (context)))
context->pattern_name = g_strdup (pika_object_get_name (pattern));
}
g_object_notify (G_OBJECT (context), "pattern");
pika_context_pattern_changed (context);
}
/*****************************************************************************/
/* gradient ****************************************************************/
PikaGradient *
pika_context_get_gradient (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->gradient;
}
void
pika_context_set_gradient (PikaContext *context,
PikaGradient *gradient)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (gradient == NULL || PIKA_IS_GRADIENT (gradient));
context_find_defined (context, PIKA_CONTEXT_PROP_GRADIENT);
pika_context_real_set_gradient (context, gradient);
}
void
pika_context_gradient_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[GRADIENT_CHANGED], 0,
context->gradient);
}
static void
pika_context_gradient_dirty (PikaGradient *gradient,
PikaContext *context)
{
g_free (context->gradient_name);
context->gradient_name = g_strdup (pika_object_get_name (gradient));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_GRADIENT);
}
static void
pika_context_gradient_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaGradient *gradient;
if (! context->gradient_name)
context->gradient_name = g_strdup (context->pika->config->default_gradient);
gradient = pika_context_find_object (context, container,
context->gradient_name,
pika_gradient_get_standard (context));
pika_context_real_set_gradient (context, gradient);
}
static void
pika_context_gradient_removed (PikaContainer *container,
PikaGradient *gradient,
PikaContext *context)
{
if (gradient == context->gradient)
{
g_signal_handlers_disconnect_by_func (context->gradient,
pika_context_gradient_dirty,
context);
g_clear_object (&context->gradient);
if (! pika_container_frozen (container))
pika_context_gradient_list_thaw (container, context);
}
}
static void
pika_context_real_set_gradient (PikaContext *context,
PikaGradient *gradient)
{
if (context->gradient == gradient)
return;
if (context->gradient_name &&
gradient != PIKA_GRADIENT (pika_gradient_get_standard (context)))
{
g_clear_pointer (&context->gradient_name, g_free);
}
if (context->gradient)
g_signal_handlers_disconnect_by_func (context->gradient,
pika_context_gradient_dirty,
context);
g_set_object (&context->gradient, gradient);
if (gradient)
{
g_signal_connect_object (gradient, "name-changed",
G_CALLBACK (pika_context_gradient_dirty),
context,
0);
if (gradient != PIKA_GRADIENT (pika_gradient_get_standard (context)))
context->gradient_name = g_strdup (pika_object_get_name (gradient));
}
g_object_notify (G_OBJECT (context), "gradient");
pika_context_gradient_changed (context);
}
/*****************************************************************************/
/* palette *****************************************************************/
PikaPalette *
pika_context_get_palette (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->palette;
}
void
pika_context_set_palette (PikaContext *context,
PikaPalette *palette)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (palette == NULL || PIKA_IS_PALETTE (palette));
context_find_defined (context, PIKA_CONTEXT_PROP_PALETTE);
pika_context_real_set_palette (context, palette);
}
void
pika_context_palette_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[PALETTE_CHANGED], 0,
context->palette);
}
static void
pika_context_palette_dirty (PikaPalette *palette,
PikaContext *context)
{
g_free (context->palette_name);
context->palette_name = g_strdup (pika_object_get_name (palette));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_PALETTE);
}
static void
pika_context_palette_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaPalette *palette;
if (! context->palette_name)
context->palette_name = g_strdup (context->pika->config->default_palette);
palette = pika_context_find_object (context, container,
context->palette_name,
pika_palette_get_standard (context));
pika_context_real_set_palette (context, palette);
}
static void
pika_context_palette_removed (PikaContainer *container,
PikaPalette *palette,
PikaContext *context)
{
if (palette == context->palette)
{
g_signal_handlers_disconnect_by_func (context->palette,
pika_context_palette_dirty,
context);
g_clear_object (&context->palette);
if (! pika_container_frozen (container))
pika_context_palette_list_thaw (container, context);
}
}
static void
pika_context_real_set_palette (PikaContext *context,
PikaPalette *palette)
{
if (context->palette == palette)
return;
if (context->palette_name &&
palette != PIKA_PALETTE (pika_palette_get_standard (context)))
{
g_clear_pointer (&context->palette_name, g_free);
}
if (context->palette)
g_signal_handlers_disconnect_by_func (context->palette,
pika_context_palette_dirty,
context);
g_set_object (&context->palette, palette);
if (palette)
{
g_signal_connect_object (palette, "name-changed",
G_CALLBACK (pika_context_palette_dirty),
context,
0);
if (palette != PIKA_PALETTE (pika_palette_get_standard (context)))
context->palette_name = g_strdup (pika_object_get_name (palette));
}
g_object_notify (G_OBJECT (context), "palette");
pika_context_palette_changed (context);
}
/*****************************************************************************/
/* font *****************************************************************/
PikaFont *
pika_context_get_font (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->font;
}
void
pika_context_set_font (PikaContext *context,
PikaFont *font)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (font == NULL || PIKA_IS_FONT (font));
context_find_defined (context, PIKA_CONTEXT_PROP_FONT);
pika_context_real_set_font (context, font);
}
const gchar *
pika_context_get_font_name (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->font_name;
}
void
pika_context_set_font_name (PikaContext *context,
const gchar *name)
{
PikaContainer *container;
PikaObject *font;
g_return_if_fail (PIKA_IS_CONTEXT (context));
container = pika_data_factory_get_container (context->pika->font_factory);
font = pika_container_search (container,
(PikaContainerSearchFunc) pika_font_match_by_lookup_name,
(gpointer) name);
if (font)
{
pika_context_set_font (context, PIKA_FONT (font));
}
else
{
/* No font with this name exists, use the standard font, but
* keep the intended name around
*/
pika_context_set_font (context, PIKA_FONT (pika_font_get_standard ()));
g_free (context->font_name);
context->font_name = g_strdup (name);
}
}
void
pika_context_font_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[FONT_CHANGED], 0,
context->font);
}
static void
pika_context_font_dirty (PikaFont *font,
PikaContext *context)
{
g_free (context->font_name);
context->font_name = g_strdup (pika_object_get_name (font));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_FONT);
}
static void
pika_context_font_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaFont *font;
if (! context->font_name)
context->font_name = g_strdup (context->pika->config->default_font);
font = pika_context_find_object (context, container,
context->font_name,
pika_font_get_standard ());
pika_context_real_set_font (context, font);
}
static void
pika_context_font_removed (PikaContainer *container,
PikaFont *font,
PikaContext *context)
{
if (font == context->font)
{
g_signal_handlers_disconnect_by_func (context->font,
pika_context_font_dirty,
context);
g_clear_object (&context->font);
if (! pika_container_frozen (container))
pika_context_font_list_thaw (container, context);
}
}
static void
pika_context_real_set_font (PikaContext *context,
PikaFont *font)
{
if (context->font == font)
return;
if (context->font_name &&
font != PIKA_FONT (pika_font_get_standard ()))
{
g_clear_pointer (&context->font_name, g_free);
}
if (context->font)
g_signal_handlers_disconnect_by_func (context->font,
pika_context_font_dirty,
context);
g_set_object (&context->font, font);
if (font)
{
g_signal_connect_object (font, "name-changed",
G_CALLBACK (pika_context_font_dirty),
context,
0);
if (font != PIKA_FONT (pika_font_get_standard ()))
context->font_name = g_strdup (pika_font_get_lookup_name (font));
}
g_object_notify (G_OBJECT (context), "font");
pika_context_font_changed (context);
}
/********************************************************************************/
/* tool preset *****************************************************************/
PikaToolPreset *
pika_context_get_tool_preset (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->tool_preset;
}
void
pika_context_set_tool_preset (PikaContext *context,
PikaToolPreset *tool_preset)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (tool_preset == NULL || PIKA_IS_TOOL_PRESET (tool_preset));
context_find_defined (context, PIKA_CONTEXT_PROP_TOOL_PRESET);
pika_context_real_set_tool_preset (context, tool_preset);
}
void
pika_context_tool_preset_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[TOOL_PRESET_CHANGED], 0,
context->tool_preset);
}
static void
pika_context_tool_preset_dirty (PikaToolPreset *tool_preset,
PikaContext *context)
{
g_free (context->tool_preset_name);
context->tool_preset_name = g_strdup (pika_object_get_name (tool_preset));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_TOOL_PRESET);
}
static void
pika_context_tool_preset_removed (PikaContainer *container,
PikaToolPreset *tool_preset,
PikaContext *context)
{
if (tool_preset == context->tool_preset)
{
g_signal_handlers_disconnect_by_func (context->tool_preset,
pika_context_tool_preset_dirty,
context);
g_clear_object (&context->tool_preset);
if (! pika_container_frozen (container))
pika_context_tool_preset_list_thaw (container, context);
}
}
static void
pika_context_tool_preset_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaToolPreset *tool_preset;
tool_preset = pika_context_find_object (context, container,
context->tool_preset_name,
NULL);
pika_context_real_set_tool_preset (context, tool_preset);
}
static void
pika_context_real_set_tool_preset (PikaContext *context,
PikaToolPreset *tool_preset)
{
if (context->tool_preset == tool_preset)
return;
if (context->tool_preset_name)
{
g_clear_pointer (&context->tool_preset_name, g_free);
}
if (context->tool_preset)
g_signal_handlers_disconnect_by_func (context->tool_preset,
pika_context_tool_preset_dirty,
context);
g_set_object (&context->tool_preset, tool_preset);
if (tool_preset)
{
g_signal_connect_object (tool_preset, "name-changed",
G_CALLBACK (pika_context_tool_preset_dirty),
context,
0);
context->tool_preset_name = g_strdup (pika_object_get_name (tool_preset));
}
g_object_notify (G_OBJECT (context), "tool-preset");
pika_context_tool_preset_changed (context);
}
/*****************************************************************************/
/* buffer ******************************************************************/
PikaBuffer *
pika_context_get_buffer (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->buffer;
}
void
pika_context_set_buffer (PikaContext *context,
PikaBuffer *buffer)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (buffer == NULL || PIKA_IS_BUFFER (buffer));
context_find_defined (context, PIKA_CONTEXT_PROP_BUFFER);
pika_context_real_set_buffer (context, buffer);
}
void
pika_context_buffer_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[BUFFER_CHANGED], 0,
context->buffer);
}
static void
pika_context_buffer_dirty (PikaBuffer *buffer,
PikaContext *context)
{
g_free (context->buffer_name);
context->buffer_name = g_strdup (pika_object_get_name (buffer));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_BUFFER);
}
static void
pika_context_buffer_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaBuffer *buffer;
buffer = pika_context_find_object (context, container,
context->buffer_name,
NULL);
if (buffer)
{
pika_context_real_set_buffer (context, buffer);
}
else
{
g_object_notify (G_OBJECT (context), "buffer");
pika_context_buffer_changed (context);
}
}
static void
pika_context_buffer_removed (PikaContainer *container,
PikaBuffer *buffer,
PikaContext *context)
{
if (buffer == context->buffer)
{
g_signal_handlers_disconnect_by_func (context->buffer,
pika_context_buffer_dirty,
context);
g_clear_object (&context->buffer);
if (! pika_container_frozen (container))
pika_context_buffer_list_thaw (container, context);
}
}
static void
pika_context_real_set_buffer (PikaContext *context,
PikaBuffer *buffer)
{
if (context->buffer == buffer)
return;
if (context->buffer_name)
{
g_clear_pointer (&context->buffer_name, g_free);
}
if (context->buffer)
g_signal_handlers_disconnect_by_func (context->buffer,
pika_context_buffer_dirty,
context);
g_set_object (&context->buffer, buffer);
if (buffer)
{
g_signal_connect_object (buffer, "name-changed",
G_CALLBACK (pika_context_buffer_dirty),
context,
0);
context->buffer_name = g_strdup (pika_object_get_name (buffer));
}
g_object_notify (G_OBJECT (context), "buffer");
pika_context_buffer_changed (context);
}
/*****************************************************************************/
/* imagefile ***************************************************************/
PikaImagefile *
pika_context_get_imagefile (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->imagefile;
}
void
pika_context_set_imagefile (PikaContext *context,
PikaImagefile *imagefile)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (imagefile == NULL || PIKA_IS_IMAGEFILE (imagefile));
context_find_defined (context, PIKA_CONTEXT_PROP_IMAGEFILE);
pika_context_real_set_imagefile (context, imagefile);
}
void
pika_context_imagefile_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[IMAGEFILE_CHANGED], 0,
context->imagefile);
}
static void
pika_context_imagefile_dirty (PikaImagefile *imagefile,
PikaContext *context)
{
g_free (context->imagefile_name);
context->imagefile_name = g_strdup (pika_object_get_name (imagefile));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_IMAGEFILE);
}
static void
pika_context_imagefile_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaImagefile *imagefile;
imagefile = pika_context_find_object (context, container,
context->imagefile_name,
NULL);
if (imagefile)
{
pika_context_real_set_imagefile (context, imagefile);
}
else
{
g_object_notify (G_OBJECT (context), "imagefile");
pika_context_imagefile_changed (context);
}
}
static void
pika_context_imagefile_removed (PikaContainer *container,
PikaImagefile *imagefile,
PikaContext *context)
{
if (imagefile == context->imagefile)
{
g_signal_handlers_disconnect_by_func (context->imagefile,
pika_context_imagefile_dirty,
context);
g_clear_object (&context->imagefile);
if (! pika_container_frozen (container))
pika_context_imagefile_list_thaw (container, context);
}
}
static void
pika_context_real_set_imagefile (PikaContext *context,
PikaImagefile *imagefile)
{
if (context->imagefile == imagefile)
return;
if (context->imagefile_name)
{
g_clear_pointer (&context->imagefile_name, g_free);
}
if (context->imagefile)
g_signal_handlers_disconnect_by_func (context->imagefile,
pika_context_imagefile_dirty,
context);
g_set_object (&context->imagefile, imagefile);
if (imagefile)
{
g_signal_connect_object (imagefile, "name-changed",
G_CALLBACK (pika_context_imagefile_dirty),
context,
0);
context->imagefile_name = g_strdup (pika_object_get_name (imagefile));
}
g_object_notify (G_OBJECT (context), "imagefile");
pika_context_imagefile_changed (context);
}
/*****************************************************************************/
/* template ***************************************************************/
PikaTemplate *
pika_context_get_template (PikaContext *context)
{
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
return context->template;
}
void
pika_context_set_template (PikaContext *context,
PikaTemplate *template)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (template == NULL || PIKA_IS_TEMPLATE (template));
context_find_defined (context, PIKA_CONTEXT_PROP_TEMPLATE);
pika_context_real_set_template (context, template);
}
void
pika_context_template_changed (PikaContext *context)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_signal_emit (context,
pika_context_signals[TEMPLATE_CHANGED], 0,
context->template);
}
static void
pika_context_template_dirty (PikaTemplate *template,
PikaContext *context)
{
g_free (context->template_name);
context->template_name = g_strdup (pika_object_get_name (template));
g_signal_emit (context, pika_context_signals[PROP_NAME_CHANGED], 0,
PIKA_CONTEXT_PROP_TEMPLATE);
}
static void
pika_context_template_list_thaw (PikaContainer *container,
PikaContext *context)
{
PikaTemplate *template;
template = pika_context_find_object (context, container,
context->template_name,
NULL);
if (template)
{
pika_context_real_set_template (context, template);
}
else
{
g_object_notify (G_OBJECT (context), "template");
pika_context_template_changed (context);
}
}
static void
pika_context_template_removed (PikaContainer *container,
PikaTemplate *template,
PikaContext *context)
{
if (template == context->template)
{
g_signal_handlers_disconnect_by_func (context->template,
pika_context_template_dirty,
context);
g_clear_object (&context->template);
if (! pika_container_frozen (container))
pika_context_template_list_thaw (container, context);
}
}
static void
pika_context_real_set_template (PikaContext *context,
PikaTemplate *template)
{
if (context->template == template)
return;
if (context->template_name)
{
g_clear_pointer (&context->template_name, g_free);
}
if (context->template)
g_signal_handlers_disconnect_by_func (context->template,
pika_context_template_dirty,
context);
g_set_object (&context->template, template);
if (template)
{
g_signal_connect_object (template, "name-changed",
G_CALLBACK (pika_context_template_dirty),
context,
0);
context->template_name = g_strdup (pika_object_get_name (template));
}
g_object_notify (G_OBJECT (context), "template");
pika_context_template_changed (context);
}
/*****************************************************************************/
/* Line Art ****************************************************************/
PikaLineArt *
pika_context_take_line_art (PikaContext *context)
{
PikaLineArt *line_art;
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
if (context->line_art)
{
g_source_remove (context->line_art_timeout_id);
context->line_art_timeout_id = 0;
line_art = context->line_art;
context->line_art = NULL;
}
else
{
line_art = pika_line_art_new ();
}
return line_art;
}
/*
* pika_context_store_line_art:
* @context:
* @line_art:
*
* The @context takes ownership of @line_art until the next time it is
* requested with pika_context_take_line_art() or until 3 minutes have
* passed.
* This function allows to temporarily store the computed line art data
* in case it is needed very soon again, so that not to free and
* recompute all the time the data when quickly switching tools.
*/
void
pika_context_store_line_art (PikaContext *context,
PikaLineArt *line_art)
{
g_return_if_fail (PIKA_IS_CONTEXT (context));
g_return_if_fail (PIKA_IS_LINE_ART (line_art));
if (context->line_art)
{
g_source_remove (context->line_art_timeout_id);
context->line_art_timeout_id = 0;
}
context->line_art = line_art;
context->line_art_timeout_id = g_timeout_add (180000,
(GSourceFunc) pika_context_free_line_art,
context);
}
static gboolean
pika_context_free_line_art (PikaContext *context)
{
g_clear_object (&context->line_art);
context->line_art_timeout_id = 0;
return G_SOURCE_REMOVE;
}
/*****************************************************************************/
/* utility functions *******************************************************/
static gpointer
pika_context_find_object (PikaContext *context,
PikaContainer *container,
const gchar *object_name,
gpointer standard_object)
{
PikaObject *object = NULL;
if (object_name)
object = pika_container_get_child_by_name (container, object_name);
if (! object && ! pika_container_is_empty (container))
object = pika_container_get_child_by_index (container, 0);
if (! object)
object = standard_object;
return object;
}