Initial checkin of Pika from heckimp
This commit is contained in:
644
app/display/display-enums.c
Normal file
644
app/display/display-enums.c
Normal file
@ -0,0 +1,644 @@
|
||||
|
||||
/* Generated data (by pika-mkenums) */
|
||||
|
||||
#include "stamp-display-enums.h"
|
||||
#include "config.h"
|
||||
#include <gio/gio.h>
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "display-enums.h"
|
||||
#include "pika-intl.h"
|
||||
|
||||
/* enumerations from "display-enums.h" */
|
||||
GType
|
||||
pika_button_press_type_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_BUTTON_PRESS_NORMAL, "PIKA_BUTTON_PRESS_NORMAL", "normal" },
|
||||
{ PIKA_BUTTON_PRESS_DOUBLE, "PIKA_BUTTON_PRESS_DOUBLE", "double" },
|
||||
{ PIKA_BUTTON_PRESS_TRIPLE, "PIKA_BUTTON_PRESS_TRIPLE", "triple" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_BUTTON_PRESS_NORMAL, "PIKA_BUTTON_PRESS_NORMAL", NULL },
|
||||
{ PIKA_BUTTON_PRESS_DOUBLE, "PIKA_BUTTON_PRESS_DOUBLE", NULL },
|
||||
{ PIKA_BUTTON_PRESS_TRIPLE, "PIKA_BUTTON_PRESS_TRIPLE", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaButtonPressType", values);
|
||||
pika_type_set_translation_context (type, "button-press-type");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_button_release_type_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_BUTTON_RELEASE_NORMAL, "PIKA_BUTTON_RELEASE_NORMAL", "normal" },
|
||||
{ PIKA_BUTTON_RELEASE_CANCEL, "PIKA_BUTTON_RELEASE_CANCEL", "cancel" },
|
||||
{ PIKA_BUTTON_RELEASE_CLICK, "PIKA_BUTTON_RELEASE_CLICK", "click" },
|
||||
{ PIKA_BUTTON_RELEASE_NO_MOTION, "PIKA_BUTTON_RELEASE_NO_MOTION", "no-motion" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_BUTTON_RELEASE_NORMAL, "PIKA_BUTTON_RELEASE_NORMAL", NULL },
|
||||
{ PIKA_BUTTON_RELEASE_CANCEL, "PIKA_BUTTON_RELEASE_CANCEL", NULL },
|
||||
{ PIKA_BUTTON_RELEASE_CLICK, "PIKA_BUTTON_RELEASE_CLICK", NULL },
|
||||
{ PIKA_BUTTON_RELEASE_NO_MOTION, "PIKA_BUTTON_RELEASE_NO_MOTION", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaButtonReleaseType", values);
|
||||
pika_type_set_translation_context (type, "button-release-type");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_compass_orientation_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_COMPASS_ORIENTATION_AUTO, "PIKA_COMPASS_ORIENTATION_AUTO", "auto" },
|
||||
{ PIKA_COMPASS_ORIENTATION_HORIZONTAL, "PIKA_COMPASS_ORIENTATION_HORIZONTAL", "horizontal" },
|
||||
{ PIKA_COMPASS_ORIENTATION_VERTICAL, "PIKA_COMPASS_ORIENTATION_VERTICAL", "vertical" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_COMPASS_ORIENTATION_AUTO, NC_("compass-orientation", "Auto"), NULL },
|
||||
{ PIKA_COMPASS_ORIENTATION_HORIZONTAL, NC_("compass-orientation", "Horizontal"), NULL },
|
||||
{ PIKA_COMPASS_ORIENTATION_VERTICAL, NC_("compass-orientation", "Vertical"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaCompassOrientation", values);
|
||||
pika_type_set_translation_context (type, "compass-orientation");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_cursor_precision_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_CURSOR_PRECISION_PIXEL_CENTER, "PIKA_CURSOR_PRECISION_PIXEL_CENTER", "pixel-center" },
|
||||
{ PIKA_CURSOR_PRECISION_PIXEL_BORDER, "PIKA_CURSOR_PRECISION_PIXEL_BORDER", "pixel-border" },
|
||||
{ PIKA_CURSOR_PRECISION_SUBPIXEL, "PIKA_CURSOR_PRECISION_SUBPIXEL", "subpixel" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_CURSOR_PRECISION_PIXEL_CENTER, "PIKA_CURSOR_PRECISION_PIXEL_CENTER", NULL },
|
||||
{ PIKA_CURSOR_PRECISION_PIXEL_BORDER, "PIKA_CURSOR_PRECISION_PIXEL_BORDER", NULL },
|
||||
{ PIKA_CURSOR_PRECISION_SUBPIXEL, "PIKA_CURSOR_PRECISION_SUBPIXEL", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaCursorPrecision", values);
|
||||
pika_type_set_translation_context (type, "cursor-precision");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_guides_type_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_GUIDES_NONE, "PIKA_GUIDES_NONE", "none" },
|
||||
{ PIKA_GUIDES_CENTER_LINES, "PIKA_GUIDES_CENTER_LINES", "center-lines" },
|
||||
{ PIKA_GUIDES_THIRDS, "PIKA_GUIDES_THIRDS", "thirds" },
|
||||
{ PIKA_GUIDES_FIFTHS, "PIKA_GUIDES_FIFTHS", "fifths" },
|
||||
{ PIKA_GUIDES_GOLDEN, "PIKA_GUIDES_GOLDEN", "golden" },
|
||||
{ PIKA_GUIDES_DIAGONALS, "PIKA_GUIDES_DIAGONALS", "diagonals" },
|
||||
{ PIKA_GUIDES_N_LINES, "PIKA_GUIDES_N_LINES", "n-lines" },
|
||||
{ PIKA_GUIDES_SPACING, "PIKA_GUIDES_SPACING", "spacing" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_GUIDES_NONE, NC_("guides-type", "No guides"), NULL },
|
||||
{ PIKA_GUIDES_CENTER_LINES, NC_("guides-type", "Center lines"), NULL },
|
||||
{ PIKA_GUIDES_THIRDS, NC_("guides-type", "Rule of thirds"), NULL },
|
||||
{ PIKA_GUIDES_FIFTHS, NC_("guides-type", "Rule of fifths"), NULL },
|
||||
{ PIKA_GUIDES_GOLDEN, NC_("guides-type", "Golden sections"), NULL },
|
||||
{ PIKA_GUIDES_DIAGONALS, NC_("guides-type", "Diagonal lines"), NULL },
|
||||
{ PIKA_GUIDES_N_LINES, NC_("guides-type", "Number of lines"), NULL },
|
||||
{ PIKA_GUIDES_SPACING, NC_("guides-type", "Line spacing"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaGuidesType", values);
|
||||
pika_type_set_translation_context (type, "guides-type");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_handle_type_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_HANDLE_SQUARE, "PIKA_HANDLE_SQUARE", "square" },
|
||||
{ PIKA_HANDLE_DASHED_SQUARE, "PIKA_HANDLE_DASHED_SQUARE", "dashed-square" },
|
||||
{ PIKA_HANDLE_FILLED_SQUARE, "PIKA_HANDLE_FILLED_SQUARE", "filled-square" },
|
||||
{ PIKA_HANDLE_CIRCLE, "PIKA_HANDLE_CIRCLE", "circle" },
|
||||
{ PIKA_HANDLE_DASHED_CIRCLE, "PIKA_HANDLE_DASHED_CIRCLE", "dashed-circle" },
|
||||
{ PIKA_HANDLE_FILLED_CIRCLE, "PIKA_HANDLE_FILLED_CIRCLE", "filled-circle" },
|
||||
{ PIKA_HANDLE_DIAMOND, "PIKA_HANDLE_DIAMOND", "diamond" },
|
||||
{ PIKA_HANDLE_DASHED_DIAMOND, "PIKA_HANDLE_DASHED_DIAMOND", "dashed-diamond" },
|
||||
{ PIKA_HANDLE_FILLED_DIAMOND, "PIKA_HANDLE_FILLED_DIAMOND", "filled-diamond" },
|
||||
{ PIKA_HANDLE_CROSS, "PIKA_HANDLE_CROSS", "cross" },
|
||||
{ PIKA_HANDLE_CROSSHAIR, "PIKA_HANDLE_CROSSHAIR", "crosshair" },
|
||||
{ PIKA_HANDLE_DROP, "PIKA_HANDLE_DROP", "drop" },
|
||||
{ PIKA_HANDLE_FILLED_DROP, "PIKA_HANDLE_FILLED_DROP", "filled-drop" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_HANDLE_SQUARE, "PIKA_HANDLE_SQUARE", NULL },
|
||||
{ PIKA_HANDLE_DASHED_SQUARE, "PIKA_HANDLE_DASHED_SQUARE", NULL },
|
||||
{ PIKA_HANDLE_FILLED_SQUARE, "PIKA_HANDLE_FILLED_SQUARE", NULL },
|
||||
{ PIKA_HANDLE_CIRCLE, "PIKA_HANDLE_CIRCLE", NULL },
|
||||
{ PIKA_HANDLE_DASHED_CIRCLE, "PIKA_HANDLE_DASHED_CIRCLE", NULL },
|
||||
{ PIKA_HANDLE_FILLED_CIRCLE, "PIKA_HANDLE_FILLED_CIRCLE", NULL },
|
||||
{ PIKA_HANDLE_DIAMOND, "PIKA_HANDLE_DIAMOND", NULL },
|
||||
{ PIKA_HANDLE_DASHED_DIAMOND, "PIKA_HANDLE_DASHED_DIAMOND", NULL },
|
||||
{ PIKA_HANDLE_FILLED_DIAMOND, "PIKA_HANDLE_FILLED_DIAMOND", NULL },
|
||||
{ PIKA_HANDLE_CROSS, "PIKA_HANDLE_CROSS", NULL },
|
||||
{ PIKA_HANDLE_CROSSHAIR, "PIKA_HANDLE_CROSSHAIR", NULL },
|
||||
{ PIKA_HANDLE_DROP, "PIKA_HANDLE_DROP", NULL },
|
||||
{ PIKA_HANDLE_FILLED_DROP, "PIKA_HANDLE_FILLED_DROP", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaHandleType", values);
|
||||
pika_type_set_translation_context (type, "handle-type");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_handle_anchor_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_HANDLE_ANCHOR_CENTER, "PIKA_HANDLE_ANCHOR_CENTER", "center" },
|
||||
{ PIKA_HANDLE_ANCHOR_NORTH, "PIKA_HANDLE_ANCHOR_NORTH", "north" },
|
||||
{ PIKA_HANDLE_ANCHOR_NORTH_WEST, "PIKA_HANDLE_ANCHOR_NORTH_WEST", "north-west" },
|
||||
{ PIKA_HANDLE_ANCHOR_NORTH_EAST, "PIKA_HANDLE_ANCHOR_NORTH_EAST", "north-east" },
|
||||
{ PIKA_HANDLE_ANCHOR_SOUTH, "PIKA_HANDLE_ANCHOR_SOUTH", "south" },
|
||||
{ PIKA_HANDLE_ANCHOR_SOUTH_WEST, "PIKA_HANDLE_ANCHOR_SOUTH_WEST", "south-west" },
|
||||
{ PIKA_HANDLE_ANCHOR_SOUTH_EAST, "PIKA_HANDLE_ANCHOR_SOUTH_EAST", "south-east" },
|
||||
{ PIKA_HANDLE_ANCHOR_WEST, "PIKA_HANDLE_ANCHOR_WEST", "west" },
|
||||
{ PIKA_HANDLE_ANCHOR_EAST, "PIKA_HANDLE_ANCHOR_EAST", "east" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_HANDLE_ANCHOR_CENTER, "PIKA_HANDLE_ANCHOR_CENTER", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_NORTH, "PIKA_HANDLE_ANCHOR_NORTH", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_NORTH_WEST, "PIKA_HANDLE_ANCHOR_NORTH_WEST", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_NORTH_EAST, "PIKA_HANDLE_ANCHOR_NORTH_EAST", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_SOUTH, "PIKA_HANDLE_ANCHOR_SOUTH", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_SOUTH_WEST, "PIKA_HANDLE_ANCHOR_SOUTH_WEST", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_SOUTH_EAST, "PIKA_HANDLE_ANCHOR_SOUTH_EAST", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_WEST, "PIKA_HANDLE_ANCHOR_WEST", NULL },
|
||||
{ PIKA_HANDLE_ANCHOR_EAST, "PIKA_HANDLE_ANCHOR_EAST", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaHandleAnchor", values);
|
||||
pika_type_set_translation_context (type, "handle-anchor");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_limit_type_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_LIMIT_CIRCLE, "PIKA_LIMIT_CIRCLE", "circle" },
|
||||
{ PIKA_LIMIT_SQUARE, "PIKA_LIMIT_SQUARE", "square" },
|
||||
{ PIKA_LIMIT_DIAMOND, "PIKA_LIMIT_DIAMOND", "diamond" },
|
||||
{ PIKA_LIMIT_HORIZONTAL, "PIKA_LIMIT_HORIZONTAL", "horizontal" },
|
||||
{ PIKA_LIMIT_VERTICAL, "PIKA_LIMIT_VERTICAL", "vertical" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_LIMIT_CIRCLE, "PIKA_LIMIT_CIRCLE", NULL },
|
||||
{ PIKA_LIMIT_SQUARE, "PIKA_LIMIT_SQUARE", NULL },
|
||||
{ PIKA_LIMIT_DIAMOND, "PIKA_LIMIT_DIAMOND", NULL },
|
||||
{ PIKA_LIMIT_HORIZONTAL, "PIKA_LIMIT_HORIZONTAL", NULL },
|
||||
{ PIKA_LIMIT_VERTICAL, "PIKA_LIMIT_VERTICAL", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaLimitType", values);
|
||||
pika_type_set_translation_context (type, "limit-type");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_path_style_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_PATH_STYLE_DEFAULT, "PIKA_PATH_STYLE_DEFAULT", "default" },
|
||||
{ PIKA_PATH_STYLE_VECTORS, "PIKA_PATH_STYLE_VECTORS", "vectors" },
|
||||
{ PIKA_PATH_STYLE_OUTLINE, "PIKA_PATH_STYLE_OUTLINE", "outline" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_PATH_STYLE_DEFAULT, "PIKA_PATH_STYLE_DEFAULT", NULL },
|
||||
{ PIKA_PATH_STYLE_VECTORS, "PIKA_PATH_STYLE_VECTORS", NULL },
|
||||
{ PIKA_PATH_STYLE_OUTLINE, "PIKA_PATH_STYLE_OUTLINE", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaPathStyle", values);
|
||||
pika_type_set_translation_context (type, "path-style");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_rectangle_constraint_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_RECTANGLE_CONSTRAIN_NONE, "PIKA_RECTANGLE_CONSTRAIN_NONE", "none" },
|
||||
{ PIKA_RECTANGLE_CONSTRAIN_IMAGE, "PIKA_RECTANGLE_CONSTRAIN_IMAGE", "image" },
|
||||
{ PIKA_RECTANGLE_CONSTRAIN_DRAWABLE, "PIKA_RECTANGLE_CONSTRAIN_DRAWABLE", "drawable" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_RECTANGLE_CONSTRAIN_NONE, "PIKA_RECTANGLE_CONSTRAIN_NONE", NULL },
|
||||
{ PIKA_RECTANGLE_CONSTRAIN_IMAGE, "PIKA_RECTANGLE_CONSTRAIN_IMAGE", NULL },
|
||||
{ PIKA_RECTANGLE_CONSTRAIN_DRAWABLE, "PIKA_RECTANGLE_CONSTRAIN_DRAWABLE", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaRectangleConstraint", values);
|
||||
pika_type_set_translation_context (type, "rectangle-constraint");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_rectangle_fixed_rule_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_RECTANGLE_FIXED_ASPECT, "PIKA_RECTANGLE_FIXED_ASPECT", "aspect" },
|
||||
{ PIKA_RECTANGLE_FIXED_WIDTH, "PIKA_RECTANGLE_FIXED_WIDTH", "width" },
|
||||
{ PIKA_RECTANGLE_FIXED_HEIGHT, "PIKA_RECTANGLE_FIXED_HEIGHT", "height" },
|
||||
{ PIKA_RECTANGLE_FIXED_SIZE, "PIKA_RECTANGLE_FIXED_SIZE", "size" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_RECTANGLE_FIXED_ASPECT, NC_("rectangle-fixed-rule", "Aspect ratio"), NULL },
|
||||
{ PIKA_RECTANGLE_FIXED_WIDTH, NC_("rectangle-fixed-rule", "Width"), NULL },
|
||||
{ PIKA_RECTANGLE_FIXED_HEIGHT, NC_("rectangle-fixed-rule", "Height"), NULL },
|
||||
{ PIKA_RECTANGLE_FIXED_SIZE, NC_("rectangle-fixed-rule", "Size"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaRectangleFixedRule", values);
|
||||
pika_type_set_translation_context (type, "rectangle-fixed-rule");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_rectangle_precision_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_RECTANGLE_PRECISION_INT, "PIKA_RECTANGLE_PRECISION_INT", "int" },
|
||||
{ PIKA_RECTANGLE_PRECISION_DOUBLE, "PIKA_RECTANGLE_PRECISION_DOUBLE", "double" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_RECTANGLE_PRECISION_INT, "PIKA_RECTANGLE_PRECISION_INT", NULL },
|
||||
{ PIKA_RECTANGLE_PRECISION_DOUBLE, "PIKA_RECTANGLE_PRECISION_DOUBLE", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaRectanglePrecision", values);
|
||||
pika_type_set_translation_context (type, "rectangle-precision");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_transform_3d_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_TRANSFORM_3D_MODE_CAMERA, "PIKA_TRANSFORM_3D_MODE_CAMERA", "camera" },
|
||||
{ PIKA_TRANSFORM_3D_MODE_MOVE, "PIKA_TRANSFORM_3D_MODE_MOVE", "move" },
|
||||
{ PIKA_TRANSFORM_3D_MODE_ROTATE, "PIKA_TRANSFORM_3D_MODE_ROTATE", "rotate" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_TRANSFORM_3D_MODE_CAMERA, "PIKA_TRANSFORM_3D_MODE_CAMERA", NULL },
|
||||
{ PIKA_TRANSFORM_3D_MODE_MOVE, "PIKA_TRANSFORM_3D_MODE_MOVE", NULL },
|
||||
{ PIKA_TRANSFORM_3D_MODE_ROTATE, "PIKA_TRANSFORM_3D_MODE_ROTATE", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaTransform3DMode", values);
|
||||
pika_type_set_translation_context (type, "transform3-dmode");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_transform_function_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_TRANSFORM_FUNCTION_NONE, "PIKA_TRANSFORM_FUNCTION_NONE", "none" },
|
||||
{ PIKA_TRANSFORM_FUNCTION_MOVE, "PIKA_TRANSFORM_FUNCTION_MOVE", "move" },
|
||||
{ PIKA_TRANSFORM_FUNCTION_SCALE, "PIKA_TRANSFORM_FUNCTION_SCALE", "scale" },
|
||||
{ PIKA_TRANSFORM_FUNCTION_ROTATE, "PIKA_TRANSFORM_FUNCTION_ROTATE", "rotate" },
|
||||
{ PIKA_TRANSFORM_FUNCTION_SHEAR, "PIKA_TRANSFORM_FUNCTION_SHEAR", "shear" },
|
||||
{ PIKA_TRANSFORM_FUNCTION_PERSPECTIVE, "PIKA_TRANSFORM_FUNCTION_PERSPECTIVE", "perspective" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_TRANSFORM_FUNCTION_NONE, "PIKA_TRANSFORM_FUNCTION_NONE", NULL },
|
||||
{ PIKA_TRANSFORM_FUNCTION_MOVE, "PIKA_TRANSFORM_FUNCTION_MOVE", NULL },
|
||||
{ PIKA_TRANSFORM_FUNCTION_SCALE, "PIKA_TRANSFORM_FUNCTION_SCALE", NULL },
|
||||
{ PIKA_TRANSFORM_FUNCTION_ROTATE, "PIKA_TRANSFORM_FUNCTION_ROTATE", NULL },
|
||||
{ PIKA_TRANSFORM_FUNCTION_SHEAR, "PIKA_TRANSFORM_FUNCTION_SHEAR", NULL },
|
||||
{ PIKA_TRANSFORM_FUNCTION_PERSPECTIVE, "PIKA_TRANSFORM_FUNCTION_PERSPECTIVE", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaTransformFunction", values);
|
||||
pika_type_set_translation_context (type, "transform-function");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_transform_handle_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_HANDLE_MODE_ADD_TRANSFORM, "PIKA_HANDLE_MODE_ADD_TRANSFORM", "add-transform" },
|
||||
{ PIKA_HANDLE_MODE_MOVE, "PIKA_HANDLE_MODE_MOVE", "move" },
|
||||
{ PIKA_HANDLE_MODE_REMOVE, "PIKA_HANDLE_MODE_REMOVE", "remove" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_HANDLE_MODE_ADD_TRANSFORM, NC_("transform-handle-mode", "Add / Transform"), NULL },
|
||||
{ PIKA_HANDLE_MODE_MOVE, NC_("transform-handle-mode", "Move"), NULL },
|
||||
{ PIKA_HANDLE_MODE_REMOVE, NC_("transform-handle-mode", "Remove"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaTransformHandleMode", values);
|
||||
pika_type_set_translation_context (type, "transform-handle-mode");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_vector_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_VECTOR_MODE_DESIGN, "PIKA_VECTOR_MODE_DESIGN", "design" },
|
||||
{ PIKA_VECTOR_MODE_EDIT, "PIKA_VECTOR_MODE_EDIT", "edit" },
|
||||
{ PIKA_VECTOR_MODE_MOVE, "PIKA_VECTOR_MODE_MOVE", "move" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_VECTOR_MODE_DESIGN, NC_("vector-mode", "Design"), NULL },
|
||||
{ PIKA_VECTOR_MODE_EDIT, NC_("vector-mode", "Edit"), NULL },
|
||||
{ PIKA_VECTOR_MODE_MOVE, NC_("vector-mode", "Move"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaVectorMode", values);
|
||||
pika_type_set_translation_context (type, "vector-mode");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_zoom_focus_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_ZOOM_FOCUS_BEST_GUESS, "PIKA_ZOOM_FOCUS_BEST_GUESS", "best-guess" },
|
||||
{ PIKA_ZOOM_FOCUS_POINTER, "PIKA_ZOOM_FOCUS_POINTER", "pointer" },
|
||||
{ PIKA_ZOOM_FOCUS_IMAGE_CENTER, "PIKA_ZOOM_FOCUS_IMAGE_CENTER", "image-center" },
|
||||
{ PIKA_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS, "PIKA_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS", "retain-centering-else-best-guess" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_ZOOM_FOCUS_BEST_GUESS, "PIKA_ZOOM_FOCUS_BEST_GUESS", NULL },
|
||||
{ PIKA_ZOOM_FOCUS_POINTER, "PIKA_ZOOM_FOCUS_POINTER", NULL },
|
||||
{ PIKA_ZOOM_FOCUS_IMAGE_CENTER, "PIKA_ZOOM_FOCUS_IMAGE_CENTER", NULL },
|
||||
{ PIKA_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS, "PIKA_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaZoomFocus", values);
|
||||
pika_type_set_translation_context (type, "zoom-focus");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_modifier_action_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_MODIFIER_ACTION_NONE, "PIKA_MODIFIER_ACTION_NONE", "none" },
|
||||
{ PIKA_MODIFIER_ACTION_PANNING, "PIKA_MODIFIER_ACTION_PANNING", "panning" },
|
||||
{ PIKA_MODIFIER_ACTION_ZOOMING, "PIKA_MODIFIER_ACTION_ZOOMING", "zooming" },
|
||||
{ PIKA_MODIFIER_ACTION_ROTATING, "PIKA_MODIFIER_ACTION_ROTATING", "rotating" },
|
||||
{ PIKA_MODIFIER_ACTION_STEP_ROTATING, "PIKA_MODIFIER_ACTION_STEP_ROTATING", "step-rotating" },
|
||||
{ PIKA_MODIFIER_ACTION_LAYER_PICKING, "PIKA_MODIFIER_ACTION_LAYER_PICKING", "layer-picking" },
|
||||
{ PIKA_MODIFIER_ACTION_MENU, "PIKA_MODIFIER_ACTION_MENU", "menu" },
|
||||
{ PIKA_MODIFIER_ACTION_ACTION, "PIKA_MODIFIER_ACTION_ACTION", "action" },
|
||||
{ PIKA_MODIFIER_ACTION_BRUSH_PIXEL_SIZE, "PIKA_MODIFIER_ACTION_BRUSH_PIXEL_SIZE", "brush-pixel-size" },
|
||||
{ PIKA_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, "PIKA_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE", "brush-radius-pixel-size" },
|
||||
{ PIKA_MODIFIER_ACTION_TOOL_OPACITY, "PIKA_MODIFIER_ACTION_TOOL_OPACITY", "tool-opacity" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_MODIFIER_ACTION_NONE, NC_("modifier-action", "No action"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_PANNING, NC_("modifier-action", "Pan"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_ZOOMING, NC_("modifier-action", "Zoom"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_ROTATING, NC_("modifier-action", "Rotate View"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_STEP_ROTATING, NC_("modifier-action", "Rotate View by 15 degree steps"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_LAYER_PICKING, NC_("modifier-action", "Pick a layer"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_MENU, NC_("modifier-action", "Display the menu"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_ACTION, NC_("modifier-action", "Custom action"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_BRUSH_PIXEL_SIZE, NC_("modifier-action", "Change brush size in canvas pixels"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, NC_("modifier-action", "Change brush radius' size in canvas pixels"), NULL },
|
||||
{ PIKA_MODIFIER_ACTION_TOOL_OPACITY, NC_("modifier-action", "Change tool opacity"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaModifierAction", values);
|
||||
pika_type_set_translation_context (type, "modifier-action");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/* Generated data ends here */
|
||||
|
||||
304
app/display/display-enums.h
Normal file
304
app/display/display-enums.h
Normal file
@ -0,0 +1,304 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DISPLAY_ENUMS_H__
|
||||
#define __DISPLAY_ENUMS_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_BUTTON_PRESS_TYPE (pika_button_press_type_get_type ())
|
||||
|
||||
GType pika_button_press_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_BUTTON_PRESS_NORMAL,
|
||||
PIKA_BUTTON_PRESS_DOUBLE,
|
||||
PIKA_BUTTON_PRESS_TRIPLE
|
||||
} PikaButtonPressType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_BUTTON_RELEASE_TYPE (pika_button_release_type_get_type ())
|
||||
|
||||
GType pika_button_release_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_BUTTON_RELEASE_NORMAL,
|
||||
PIKA_BUTTON_RELEASE_CANCEL,
|
||||
PIKA_BUTTON_RELEASE_CLICK,
|
||||
PIKA_BUTTON_RELEASE_NO_MOTION
|
||||
} PikaButtonReleaseType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_COMPASS_ORIENTATION (pika_compass_orientation_get_type ())
|
||||
|
||||
GType pika_compass_orientation_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_COMPASS_ORIENTATION_AUTO, /*< desc="Auto" >*/
|
||||
PIKA_COMPASS_ORIENTATION_HORIZONTAL, /*< desc="Horizontal" >*/
|
||||
PIKA_COMPASS_ORIENTATION_VERTICAL /*< desc="Vertical" >*/
|
||||
} PikaCompassOrientation;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CURSOR_PRECISION (pika_cursor_precision_get_type ())
|
||||
|
||||
GType pika_cursor_precision_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_CURSOR_PRECISION_PIXEL_CENTER,
|
||||
PIKA_CURSOR_PRECISION_PIXEL_BORDER,
|
||||
PIKA_CURSOR_PRECISION_SUBPIXEL
|
||||
} PikaCursorPrecision;
|
||||
|
||||
|
||||
#define PIKA_TYPE_GUIDES_TYPE (pika_guides_type_get_type ())
|
||||
|
||||
GType pika_guides_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_GUIDES_NONE, /*< desc="No guides" >*/
|
||||
PIKA_GUIDES_CENTER_LINES, /*< desc="Center lines" >*/
|
||||
PIKA_GUIDES_THIRDS, /*< desc="Rule of thirds" >*/
|
||||
PIKA_GUIDES_FIFTHS, /*< desc="Rule of fifths" >*/
|
||||
PIKA_GUIDES_GOLDEN, /*< desc="Golden sections" >*/
|
||||
PIKA_GUIDES_DIAGONALS, /*< desc="Diagonal lines" >*/
|
||||
PIKA_GUIDES_N_LINES, /*< desc="Number of lines" >*/
|
||||
PIKA_GUIDES_SPACING /*< desc="Line spacing" >*/
|
||||
} PikaGuidesType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_HANDLE_TYPE (pika_handle_type_get_type ())
|
||||
|
||||
GType pika_handle_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_HANDLE_SQUARE,
|
||||
PIKA_HANDLE_DASHED_SQUARE,
|
||||
PIKA_HANDLE_FILLED_SQUARE,
|
||||
PIKA_HANDLE_CIRCLE,
|
||||
PIKA_HANDLE_DASHED_CIRCLE,
|
||||
PIKA_HANDLE_FILLED_CIRCLE,
|
||||
PIKA_HANDLE_DIAMOND,
|
||||
PIKA_HANDLE_DASHED_DIAMOND,
|
||||
PIKA_HANDLE_FILLED_DIAMOND,
|
||||
PIKA_HANDLE_CROSS,
|
||||
PIKA_HANDLE_CROSSHAIR,
|
||||
PIKA_HANDLE_DROP,
|
||||
PIKA_HANDLE_FILLED_DROP
|
||||
} PikaHandleType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_HANDLE_ANCHOR (pika_handle_anchor_get_type ())
|
||||
|
||||
GType pika_handle_anchor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_HANDLE_ANCHOR_CENTER,
|
||||
PIKA_HANDLE_ANCHOR_NORTH,
|
||||
PIKA_HANDLE_ANCHOR_NORTH_WEST,
|
||||
PIKA_HANDLE_ANCHOR_NORTH_EAST,
|
||||
PIKA_HANDLE_ANCHOR_SOUTH,
|
||||
PIKA_HANDLE_ANCHOR_SOUTH_WEST,
|
||||
PIKA_HANDLE_ANCHOR_SOUTH_EAST,
|
||||
PIKA_HANDLE_ANCHOR_WEST,
|
||||
PIKA_HANDLE_ANCHOR_EAST
|
||||
} PikaHandleAnchor;
|
||||
|
||||
|
||||
#define PIKA_TYPE_LIMIT_TYPE (pika_limit_type_get_type ())
|
||||
|
||||
GType pika_limit_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_LIMIT_CIRCLE,
|
||||
PIKA_LIMIT_SQUARE,
|
||||
PIKA_LIMIT_DIAMOND,
|
||||
PIKA_LIMIT_HORIZONTAL,
|
||||
PIKA_LIMIT_VERTICAL
|
||||
} PikaLimitType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_PATH_STYLE (pika_path_style_get_type ())
|
||||
|
||||
GType pika_path_style_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_PATH_STYLE_DEFAULT,
|
||||
PIKA_PATH_STYLE_VECTORS,
|
||||
PIKA_PATH_STYLE_OUTLINE
|
||||
} PikaPathStyle;
|
||||
|
||||
|
||||
#define PIKA_TYPE_RECTANGLE_CONSTRAINT (pika_rectangle_constraint_get_type ())
|
||||
|
||||
GType pika_rectangle_constraint_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_RECTANGLE_CONSTRAIN_NONE,
|
||||
PIKA_RECTANGLE_CONSTRAIN_IMAGE,
|
||||
PIKA_RECTANGLE_CONSTRAIN_DRAWABLE
|
||||
} PikaRectangleConstraint;
|
||||
|
||||
|
||||
#define PIKA_TYPE_RECTANGLE_FIXED_RULE (pika_rectangle_fixed_rule_get_type ())
|
||||
|
||||
GType pika_rectangle_fixed_rule_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_RECTANGLE_FIXED_ASPECT, /*< desc="Aspect ratio" >*/
|
||||
PIKA_RECTANGLE_FIXED_WIDTH, /*< desc="Width" >*/
|
||||
PIKA_RECTANGLE_FIXED_HEIGHT, /*< desc="Height" >*/
|
||||
PIKA_RECTANGLE_FIXED_SIZE, /*< desc="Size" >*/
|
||||
} PikaRectangleFixedRule;
|
||||
|
||||
|
||||
#define PIKA_TYPE_RECTANGLE_PRECISION (pika_rectangle_precision_get_type ())
|
||||
|
||||
GType pika_rectangle_precision_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_RECTANGLE_PRECISION_INT,
|
||||
PIKA_RECTANGLE_PRECISION_DOUBLE,
|
||||
} PikaRectanglePrecision;
|
||||
|
||||
|
||||
#define PIKA_TYPE_TRANSFORM_3D_MODE (pika_transform_3d_mode_get_type ())
|
||||
|
||||
GType pika_transform_3d_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< lowercase_name=pika_transform_3d_mode >*/
|
||||
{
|
||||
PIKA_TRANSFORM_3D_MODE_CAMERA,
|
||||
PIKA_TRANSFORM_3D_MODE_MOVE,
|
||||
PIKA_TRANSFORM_3D_MODE_ROTATE
|
||||
} PikaTransform3DMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_TRANSFORM_FUNCTION (pika_transform_function_get_type ())
|
||||
|
||||
GType pika_transform_function_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_TRANSFORM_FUNCTION_NONE,
|
||||
PIKA_TRANSFORM_FUNCTION_MOVE,
|
||||
PIKA_TRANSFORM_FUNCTION_SCALE,
|
||||
PIKA_TRANSFORM_FUNCTION_ROTATE,
|
||||
PIKA_TRANSFORM_FUNCTION_SHEAR,
|
||||
PIKA_TRANSFORM_FUNCTION_PERSPECTIVE
|
||||
} PikaTransformFunction;
|
||||
|
||||
|
||||
#define PIKA_TYPE_TRANSFORM_HANDLE_MODE (pika_transform_handle_mode_get_type ())
|
||||
|
||||
GType pika_transform_handle_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_HANDLE_MODE_ADD_TRANSFORM, /*< desc="Add / Transform" >*/
|
||||
PIKA_HANDLE_MODE_MOVE, /*< desc="Move" >*/
|
||||
PIKA_HANDLE_MODE_REMOVE /*< desc="Remove" >*/
|
||||
} PikaTransformHandleMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_VECTOR_MODE (pika_vector_mode_get_type ())
|
||||
|
||||
GType pika_vector_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_VECTOR_MODE_DESIGN, /*< desc="Design" >*/
|
||||
PIKA_VECTOR_MODE_EDIT, /*< desc="Edit" >*/
|
||||
PIKA_VECTOR_MODE_MOVE /*< desc="Move" >*/
|
||||
} PikaVectorMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_ZOOM_FOCUS (pika_zoom_focus_get_type ())
|
||||
|
||||
GType pika_zoom_focus_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* Make a best guess */
|
||||
PIKA_ZOOM_FOCUS_BEST_GUESS,
|
||||
|
||||
/* Use the mouse cursor (if within canvas) */
|
||||
PIKA_ZOOM_FOCUS_POINTER,
|
||||
|
||||
/* Use the image center */
|
||||
PIKA_ZOOM_FOCUS_IMAGE_CENTER,
|
||||
|
||||
/* If the image is centered, retain the centering. Else use
|
||||
* _BEST_GUESS
|
||||
*/
|
||||
PIKA_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS
|
||||
|
||||
} PikaZoomFocus;
|
||||
|
||||
|
||||
#define PIKA_TYPE_MODIFIER_ACTION (pika_modifier_action_get_type ())
|
||||
|
||||
GType pika_modifier_action_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_MODIFIER_ACTION_NONE, /*< desc="No action" >*/
|
||||
PIKA_MODIFIER_ACTION_PANNING, /*< desc="Pan" >*/
|
||||
PIKA_MODIFIER_ACTION_ZOOMING, /*< desc="Zoom" >*/
|
||||
PIKA_MODIFIER_ACTION_ROTATING, /*< desc="Rotate View" >*/
|
||||
PIKA_MODIFIER_ACTION_STEP_ROTATING, /*< desc="Rotate View by 15 degree steps" >*/
|
||||
PIKA_MODIFIER_ACTION_LAYER_PICKING, /*< desc="Pick a layer" >*/
|
||||
|
||||
PIKA_MODIFIER_ACTION_MENU, /*< desc="Display the menu" >*/
|
||||
|
||||
PIKA_MODIFIER_ACTION_ACTION, /*< desc="Custom action" >*/
|
||||
|
||||
PIKA_MODIFIER_ACTION_BRUSH_PIXEL_SIZE, /*< desc="Change brush size in canvas pixels" >*/
|
||||
PIKA_MODIFIER_ACTION_BRUSH_RADIUS_PIXEL_SIZE, /*< desc="Change brush radius' size in canvas pixels" >*/
|
||||
PIKA_MODIFIER_ACTION_TOOL_OPACITY, /*< desc="Change tool opacity" >*/
|
||||
} PikaModifierAction;
|
||||
|
||||
|
||||
/*
|
||||
* non-registered enums; register them if needed
|
||||
*/
|
||||
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_HIT_NONE,
|
||||
PIKA_HIT_INDIRECT,
|
||||
PIKA_HIT_DIRECT
|
||||
} PikaHit;
|
||||
|
||||
|
||||
#endif /* __DISPLAY_ENUMS_H__ */
|
||||
58
app/display/display-types.h
Normal file
58
app/display/display-types.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DISPLAY_TYPES_H__
|
||||
#define __DISPLAY_TYPES_H__
|
||||
|
||||
|
||||
#include "propgui/propgui-types.h"
|
||||
|
||||
#include "display/display-enums.h"
|
||||
|
||||
|
||||
typedef struct _PikaCanvas PikaCanvas;
|
||||
typedef struct _PikaCanvasGroup PikaCanvasGroup;
|
||||
typedef struct _PikaCanvasItem PikaCanvasItem;
|
||||
|
||||
typedef struct _PikaDisplayShell PikaDisplayShell;
|
||||
typedef struct _PikaMotionBuffer PikaMotionBuffer;
|
||||
|
||||
typedef struct _PikaImageWindow PikaImageWindow;
|
||||
typedef struct _PikaMultiWindowStrategy PikaMultiWindowStrategy;
|
||||
typedef struct _PikaSingleWindowStrategy PikaSingleWindowStrategy;
|
||||
|
||||
typedef struct _PikaCursorView PikaCursorView;
|
||||
typedef struct _PikaNavigationEditor PikaNavigationEditor;
|
||||
typedef struct _PikaScaleComboBox PikaScaleComboBox;
|
||||
typedef struct _PikaStatusbar PikaStatusbar;
|
||||
|
||||
typedef struct _PikaToolDialog PikaToolDialog;
|
||||
typedef struct _PikaToolGui PikaToolGui;
|
||||
typedef struct _PikaToolWidget PikaToolWidget;
|
||||
typedef struct _PikaToolWidgetGroup PikaToolWidgetGroup;
|
||||
|
||||
typedef struct _PikaDisplayXfer PikaDisplayXfer;
|
||||
typedef struct _Selection Selection;
|
||||
|
||||
typedef struct _PikaModifiersManager PikaModifiersManager;
|
||||
|
||||
|
||||
#endif /* __DISPLAY_TYPES_H__ */
|
||||
127
app/display/meson.build
Normal file
127
app/display/meson.build
Normal file
@ -0,0 +1,127 @@
|
||||
stamp_display_enums = custom_target('stamp-display-enums.h',
|
||||
input : [
|
||||
files(
|
||||
'display-enums.h'
|
||||
),
|
||||
],
|
||||
output: [ 'stamp-display-enums.h', ],
|
||||
command: [
|
||||
mkenums_wrap, perl,
|
||||
meson.project_source_root(), meson.current_source_dir(),
|
||||
meson.current_build_dir(),
|
||||
'display-',
|
||||
'#include <gio/gio.h>\n' +
|
||||
'#include "libpikabase/pikabase.h"\n',
|
||||
'#include "pika-intl.h"'
|
||||
],
|
||||
build_by_default: true
|
||||
)
|
||||
|
||||
libappdisplay_sources = [
|
||||
'pikacanvas-style.c',
|
||||
'pikacanvas.c',
|
||||
'pikacanvasarc.c',
|
||||
'pikacanvasboundary.c',
|
||||
'pikacanvasbufferpreview.c',
|
||||
'pikacanvascanvasboundary.c',
|
||||
'pikacanvascorner.c',
|
||||
'pikacanvascursor.c',
|
||||
'pikacanvasgrid.c',
|
||||
'pikacanvasgroup.c',
|
||||
'pikacanvasguide.c',
|
||||
'pikacanvashandle.c',
|
||||
'pikacanvasitem-utils.c',
|
||||
'pikacanvasitem.c',
|
||||
'pikacanvaslayerboundary.c',
|
||||
'pikacanvaslimit.c',
|
||||
'pikacanvasline.c',
|
||||
'pikacanvaspassepartout.c',
|
||||
'pikacanvaspath.c',
|
||||
'pikacanvaspen.c',
|
||||
'pikacanvaspolygon.c',
|
||||
'pikacanvasprogress.c',
|
||||
'pikacanvasproxygroup.c',
|
||||
'pikacanvasrectangle.c',
|
||||
'pikacanvasrectangleguides.c',
|
||||
'pikacanvassamplepoint.c',
|
||||
'pikacanvastextcursor.c',
|
||||
'pikacanvastransformguides.c',
|
||||
'pikacanvastransformpreview.c',
|
||||
'pikacanvastext.c',
|
||||
'pikacanvastext.h',
|
||||
'pikacursorview.c',
|
||||
'pikadisplay-foreach.c',
|
||||
'pikadisplay-handlers.c',
|
||||
'pikadisplay.c',
|
||||
'pikadisplayshell-actions.c',
|
||||
'pikadisplayshell-appearance.c',
|
||||
'pikadisplayshell-autoscroll.c',
|
||||
'pikadisplayshell-callbacks.c',
|
||||
'pikadisplayshell-close.c',
|
||||
'pikadisplayshell-cursor.c',
|
||||
'pikadisplayshell-dnd.c',
|
||||
'pikadisplayshell-draw.c',
|
||||
'pikadisplayshell-expose.c',
|
||||
'pikadisplayshell-filter-dialog.c',
|
||||
'pikadisplayshell-filter.c',
|
||||
'pikadisplayshell-grab.c',
|
||||
'pikadisplayshell-handlers.c',
|
||||
'pikadisplayshell-items.c',
|
||||
'pikadisplayshell-layer-select.c',
|
||||
'pikadisplayshell-profile.c',
|
||||
'pikadisplayshell-progress.c',
|
||||
'pikadisplayshell-render.c',
|
||||
'pikadisplayshell-rotate-dialog.c',
|
||||
'pikadisplayshell-rotate.c',
|
||||
'pikadisplayshell-rulers.c',
|
||||
'pikadisplayshell-scale-dialog.c',
|
||||
'pikadisplayshell-scale.c',
|
||||
'pikadisplayshell-scroll.c',
|
||||
'pikadisplayshell-scrollbars.c',
|
||||
'pikadisplayshell-selection.c',
|
||||
'pikadisplayshell-title.c',
|
||||
'pikadisplayshell-tool-events.c',
|
||||
'pikadisplayshell-transform.c',
|
||||
'pikadisplayshell-utils.c',
|
||||
'pikadisplayshell.c',
|
||||
'pikamodifiersmanager.c',
|
||||
'pikaimagewindow.c',
|
||||
'pikamotionbuffer.c',
|
||||
'pikamultiwindowstrategy.c',
|
||||
'pikanavigationeditor.c',
|
||||
'pikascalecombobox.c',
|
||||
'pikasinglewindowstrategy.c',
|
||||
'pikastatusbar.c',
|
||||
'pikatoolcompass.c',
|
||||
'pikatooldialog.c',
|
||||
'pikatoolfocus.c',
|
||||
'pikatoolgui.c',
|
||||
'pikatoolgyroscope.c',
|
||||
'pikatoolhandlegrid.c',
|
||||
'pikatoolline.c',
|
||||
'pikatoolpath.c',
|
||||
'pikatoolpolygon.c',
|
||||
'pikatoolrectangle.c',
|
||||
'pikatoolrotategrid.c',
|
||||
'pikatoolsheargrid.c',
|
||||
'pikatooltransform3dgrid.c',
|
||||
'pikatooltransformgrid.c',
|
||||
'pikatoolwidget.c',
|
||||
'pikatoolwidgetgroup.c',
|
||||
|
||||
'display-enums.c',
|
||||
stamp_display_enums,
|
||||
|
||||
gitversion_h,
|
||||
|
||||
appcoremarshal[1],
|
||||
]
|
||||
|
||||
libappdisplay = static_library('appdisplay',
|
||||
libappdisplay_sources,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Display"',
|
||||
dependencies: [
|
||||
gegl, gtk3, cairo,
|
||||
],
|
||||
)
|
||||
462
app/display/pikacanvas-style.c
Normal file
462
app/display/pikacanvas-style.c
Normal file
@ -0,0 +1,462 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvas-style.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
#include "core/pikagrid.h"
|
||||
#include "core/pikalayer.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
|
||||
/* Styles for common and custom guides. */
|
||||
static const PikaRGB guide_normal_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB guide_normal_bg = { 0.0, 0.8, 1.0, 1.0 };
|
||||
static const PikaRGB guide_active_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB guide_active_bg = { 1.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB guide_mirror_normal_fg = { 1.0, 1.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_mirror_normal_bg = { 0.0, 1.0, 0.0, 1.0 };
|
||||
static const PikaRGB guide_mirror_active_fg = { 0.0, 1.0, 0.0, 1.0 };
|
||||
static const PikaRGB guide_mirror_active_bg = { 1.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB guide_mandala_normal_fg = { 1.0, 1.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_mandala_normal_bg = { 0.0, 1.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_mandala_active_fg = { 0.0, 1.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_mandala_active_bg = { 1.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB guide_split_normal_fg = { 1.0, 1.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_split_normal_bg = { 1.0, 0.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_split_active_fg = { 1.0, 0.0, 1.0, 1.0 };
|
||||
static const PikaRGB guide_split_active_bg = { 1.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
/* Styles for other canvas items. */
|
||||
static const PikaRGB sample_point_normal = { 0.0, 0.8, 1.0, 1.0 };
|
||||
static const PikaRGB sample_point_active = { 1.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB layer_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB layer_bg = { 1.0, 1.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB layer_group_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB layer_group_bg = { 0.0, 1.0, 1.0, 1.0 };
|
||||
|
||||
static const PikaRGB layer_mask_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB layer_mask_bg = { 0.0, 1.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB canvas_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB canvas_bg = { 1.0, 0.5, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB selection_out_fg = { 1.0, 1.0, 1.0, 1.0 };
|
||||
static const PikaRGB selection_out_bg = { 0.5, 0.5, 0.5, 1.0 };
|
||||
|
||||
static const PikaRGB selection_in_fg = { 0.0, 0.0, 0.0, 1.0 };
|
||||
static const PikaRGB selection_in_bg = { 1.0, 1.0, 1.0, 1.0 };
|
||||
|
||||
static const PikaRGB vectors_normal_bg = { 1.0, 1.0, 1.0, 0.6 };
|
||||
static const PikaRGB vectors_normal_fg = { 0.0, 0.0, 1.0, 0.8 };
|
||||
|
||||
static const PikaRGB vectors_active_bg = { 1.0, 1.0, 1.0, 0.6 };
|
||||
static const PikaRGB vectors_active_fg = { 1.0, 0.0, 0.0, 0.8 };
|
||||
|
||||
static const PikaRGB outline_bg = { 1.0, 1.0, 1.0, 0.6 };
|
||||
static const PikaRGB outline_fg = { 0.0, 0.0, 0.0, 0.8 };
|
||||
|
||||
static const PikaRGB passe_partout = { 0.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
static const PikaRGB tool_bg = { 0.0, 0.0, 0.0, 0.4 };
|
||||
static const PikaRGB tool_fg = { 1.0, 1.0, 1.0, 0.8 };
|
||||
static const PikaRGB tool_fg_highlight = { 1.0, 0.8, 0.2, 0.8 };
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_canvas_set_guide_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
PikaGuideStyle style,
|
||||
gboolean active,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
PikaRGB normal_fg;
|
||||
PikaRGB normal_bg;
|
||||
PikaRGB active_fg;
|
||||
PikaRGB active_bg;
|
||||
gdouble line_width;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case PIKA_GUIDE_STYLE_NORMAL:
|
||||
normal_fg = guide_normal_fg;
|
||||
normal_bg = guide_normal_bg;
|
||||
active_fg = guide_active_fg;
|
||||
active_bg = guide_active_bg;
|
||||
line_width = 1.0;
|
||||
break;
|
||||
|
||||
case PIKA_GUIDE_STYLE_MIRROR:
|
||||
normal_fg = guide_mirror_normal_fg;
|
||||
normal_bg = guide_mirror_normal_bg;
|
||||
active_fg = guide_mirror_active_fg;
|
||||
active_bg = guide_mirror_active_bg;
|
||||
line_width = 1.0;
|
||||
break;
|
||||
|
||||
case PIKA_GUIDE_STYLE_MANDALA:
|
||||
normal_fg = guide_mandala_normal_fg;
|
||||
normal_bg = guide_mandala_normal_bg;
|
||||
active_fg = guide_mandala_active_fg;
|
||||
active_bg = guide_mandala_active_bg;
|
||||
line_width = 1.0;
|
||||
break;
|
||||
|
||||
case PIKA_GUIDE_STYLE_SPLIT_VIEW:
|
||||
normal_fg = guide_split_normal_fg;
|
||||
normal_bg = guide_split_normal_bg;
|
||||
active_fg = guide_split_active_fg;
|
||||
active_bg = guide_split_active_bg;
|
||||
line_width = 1.0;
|
||||
break;
|
||||
|
||||
default: /* PIKA_GUIDE_STYLE_NONE */
|
||||
/* This should not happen. */
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
||||
cairo_set_line_width (cr, line_width);
|
||||
|
||||
if (active)
|
||||
pattern = pika_cairo_pattern_create_stipple (&active_fg, &active_bg, 0,
|
||||
offset_x, offset_y);
|
||||
else
|
||||
pattern = pika_cairo_pattern_create_stipple (&normal_fg, &normal_bg, 0,
|
||||
offset_x, offset_y);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_sample_point_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean active)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
if (active)
|
||||
pika_cairo_set_source_rgb (cr, &sample_point_active);
|
||||
else
|
||||
pika_cairo_set_source_rgb (cr, &sample_point_normal);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_grid_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
PikaGrid *grid,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
PikaRGB fg;
|
||||
PikaRGB bg;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (PIKA_IS_GRID (grid));
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
pika_grid_get_fgcolor (grid, &fg);
|
||||
|
||||
switch (pika_grid_get_style (grid))
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
case PIKA_GRID_ON_OFF_DASH:
|
||||
case PIKA_GRID_DOUBLE_DASH:
|
||||
if (grid->style == PIKA_GRID_DOUBLE_DASH)
|
||||
{
|
||||
pika_grid_get_bgcolor (grid, &bg);
|
||||
|
||||
pattern = pika_cairo_pattern_create_stipple (&fg, &bg, 0,
|
||||
offset_x, offset_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
pattern = pika_cairo_pattern_create_stipple (&fg, &bg, 0,
|
||||
offset_x, offset_y);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
break;
|
||||
|
||||
case PIKA_GRID_DOTS:
|
||||
case PIKA_GRID_INTERSECTIONS:
|
||||
case PIKA_GRID_SOLID:
|
||||
pika_cairo_set_source_rgb (cr, &fg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_pen_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
const PikaRGB *color,
|
||||
gint width)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (color != NULL);
|
||||
|
||||
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
|
||||
cairo_set_line_width (cr, width);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
pika_cairo_set_source_rgb (cr, color);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_layer_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
PikaLayer *layer,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (PIKA_IS_LAYER (layer));
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
|
||||
if (pika_layer_get_mask (layer) &&
|
||||
pika_layer_get_edit_mask (layer))
|
||||
{
|
||||
pattern = pika_cairo_pattern_create_stipple (&layer_mask_fg,
|
||||
&layer_mask_bg,
|
||||
0,
|
||||
offset_x, offset_y);
|
||||
}
|
||||
else if (pika_viewable_get_children (PIKA_VIEWABLE (layer)))
|
||||
{
|
||||
pattern = pika_cairo_pattern_create_stipple (&layer_group_fg,
|
||||
&layer_group_bg,
|
||||
0,
|
||||
offset_x, offset_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = pika_cairo_pattern_create_stipple (&layer_fg,
|
||||
&layer_bg,
|
||||
0,
|
||||
offset_x, offset_y);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_canvas_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
|
||||
pattern = pika_cairo_pattern_create_stipple (&canvas_fg,
|
||||
&canvas_bg,
|
||||
0,
|
||||
offset_x, offset_y);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_selection_out_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
|
||||
pattern = pika_cairo_pattern_create_stipple (&selection_out_fg,
|
||||
&selection_out_bg,
|
||||
0,
|
||||
offset_x, offset_y);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_selection_in_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gint index,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
|
||||
pattern = pika_cairo_pattern_create_stipple (&selection_in_fg,
|
||||
&selection_in_bg,
|
||||
index,
|
||||
offset_x, offset_y);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_vectors_bg_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean active)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 3.0);
|
||||
|
||||
if (active)
|
||||
pika_cairo_set_source_rgba (cr, &vectors_active_bg);
|
||||
else
|
||||
pika_cairo_set_source_rgba (cr, &vectors_normal_bg);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_vectors_fg_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean active)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
if (active)
|
||||
pika_cairo_set_source_rgba (cr, &vectors_active_fg);
|
||||
else
|
||||
pika_cairo_set_source_rgba (cr, &vectors_normal_fg);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_outline_bg_style (GtkWidget *canvas,
|
||||
cairo_t *cr)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
pika_cairo_set_source_rgba (cr, &outline_bg);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_outline_fg_style (GtkWidget *canvas,
|
||||
cairo_t *cr)
|
||||
{
|
||||
static const double dashes[] = { 4.0, 4.0 };
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
pika_cairo_set_source_rgba (cr, &outline_fg);
|
||||
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_passe_partout_style (GtkWidget *canvas,
|
||||
cairo_t *cr)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
pika_cairo_set_source_rgba (cr, &passe_partout);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_tool_bg_style (GtkWidget *canvas,
|
||||
cairo_t *cr)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (canvas));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 3.0);
|
||||
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
pika_cairo_set_source_rgba (cr, &tool_bg);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_set_tool_fg_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean highlight)
|
||||
{
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
if (highlight)
|
||||
pika_cairo_set_source_rgba (cr, &tool_fg_highlight);
|
||||
else
|
||||
pika_cairo_set_source_rgba (cr, &tool_fg);
|
||||
}
|
||||
85
app/display/pikacanvas-style.h
Normal file
85
app/display/pikacanvas-style.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* 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
|
||||
*
|
||||
* pikadisplayshell-style.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_STYLE_H__
|
||||
#define __PIKA_CANVAS_STYLE_H__
|
||||
|
||||
|
||||
void pika_canvas_set_guide_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
PikaGuideStyle style,
|
||||
gboolean active,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
void pika_canvas_set_sample_point_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean active);
|
||||
void pika_canvas_set_grid_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
PikaGrid *grid,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
void pika_canvas_set_pen_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
const PikaRGB *color,
|
||||
gint width);
|
||||
void pika_canvas_set_layer_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
PikaLayer *layer,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
void pika_canvas_set_canvas_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
void pika_canvas_set_selection_out_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
void pika_canvas_set_selection_in_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gint index,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
void pika_canvas_set_vectors_bg_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean active);
|
||||
void pika_canvas_set_vectors_fg_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean active);
|
||||
void pika_canvas_set_outline_bg_style (GtkWidget *canvas,
|
||||
cairo_t *cr);
|
||||
void pika_canvas_set_outline_fg_style (GtkWidget *canvas,
|
||||
cairo_t *cr);
|
||||
void pika_canvas_set_passe_partout_style (GtkWidget *canvas,
|
||||
cairo_t *cr);
|
||||
|
||||
void pika_canvas_set_tool_bg_style (GtkWidget *canvas,
|
||||
cairo_t *cr);
|
||||
void pika_canvas_set_tool_fg_style (GtkWidget *canvas,
|
||||
cairo_t *cr,
|
||||
gboolean highlight);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_STYLE_H__ */
|
||||
292
app/display/pikacanvas.c
Normal file
292
app/display/pikacanvas.c
Normal file
@ -0,0 +1,292 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "config/pikadisplayconfig.h"
|
||||
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define MAX_BATCH_SIZE 32000
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CONFIG
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_canvas_unrealize (GtkWidget *widget);
|
||||
static void pika_canvas_style_updated (GtkWidget *widget);
|
||||
static gboolean pika_canvas_focus_in_event (GtkWidget *widget,
|
||||
GdkEventFocus *event);
|
||||
static gboolean pika_canvas_focus_out_event (GtkWidget *widget,
|
||||
GdkEventFocus *event);
|
||||
static gboolean pika_canvas_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaCanvas, pika_canvas, PIKA_TYPE_OVERLAY_BOX)
|
||||
|
||||
#define parent_class pika_canvas_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_class_init (PikaCanvasClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_set_property;
|
||||
object_class->get_property = pika_canvas_get_property;
|
||||
|
||||
widget_class->unrealize = pika_canvas_unrealize;
|
||||
widget_class->style_updated = pika_canvas_style_updated;
|
||||
widget_class->focus_in_event = pika_canvas_focus_in_event;
|
||||
widget_class->focus_out_event = pika_canvas_focus_out_event;
|
||||
widget_class->focus = pika_canvas_focus;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CONFIG,
|
||||
g_param_spec_object ("config", NULL, NULL,
|
||||
PIKA_TYPE_DISPLAY_CONFIG,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_init (PikaCanvas *canvas)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (canvas);
|
||||
|
||||
gtk_widget_set_can_focus (widget, TRUE);
|
||||
gtk_widget_add_events (widget, PIKA_CANVAS_EVENT_MASK);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvas *canvas = PIKA_CANVAS (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_CONFIG:
|
||||
canvas->config = g_value_get_object (value); /* don't dup */
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvas *canvas = PIKA_CANVAS (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_CONFIG:
|
||||
g_value_set_object (value, canvas->config);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_unrealize (GtkWidget *widget)
|
||||
{
|
||||
PikaCanvas *canvas = PIKA_CANVAS (widget);
|
||||
|
||||
g_clear_object (&canvas->layout);
|
||||
|
||||
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_style_updated (GtkWidget *widget)
|
||||
{
|
||||
PikaCanvas *canvas = PIKA_CANVAS (widget);
|
||||
|
||||
g_clear_object (&canvas->layout);
|
||||
|
||||
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_focus_in_event (GtkWidget *widget,
|
||||
GdkEventFocus *event)
|
||||
{
|
||||
/* don't allow the default impl to invalidate the whole widget,
|
||||
* we don't draw a focus indicator anyway.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_focus_out_event (GtkWidget *widget,
|
||||
GdkEventFocus *event)
|
||||
{
|
||||
/* see focus-in-event
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkWidget *focus = gtk_container_get_focus_child (GTK_CONTAINER (widget));
|
||||
|
||||
/* override GtkContainer's focus() implementation which would always
|
||||
* give focus to the canvas because it is focussable. Instead, try
|
||||
* navigating in the focused overlay child first, and use
|
||||
* GtkContainer's default implementation only if that fails (which
|
||||
* happens when focus navigation leaves the overlay child).
|
||||
*/
|
||||
|
||||
if (focus && gtk_widget_child_focus (focus, direction))
|
||||
return TRUE;
|
||||
|
||||
return GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
/**
|
||||
* pika_canvas_new:
|
||||
*
|
||||
* Creates a new #PikaCanvas widget.
|
||||
*
|
||||
* The #PikaCanvas widget is a #GtkDrawingArea abstraction. It manages
|
||||
* a set of graphic contexts for drawing on a PIKA display. If you
|
||||
* draw using a #PikaCanvasStyle, #PikaCanvas makes sure that the
|
||||
* associated #GdkGC is created. All drawing on the canvas needs to
|
||||
* happen by means of the #PikaCanvas drawing functions. Besides from
|
||||
* not needing a #GdkGC pointer, the #PikaCanvas drawing functions
|
||||
* look and work like their #GdkDrawable counterparts. #PikaCanvas
|
||||
* gracefully handles attempts to draw on the unrealized widget.
|
||||
*
|
||||
* Returns: a new #PikaCanvas widget
|
||||
**/
|
||||
GtkWidget *
|
||||
pika_canvas_new (PikaDisplayConfig *config)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_CONFIG (config), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS,
|
||||
"name", "pika-canvas",
|
||||
"config", config,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_canvas_get_layout:
|
||||
* @canvas: a #PikaCanvas widget
|
||||
* @format: a standard printf() format string.
|
||||
* @Varargs: the parameters to insert into the format string.
|
||||
*
|
||||
* Returns a layout which can be used for
|
||||
* pango_cairo_show_layout(). The layout belongs to the canvas and
|
||||
* should not be freed, not should a pointer to it be kept around
|
||||
* after drawing.
|
||||
*
|
||||
* Returns: a #PangoLayout owned by the canvas.
|
||||
**/
|
||||
PangoLayout *
|
||||
pika_canvas_get_layout (PikaCanvas *canvas,
|
||||
const gchar *format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
gchar *text;
|
||||
|
||||
if (! canvas->layout)
|
||||
canvas->layout = gtk_widget_create_pango_layout (GTK_WIDGET (canvas),
|
||||
NULL);
|
||||
|
||||
va_start (args, format);
|
||||
text = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
pango_layout_set_text (canvas->layout, text, -1);
|
||||
g_free (text);
|
||||
|
||||
return canvas->layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_canvas_set_padding:
|
||||
* @canvas: a #PikaCanvas widget
|
||||
* @color: a color in #PikaRGB format
|
||||
*
|
||||
* Sets the background color of the canvas's window. This
|
||||
* is the color the canvas is set to if it is cleared.
|
||||
**/
|
||||
void
|
||||
pika_canvas_set_padding (PikaCanvas *canvas,
|
||||
PikaCanvasPaddingMode padding_mode,
|
||||
const PikaRGB *padding_color)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS (canvas));
|
||||
g_return_if_fail (padding_color != NULL);
|
||||
|
||||
canvas->padding_mode = padding_mode;
|
||||
canvas->padding_color = *padding_color;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (canvas));
|
||||
}
|
||||
85
app/display/pikacanvas.h
Normal file
85
app/display/pikacanvas.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_H__
|
||||
#define __PIKA_CANVAS_H__
|
||||
|
||||
|
||||
#include "widgets/pikaoverlaybox.h"
|
||||
|
||||
|
||||
#define PIKA_CANVAS_EVENT_MASK (GDK_EXPOSURE_MASK | \
|
||||
GDK_POINTER_MOTION_MASK | \
|
||||
GDK_BUTTON_PRESS_MASK | \
|
||||
GDK_BUTTON_RELEASE_MASK | \
|
||||
GDK_SCROLL_MASK | \
|
||||
GDK_SMOOTH_SCROLL_MASK | \
|
||||
GDK_TOUCHPAD_GESTURE_MASK | \
|
||||
GDK_STRUCTURE_MASK | \
|
||||
GDK_ENTER_NOTIFY_MASK | \
|
||||
GDK_LEAVE_NOTIFY_MASK | \
|
||||
GDK_FOCUS_CHANGE_MASK | \
|
||||
GDK_KEY_PRESS_MASK | \
|
||||
GDK_KEY_RELEASE_MASK | \
|
||||
GDK_PROXIMITY_OUT_MASK)
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS (pika_canvas_get_type ())
|
||||
#define PIKA_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS, PikaCanvas))
|
||||
#define PIKA_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS, PikaCanvasClass))
|
||||
#define PIKA_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS))
|
||||
#define PIKA_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS))
|
||||
#define PIKA_CANVAS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS, PikaCanvasClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasClass PikaCanvasClass;
|
||||
|
||||
struct _PikaCanvas
|
||||
{
|
||||
PikaOverlayBox parent_instance;
|
||||
|
||||
PikaDisplayConfig *config;
|
||||
PangoLayout *layout;
|
||||
|
||||
PikaCanvasPaddingMode padding_mode;
|
||||
PikaRGB padding_color;
|
||||
};
|
||||
|
||||
struct _PikaCanvasClass
|
||||
{
|
||||
PikaOverlayBoxClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * pika_canvas_new (PikaDisplayConfig *config);
|
||||
|
||||
PangoLayout * pika_canvas_get_layout (PikaCanvas *canvas,
|
||||
const gchar *format,
|
||||
...) G_GNUC_PRINTF (2, 3);
|
||||
|
||||
void pika_canvas_set_padding (PikaCanvas *canvas,
|
||||
PikaCanvasPaddingMode padding_mode,
|
||||
const PikaRGB *padding_color);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_H__ */
|
||||
373
app/display/pikacanvasarc.c
Normal file
373
app/display/pikacanvasarc.c
Normal file
@ -0,0 +1,373 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasarc.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
|
||||
#include "pikacanvasarc.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CENTER_X,
|
||||
PROP_CENTER_Y,
|
||||
PROP_RADIUS_X,
|
||||
PROP_RADIUS_Y,
|
||||
PROP_START_ANGLE,
|
||||
PROP_SLICE_ANGLE,
|
||||
PROP_FILLED
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasArcPrivate PikaCanvasArcPrivate;
|
||||
|
||||
struct _PikaCanvasArcPrivate
|
||||
{
|
||||
gdouble center_x;
|
||||
gdouble center_y;
|
||||
gdouble radius_x;
|
||||
gdouble radius_y;
|
||||
gdouble start_angle;
|
||||
gdouble slice_angle;
|
||||
gboolean filled;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(arc) \
|
||||
((PikaCanvasArcPrivate *) pika_canvas_arc_get_instance_private ((PikaCanvasArc *) (arc)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_arc_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_arc_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_arc_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_arc_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasArc, pika_canvas_arc,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_arc_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_arc_class_init (PikaCanvasArcClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_arc_set_property;
|
||||
object_class->get_property = pika_canvas_arc_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_arc_draw;
|
||||
item_class->get_extents = pika_canvas_arc_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CENTER_X,
|
||||
g_param_spec_double ("center-x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CENTER_Y,
|
||||
g_param_spec_double ("center-y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RADIUS_X,
|
||||
g_param_spec_double ("radius-x", NULL, NULL,
|
||||
0, PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RADIUS_Y,
|
||||
g_param_spec_double ("radius-y", NULL, NULL,
|
||||
0, PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_START_ANGLE,
|
||||
g_param_spec_double ("start-angle", NULL, NULL,
|
||||
-1000, 1000, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SLICE_ANGLE,
|
||||
g_param_spec_double ("slice-angle", NULL, NULL,
|
||||
-1000, 1000, 2 * G_PI,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FILLED,
|
||||
g_param_spec_boolean ("filled", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_arc_init (PikaCanvasArc *arc)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_arc_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasArcPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_CENTER_X:
|
||||
private->center_x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_CENTER_Y:
|
||||
private->center_y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_RADIUS_X:
|
||||
private->radius_x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_RADIUS_Y:
|
||||
private->radius_y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_START_ANGLE:
|
||||
private->start_angle = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_SLICE_ANGLE:
|
||||
private->slice_angle = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_FILLED:
|
||||
private->filled = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_arc_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasArcPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_CENTER_X:
|
||||
g_value_set_double (value, private->center_x);
|
||||
break;
|
||||
case PROP_CENTER_Y:
|
||||
g_value_set_double (value, private->center_y);
|
||||
break;
|
||||
case PROP_RADIUS_X:
|
||||
g_value_set_double (value, private->radius_x);
|
||||
break;
|
||||
case PROP_RADIUS_Y:
|
||||
g_value_set_double (value, private->radius_y);
|
||||
break;
|
||||
case PROP_START_ANGLE:
|
||||
g_value_set_double (value, private->start_angle);
|
||||
break;
|
||||
case PROP_SLICE_ANGLE:
|
||||
g_value_set_double (value, private->slice_angle);
|
||||
break;
|
||||
case PROP_FILLED:
|
||||
g_value_set_boolean (value, private->filled);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_arc_transform (PikaCanvasItem *item,
|
||||
gdouble *center_x,
|
||||
gdouble *center_y,
|
||||
gdouble *radius_x,
|
||||
gdouble *radius_y)
|
||||
{
|
||||
PikaCanvasArcPrivate *private = GET_PRIVATE (item);
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->center_x - private->radius_x,
|
||||
private->center_y - private->radius_y,
|
||||
&x1, &y1);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->center_x + private->radius_x,
|
||||
private->center_y + private->radius_y,
|
||||
&x2, &y2);
|
||||
|
||||
x1 = floor (x1);
|
||||
y1 = floor (y1);
|
||||
x2 = ceil (x2);
|
||||
y2 = ceil (y2);
|
||||
|
||||
*center_x = (x1 + x2) / 2.0;
|
||||
*center_y = (y1 + y2) / 2.0;
|
||||
|
||||
*radius_x = (x2 - x1) / 2.0;
|
||||
*radius_y = (y2 - y1) / 2.0;
|
||||
|
||||
if (! private->filled)
|
||||
{
|
||||
*radius_x = MAX (*radius_x - 0.5, 0.0);
|
||||
*radius_y = MAX (*radius_y - 0.5, 0.0);
|
||||
}
|
||||
|
||||
/* avoid cairo_scale (cr, 0.0, 0.0) */
|
||||
if (*radius_x == 0.0) *radius_x = 0.000001;
|
||||
if (*radius_y == 0.0) *radius_y = 0.000001;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_arc_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasArcPrivate *private = GET_PRIVATE (item);
|
||||
gdouble center_x, center_y;
|
||||
gdouble radius_x, radius_y;
|
||||
|
||||
pika_canvas_arc_transform (item,
|
||||
¢er_x, ¢er_y,
|
||||
&radius_x, &radius_y);
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, center_x, center_y);
|
||||
cairo_scale (cr, radius_x, radius_y);
|
||||
pika_cairo_arc (cr, 0.0, 0.0, 1.0,
|
||||
private->start_angle, private->slice_angle);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (private->filled)
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
else
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_arc_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasArcPrivate *private = GET_PRIVATE (item);
|
||||
cairo_region_t *region;
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble center_x, center_y;
|
||||
gdouble radius_x, radius_y;
|
||||
|
||||
pika_canvas_arc_transform (item,
|
||||
¢er_x, ¢er_y,
|
||||
&radius_x, &radius_y);
|
||||
|
||||
rectangle.x = floor (center_x - radius_x - 1.5);
|
||||
rectangle.y = floor (center_y - radius_y - 1.5);
|
||||
rectangle.width = ceil (center_x + radius_x + 1.5) - rectangle.x;
|
||||
rectangle.height = ceil (center_y + radius_y + 1.5) - rectangle.y;
|
||||
|
||||
region = cairo_region_create_rectangle (&rectangle);
|
||||
|
||||
if (! private->filled &&
|
||||
rectangle.width > 64 * 1.43 &&
|
||||
rectangle.height > 64 * 1.43)
|
||||
{
|
||||
radius_x *= 0.7;
|
||||
radius_y *= 0.7;
|
||||
|
||||
rectangle.x = ceil (center_x - radius_x + 1.5);
|
||||
rectangle.y = ceil (center_y - radius_y + 1.5);
|
||||
rectangle.width = floor (center_x + radius_x - 1.5) - rectangle.x;
|
||||
rectangle.height = floor (center_y + radius_y - 1.5) - rectangle.y;
|
||||
|
||||
cairo_region_subtract_rectangle (region, &rectangle);
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_arc_new (PikaDisplayShell *shell,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble radius_x,
|
||||
gdouble radius_y,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle,
|
||||
gboolean filled)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_ARC,
|
||||
"shell", shell,
|
||||
"center-x", center_x,
|
||||
"center-y", center_y,
|
||||
"radius-x", radius_x,
|
||||
"radius-y", radius_y,
|
||||
"start-angle", start_angle,
|
||||
"slice-angle", slice_angle,
|
||||
"filled", filled,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_arc_set (PikaCanvasItem *arc,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble radius_x,
|
||||
gdouble radius_y,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ARC (arc));
|
||||
|
||||
pika_canvas_item_begin_change (arc);
|
||||
g_object_set (arc,
|
||||
"center-x", center_x,
|
||||
"center-y", center_y,
|
||||
"radius-x", radius_x,
|
||||
"radius-y", radius_y,
|
||||
"start-angle", start_angle,
|
||||
"slice-angle", slice_angle,
|
||||
NULL);
|
||||
pika_canvas_item_end_change (arc);
|
||||
}
|
||||
73
app/display/pikacanvasarc.h
Normal file
73
app/display/pikacanvasarc.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasarc.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_ARC_H__
|
||||
#define __PIKA_CANVAS_ARC_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_ARC (pika_canvas_arc_get_type ())
|
||||
#define PIKA_CANVAS_ARC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_ARC, PikaCanvasArc))
|
||||
#define PIKA_CANVAS_ARC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_ARC, PikaCanvasArcClass))
|
||||
#define PIKA_IS_CANVAS_ARC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_ARC))
|
||||
#define PIKA_IS_CANVAS_ARC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_ARC))
|
||||
#define PIKA_CANVAS_ARC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_ARC, PikaCanvasArcClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasArc PikaCanvasArc;
|
||||
typedef struct _PikaCanvasArcClass PikaCanvasArcClass;
|
||||
|
||||
struct _PikaCanvasArc
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasArcClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_arc_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_arc_new (PikaDisplayShell *shell,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble radius_x,
|
||||
gdouble radius_y,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle,
|
||||
gboolean filled);
|
||||
|
||||
void pika_canvas_arc_set (PikaCanvasItem *arc,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble radius_x,
|
||||
gdouble radius_y,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle);
|
||||
|
||||
#endif /* __PIKA_CANVAS_ARC_H__ */
|
||||
388
app/display/pikacanvasboundary.c
Normal file
388
app/display/pikacanvasboundary.c
Normal file
@ -0,0 +1,388 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasboundary.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
#include "core/pika-transform-utils.h"
|
||||
#include "core/pikaboundary.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
|
||||
#include "pikacanvasboundary.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SEGS,
|
||||
PROP_TRANSFORM,
|
||||
PROP_OFFSET_X,
|
||||
PROP_OFFSET_Y
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasBoundaryPrivate PikaCanvasBoundaryPrivate;
|
||||
|
||||
struct _PikaCanvasBoundaryPrivate
|
||||
{
|
||||
PikaBoundSeg *segs;
|
||||
gint n_segs;
|
||||
PikaMatrix3 *transform;
|
||||
gdouble offset_x;
|
||||
gdouble offset_y;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(boundary) \
|
||||
((PikaCanvasBoundaryPrivate *) pika_canvas_boundary_get_instance_private ((PikaCanvasBoundary *) (boundary)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_boundary_finalize (GObject *object);
|
||||
static void pika_canvas_boundary_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_boundary_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_boundary_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_boundary_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasBoundary, pika_canvas_boundary,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_boundary_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_class_init (PikaCanvasBoundaryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_boundary_finalize;
|
||||
object_class->set_property = pika_canvas_boundary_set_property;
|
||||
object_class->get_property = pika_canvas_boundary_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_boundary_draw;
|
||||
item_class->get_extents = pika_canvas_boundary_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SEGS,
|
||||
pika_param_spec_array ("segs", NULL, NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TRANSFORM,
|
||||
g_param_spec_pointer ("transform", NULL, NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OFFSET_X,
|
||||
g_param_spec_double ("offset-x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OFFSET_Y,
|
||||
g_param_spec_double ("offset-y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_init (PikaCanvasBoundary *boundary)
|
||||
{
|
||||
pika_canvas_item_set_line_cap (PIKA_CANVAS_ITEM (boundary),
|
||||
CAIRO_LINE_CAP_SQUARE);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_pointer (&private->segs, g_free);
|
||||
private->n_segs = 0;
|
||||
|
||||
g_clear_pointer (&private->transform, g_free);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SEGS:
|
||||
break;
|
||||
|
||||
case PROP_TRANSFORM:
|
||||
{
|
||||
PikaMatrix3 *transform = g_value_get_pointer (value);
|
||||
if (private->transform)
|
||||
g_free (private->transform);
|
||||
if (transform)
|
||||
private->transform = g_memdup2 (transform, sizeof (PikaMatrix3));
|
||||
else
|
||||
private->transform = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OFFSET_X:
|
||||
private->offset_x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_OFFSET_Y:
|
||||
private->offset_y = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SEGS:
|
||||
break;
|
||||
|
||||
case PROP_TRANSFORM:
|
||||
g_value_set_pointer (value, private->transform);
|
||||
break;
|
||||
|
||||
case PROP_OFFSET_X:
|
||||
g_value_set_double (value, private->offset_x);
|
||||
break;
|
||||
case PROP_OFFSET_Y:
|
||||
g_value_set_double (value, private->offset_y);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_transform (PikaCanvasItem *item,
|
||||
PikaSegment *segs,
|
||||
gint *n_segs)
|
||||
{
|
||||
PikaCanvasBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
gint i;
|
||||
|
||||
if (private->transform)
|
||||
{
|
||||
gint n = 0;
|
||||
|
||||
for (i = 0; i < private->n_segs; i++)
|
||||
{
|
||||
PikaVector2 vertices[2];
|
||||
PikaVector2 t_vertices[2];
|
||||
gint n_t_vertices;
|
||||
|
||||
vertices[0] = (PikaVector2) { private->segs[i].x1, private->segs[i].y1 };
|
||||
vertices[1] = (PikaVector2) { private->segs[i].x2, private->segs[i].y2 };
|
||||
|
||||
pika_transform_polygon (private->transform, vertices, 2, FALSE,
|
||||
t_vertices, &n_t_vertices);
|
||||
|
||||
if (n_t_vertices == 2)
|
||||
{
|
||||
pika_canvas_item_transform_xy (item,
|
||||
t_vertices[0].x + private->offset_x,
|
||||
t_vertices[0].y + private->offset_y,
|
||||
&segs[n].x1, &segs[n].y1);
|
||||
pika_canvas_item_transform_xy (item,
|
||||
t_vertices[1].x + private->offset_x,
|
||||
t_vertices[1].y + private->offset_y,
|
||||
&segs[n].x2, &segs[n].y2);
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
*n_segs = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < private->n_segs; i++)
|
||||
{
|
||||
pika_canvas_item_transform_xy (item,
|
||||
private->segs[i].x1 + private->offset_x,
|
||||
private->segs[i].y1 + private->offset_y,
|
||||
&segs[i].x1,
|
||||
&segs[i].y1);
|
||||
pika_canvas_item_transform_xy (item,
|
||||
private->segs[i].x2 + private->offset_x,
|
||||
private->segs[i].y2 + private->offset_y,
|
||||
&segs[i].x2,
|
||||
&segs[i].y2);
|
||||
|
||||
/* If this segment is a closing segment && the segments lie inside
|
||||
* the region, OR if this is an opening segment and the segments
|
||||
* lie outside the region...
|
||||
* we need to transform it by one display pixel
|
||||
*/
|
||||
if (! private->segs[i].open)
|
||||
{
|
||||
/* If it is vertical */
|
||||
if (segs[i].x1 == segs[i].x2)
|
||||
{
|
||||
segs[i].x1 -= 1;
|
||||
segs[i].x2 -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
segs[i].y1 -= 1;
|
||||
segs[i].y2 -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*n_segs = private->n_segs;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_boundary_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
PikaSegment *segs;
|
||||
gint n_segs;
|
||||
|
||||
segs = g_new0 (PikaSegment, private->n_segs);
|
||||
|
||||
pika_canvas_boundary_transform (item, segs, &n_segs);
|
||||
|
||||
pika_cairo_segments (cr, segs, n_segs);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
g_free (segs);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_boundary_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
PikaSegment *segs;
|
||||
gint n_segs;
|
||||
gint x1, y1, x2, y2;
|
||||
gint i;
|
||||
|
||||
segs = g_new0 (PikaSegment, private->n_segs);
|
||||
|
||||
pika_canvas_boundary_transform (item, segs, &n_segs);
|
||||
|
||||
if (n_segs == 0)
|
||||
{
|
||||
g_free (segs);
|
||||
|
||||
return cairo_region_create ();
|
||||
}
|
||||
|
||||
x1 = MIN (segs[0].x1, segs[0].x2);
|
||||
y1 = MIN (segs[0].y1, segs[0].y2);
|
||||
x2 = MAX (segs[0].x1, segs[0].x2);
|
||||
y2 = MAX (segs[0].y1, segs[0].y2);
|
||||
|
||||
for (i = 1; i < n_segs; i++)
|
||||
{
|
||||
gint x3 = MIN (segs[i].x1, segs[i].x2);
|
||||
gint y3 = MIN (segs[i].y1, segs[i].y2);
|
||||
gint x4 = MAX (segs[i].x1, segs[i].x2);
|
||||
gint y4 = MAX (segs[i].y1, segs[i].y2);
|
||||
|
||||
x1 = MIN (x1, x3);
|
||||
y1 = MIN (y1, y3);
|
||||
x2 = MAX (x2, x4);
|
||||
y2 = MAX (y2, y4);
|
||||
}
|
||||
|
||||
g_free (segs);
|
||||
|
||||
rectangle.x = x1 - 2;
|
||||
rectangle.y = y1 - 2;
|
||||
rectangle.width = x2 - x1 + 4;
|
||||
rectangle.height = y2 - y1 + 4;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_boundary_new (PikaDisplayShell *shell,
|
||||
const PikaBoundSeg *segs,
|
||||
gint n_segs,
|
||||
PikaMatrix3 *transform,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
PikaCanvasItem *item;
|
||||
PikaCanvasBoundaryPrivate *private;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
item = g_object_new (PIKA_TYPE_CANVAS_BOUNDARY,
|
||||
"shell", shell,
|
||||
"transform", transform,
|
||||
"offset-x", offset_x,
|
||||
"offset-y", offset_y,
|
||||
NULL);
|
||||
private = GET_PRIVATE (item);
|
||||
|
||||
/* puke */
|
||||
private->segs = g_memdup2 (segs, n_segs * sizeof (PikaBoundSeg));
|
||||
private->n_segs = n_segs;
|
||||
|
||||
return item;
|
||||
}
|
||||
64
app/display/pikacanvasboundary.h
Normal file
64
app/display/pikacanvasboundary.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasboundary.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_BOUNDARY_H__
|
||||
#define __PIKA_CANVAS_BOUNDARY_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_BOUNDARY (pika_canvas_boundary_get_type ())
|
||||
#define PIKA_CANVAS_BOUNDARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_BOUNDARY, PikaCanvasBoundary))
|
||||
#define PIKA_CANVAS_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_BOUNDARY, PikaCanvasBoundaryClass))
|
||||
#define PIKA_IS_CANVAS_BOUNDARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_BOUNDARY))
|
||||
#define PIKA_IS_CANVAS_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_BOUNDARY))
|
||||
#define PIKA_CANVAS_BOUNDARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_BOUNDARY, PikaCanvasBoundaryClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasBoundary PikaCanvasBoundary;
|
||||
typedef struct _PikaCanvasBoundaryClass PikaCanvasBoundaryClass;
|
||||
|
||||
struct _PikaCanvasBoundary
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasBoundaryClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_boundary_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_boundary_new (PikaDisplayShell *shell,
|
||||
const PikaBoundSeg *segs,
|
||||
gint n_segs,
|
||||
PikaMatrix3 *transform,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_BOUNDARY_H__ */
|
||||
267
app/display/pikacanvasbufferpreview.c
Normal file
267
app/display/pikacanvasbufferpreview.c
Normal file
@ -0,0 +1,267 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasbufferpreview.c
|
||||
* Copyright (C) 2013 Marek Dvoroznak <dvoromar@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display/display-types.h"
|
||||
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvasbufferpreview.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-scroll.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_BUFFER
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasBufferPreviewPrivate PikaCanvasBufferPreviewPrivate;
|
||||
|
||||
struct _PikaCanvasBufferPreviewPrivate
|
||||
{
|
||||
GeglBuffer *buffer;
|
||||
};
|
||||
|
||||
|
||||
#define GET_PRIVATE(transform_preview) \
|
||||
((PikaCanvasBufferPreviewPrivate *) pika_canvas_buffer_preview_get_instance_private ((PikaCanvasBufferPreview *) (transform_preview)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_buffer_preview_dispose (GObject *object);
|
||||
static void pika_canvas_buffer_preview_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_buffer_preview_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_canvas_buffer_preview_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_buffer_preview_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_buffer_preview_compute_bounds (PikaCanvasItem *item,
|
||||
cairo_rectangle_int_t *bounds);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasBufferPreview, pika_canvas_buffer_preview,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_buffer_preview_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_class_init (PikaCanvasBufferPreviewClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->dispose = pika_canvas_buffer_preview_dispose;
|
||||
object_class->set_property = pika_canvas_buffer_preview_set_property;
|
||||
object_class->get_property = pika_canvas_buffer_preview_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_buffer_preview_draw;
|
||||
item_class->get_extents = pika_canvas_buffer_preview_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_BUFFER,
|
||||
g_param_spec_object ("buffer",
|
||||
NULL, NULL,
|
||||
GEGL_TYPE_BUFFER,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_init (PikaCanvasBufferPreview *transform_preview)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_dispose (GObject *object)
|
||||
{
|
||||
PikaCanvasBufferPreviewPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_object (&private->buffer);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasBufferPreviewPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_BUFFER:
|
||||
g_set_object (&private->buffer, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasBufferPreviewPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_BUFFER:
|
||||
g_value_set_object (value, private->buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
GeglBuffer *buffer = GET_PRIVATE (item)->buffer;
|
||||
cairo_surface_t *area;
|
||||
guchar *data;
|
||||
cairo_rectangle_int_t rectangle;
|
||||
|
||||
g_return_if_fail (GEGL_IS_BUFFER (buffer));
|
||||
|
||||
pika_canvas_buffer_preview_compute_bounds (item, &rectangle);
|
||||
|
||||
area = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
rectangle.width,
|
||||
rectangle.height);
|
||||
|
||||
data = cairo_image_surface_get_data (area);
|
||||
gegl_buffer_get (buffer,
|
||||
GEGL_RECTANGLE (rectangle.x + shell->offset_x,
|
||||
rectangle.y + shell->offset_y,
|
||||
rectangle.width,
|
||||
rectangle.height),
|
||||
shell->scale_x,
|
||||
babl_format ("cairo-ARGB32"),
|
||||
data,
|
||||
cairo_image_surface_get_stride (area),
|
||||
GEGL_ABYSS_NONE);
|
||||
|
||||
cairo_surface_flush (area);
|
||||
cairo_surface_mark_dirty (area);
|
||||
|
||||
cairo_set_source_surface (cr, area, rectangle.x, rectangle.y);
|
||||
cairo_rectangle (cr,
|
||||
rectangle.x, rectangle.y,
|
||||
rectangle.width, rectangle.height);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_surface_destroy (area);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_buffer_preview_compute_bounds (PikaCanvasItem *item,
|
||||
cairo_rectangle_int_t *bounds)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
GeglBuffer *buffer = GET_PRIVATE (item)->buffer;
|
||||
GeglRectangle extent;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
g_return_if_fail (GEGL_IS_BUFFER (buffer));
|
||||
|
||||
extent = *gegl_buffer_get_extent (buffer);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
extent.x,
|
||||
extent.y,
|
||||
&x1, &y1);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
extent.x + extent.width,
|
||||
extent.y + extent.height,
|
||||
&x2, &y2);
|
||||
|
||||
extent.x = floor (x1);
|
||||
extent.y = floor (y1);
|
||||
extent.width = ceil (x2) - extent.x;
|
||||
extent.height = ceil (y2) - extent.y;
|
||||
|
||||
gegl_rectangle_intersect (&extent,
|
||||
&extent,
|
||||
GEGL_RECTANGLE (0,
|
||||
0,
|
||||
shell->disp_width,
|
||||
shell->disp_height));
|
||||
|
||||
bounds->x = extent.x;
|
||||
bounds->y = extent.y;
|
||||
bounds->width = extent.width;
|
||||
bounds->height = extent.height;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_buffer_preview_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
|
||||
pika_canvas_buffer_preview_compute_bounds (item, &rectangle);
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_buffer_preview_new (PikaDisplayShell *shell,
|
||||
GeglBuffer *buffer)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_BUFFER_PREVIEW,
|
||||
"shell", shell,
|
||||
"buffer", buffer,
|
||||
NULL);
|
||||
}
|
||||
60
app/display/pikacanvasbufferpreview.h
Normal file
60
app/display/pikacanvasbufferpreview.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasbufferpreview.h
|
||||
* Copyright (C) 2013 Marek Dvoroznak <dvoromar@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_BUFFER_PREVIEW_H__
|
||||
#define __PIKA_CANVAS_BUFFER_PREVIEW_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_BUFFER_PREVIEW (pika_canvas_buffer_preview_get_type ())
|
||||
#define PIKA_CANVAS_BUFFER_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_BUFFER_PREVIEW, PikaCanvasBufferPreview))
|
||||
#define PIKA_CANVAS_BUFFER_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_BUFFER_PREVIEW, PikaCanvasBufferPreviewClass))
|
||||
#define PIKA_IS_CANVAS_BUFFER_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_BUFFER_PREVIEW))
|
||||
#define PIKA_IS_CANVAS_BUFFER_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_BUFFER_PREVIEW))
|
||||
#define PIKA_CANVAS_BUFFER_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_BUFFER_PREVIEW, PikaCanvasBufferPreviewClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasBufferPreview PikaCanvasBufferPreview;
|
||||
typedef struct _PikaCanvasBufferPreviewClass PikaCanvasBufferPreviewClass;
|
||||
|
||||
struct _PikaCanvasBufferPreview
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasBufferPreviewClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_buffer_preview_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_buffer_preview_new (PikaDisplayShell *shell,
|
||||
GeglBuffer *buffer);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_BUFFER_PREVIEW_H__ */
|
||||
266
app/display/pikacanvascanvasboundary.c
Normal file
266
app/display/pikacanvascanvasboundary.c
Normal file
@ -0,0 +1,266 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvascanvasboundary.c
|
||||
* Copyright (C) 2019 Ell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvascanvasboundary.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_IMAGE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasCanvasBoundaryPrivate PikaCanvasCanvasBoundaryPrivate;
|
||||
|
||||
struct _PikaCanvasCanvasBoundaryPrivate
|
||||
{
|
||||
PikaImage *image;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(canvas_boundary) \
|
||||
((PikaCanvasCanvasBoundaryPrivate *) pika_canvas_canvas_boundary_get_instance_private ((PikaCanvasCanvasBoundary *) (canvas_boundary)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_canvas_boundary_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_canvas_boundary_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_canvas_boundary_finalize (GObject *object);
|
||||
static void pika_canvas_canvas_boundary_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_canvas_boundary_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_canvas_boundary_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasCanvasBoundary, pika_canvas_canvas_boundary,
|
||||
PIKA_TYPE_CANVAS_RECTANGLE)
|
||||
|
||||
#define parent_class pika_canvas_canvas_boundary_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_class_init (PikaCanvasCanvasBoundaryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_canvas_boundary_set_property;
|
||||
object_class->get_property = pika_canvas_canvas_boundary_get_property;
|
||||
object_class->finalize = pika_canvas_canvas_boundary_finalize;
|
||||
|
||||
item_class->draw = pika_canvas_canvas_boundary_draw;
|
||||
item_class->get_extents = pika_canvas_canvas_boundary_get_extents;
|
||||
item_class->stroke = pika_canvas_canvas_boundary_stroke;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_IMAGE,
|
||||
g_param_spec_object ("image", NULL, NULL,
|
||||
PIKA_TYPE_IMAGE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_init (PikaCanvasCanvasBoundary *canvas_boundary)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_weak_pointer (&private->image);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_IMAGE:
|
||||
g_set_weak_pointer (&private->image, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_IMAGE:
|
||||
g_value_set_object (value, private->image);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->image)
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->draw (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_canvas_boundary_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasCanvasBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->image)
|
||||
return PIKA_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_canvas_boundary_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
|
||||
pika_canvas_set_canvas_style (pika_canvas_item_get_canvas (item), cr,
|
||||
shell->offset_x, shell->offset_y);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_canvas_boundary_new (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_CANVAS_BOUNDARY,
|
||||
"shell", shell,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_canvas_boundary_set_image (PikaCanvasCanvasBoundary *boundary,
|
||||
PikaImage *image)
|
||||
{
|
||||
PikaCanvasCanvasBoundaryPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_CANVAS_BOUNDARY (boundary));
|
||||
g_return_if_fail (image == NULL || PIKA_IS_IMAGE (image));
|
||||
|
||||
private = GET_PRIVATE (boundary);
|
||||
|
||||
if (image != private->image)
|
||||
{
|
||||
pika_canvas_item_begin_change (PIKA_CANVAS_ITEM (boundary));
|
||||
|
||||
if (image)
|
||||
{
|
||||
g_object_set (boundary,
|
||||
"x", (gdouble) 0,
|
||||
"y", (gdouble) 0,
|
||||
"width", (gdouble) pika_image_get_width (image),
|
||||
"height", (gdouble) pika_image_get_height (image),
|
||||
NULL);
|
||||
}
|
||||
|
||||
g_object_set (boundary,
|
||||
"image", image,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (PIKA_CANVAS_ITEM (boundary));
|
||||
}
|
||||
else if (image && image == private->image)
|
||||
{
|
||||
gint lx, ly, lw, lh;
|
||||
gdouble x, y, w ,h;
|
||||
|
||||
lx = 0;
|
||||
ly = 0;
|
||||
lw = pika_image_get_width (image);
|
||||
lh = pika_image_get_height (image);
|
||||
|
||||
g_object_get (boundary,
|
||||
"x", &x,
|
||||
"y", &y,
|
||||
"width", &w,
|
||||
"height", &h,
|
||||
NULL);
|
||||
|
||||
if (lx != (gint) x ||
|
||||
ly != (gint) y ||
|
||||
lw != (gint) w ||
|
||||
lh != (gint) h)
|
||||
{
|
||||
pika_canvas_item_begin_change (PIKA_CANVAS_ITEM (boundary));
|
||||
|
||||
g_object_set (boundary,
|
||||
"x", (gdouble) lx,
|
||||
"y", (gdouble) ly,
|
||||
"width", (gdouble) lw,
|
||||
"height", (gdouble) lh,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (PIKA_CANVAS_ITEM (boundary));
|
||||
}
|
||||
}
|
||||
}
|
||||
62
app/display/pikacanvascanvasboundary.h
Normal file
62
app/display/pikacanvascanvasboundary.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvascanvasvboundary.h
|
||||
* Copyright (C) 2019 Ell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_CANVAS_BOUNDARY_H__
|
||||
#define __PIKA_CANVAS_CANVAS_BOUNDARY_H__
|
||||
|
||||
|
||||
#include "pikacanvasrectangle.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_CANVAS_BOUNDARY (pika_canvas_canvas_boundary_get_type ())
|
||||
#define PIKA_CANVAS_CANVAS_BOUNDARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_CANVAS_BOUNDARY, PikaCanvasCanvasBoundary))
|
||||
#define PIKA_CANVAS_CANVAS_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_CANVAS_BOUNDARY, PikaCanvasCanvasBoundaryClass))
|
||||
#define PIKA_IS_CANVAS_CANVAS_BOUNDARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_CANVAS_BOUNDARY))
|
||||
#define PIKA_IS_CANVAS_CANVAS_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_CANVAS_BOUNDARY))
|
||||
#define PIKA_CANVAS_CANVAS_BOUNDARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_CANVAS_BOUNDARY, PikaCanvasCanvasBoundaryClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasCanvasBoundary PikaCanvasCanvasBoundary;
|
||||
typedef struct _PikaCanvasCanvasBoundaryClass PikaCanvasCanvasBoundaryClass;
|
||||
|
||||
struct _PikaCanvasCanvasBoundary
|
||||
{
|
||||
PikaCanvasRectangle parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasCanvasBoundaryClass
|
||||
{
|
||||
PikaCanvasRectangleClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_canvas_boundary_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_canvas_boundary_new (PikaDisplayShell *shell);
|
||||
|
||||
void pika_canvas_canvas_boundary_set_image (PikaCanvasCanvasBoundary *boundary,
|
||||
PikaImage *image);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_CANVAS_BOUNDARY_H__ */
|
||||
472
app/display/pikacanvascorner.c
Normal file
472
app/display/pikacanvascorner.c
Normal file
@ -0,0 +1,472 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvascorner.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvascorner.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_ANCHOR,
|
||||
PROP_CORNER_WIDTH,
|
||||
PROP_CORNER_HEIGHT,
|
||||
PROP_OUTSIDE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasCornerPrivate PikaCanvasCornerPrivate;
|
||||
|
||||
struct _PikaCanvasCornerPrivate
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble width;
|
||||
gdouble height;
|
||||
PikaHandleAnchor anchor;
|
||||
gint corner_width;
|
||||
gint corner_height;
|
||||
gboolean outside;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(corner) \
|
||||
((PikaCanvasCornerPrivate *) pika_canvas_corner_get_instance_private ((PikaCanvasCorner *) (corner)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_corner_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_corner_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_corner_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_corner_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasCorner, pika_canvas_corner,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_corner_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_corner_class_init (PikaCanvasCornerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_corner_set_property;
|
||||
object_class->get_property = pika_canvas_corner_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_corner_draw;
|
||||
item_class->get_extents = pika_canvas_corner_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WIDTH,
|
||||
g_param_spec_double ("width", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HEIGHT,
|
||||
g_param_spec_double ("height", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ANCHOR,
|
||||
g_param_spec_enum ("anchor", NULL, NULL,
|
||||
PIKA_TYPE_HANDLE_ANCHOR,
|
||||
PIKA_HANDLE_ANCHOR_CENTER,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CORNER_WIDTH,
|
||||
g_param_spec_int ("corner-width", NULL, NULL,
|
||||
3, PIKA_MAX_IMAGE_SIZE, 3,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CORNER_HEIGHT,
|
||||
g_param_spec_int ("corner-height", NULL, NULL,
|
||||
3, PIKA_MAX_IMAGE_SIZE, 3,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OUTSIDE,
|
||||
g_param_spec_boolean ("outside", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_corner_init (PikaCanvasCorner *corner)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_corner_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasCornerPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
private->width = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
private->height = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_ANCHOR:
|
||||
private->anchor = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_CORNER_WIDTH:
|
||||
private->corner_width = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_CORNER_HEIGHT:
|
||||
private->corner_height = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_OUTSIDE:
|
||||
private->outside = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_corner_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasCornerPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
g_value_set_double (value, private->width);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_double (value, private->height);
|
||||
break;
|
||||
case PROP_ANCHOR:
|
||||
g_value_set_enum (value, private->anchor);
|
||||
break;
|
||||
case PROP_CORNER_WIDTH:
|
||||
g_value_set_int (value, private->corner_width);
|
||||
break;
|
||||
case PROP_CORNER_HEIGHT:
|
||||
g_value_set_int (value, private->corner_height);
|
||||
break;
|
||||
case PROP_OUTSIDE:
|
||||
g_value_set_boolean (value, private->outside);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_corner_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y,
|
||||
gdouble *w,
|
||||
gdouble *h)
|
||||
{
|
||||
PikaCanvasCornerPrivate *private = GET_PRIVATE (item);
|
||||
gdouble rx, ry;
|
||||
gdouble rw, rh;
|
||||
gint top_and_bottom_handle_x_offset;
|
||||
gint left_and_right_handle_y_offset;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MIN (private->x,
|
||||
private->x + private->width),
|
||||
MIN (private->y,
|
||||
private->y + private->height),
|
||||
&rx, &ry);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MAX (private->x,
|
||||
private->x + private->width),
|
||||
MAX (private->y,
|
||||
private->y + private->height),
|
||||
&rw, &rh);
|
||||
|
||||
rw -= rx;
|
||||
rh -= ry;
|
||||
|
||||
rx = floor (rx) + 0.5;
|
||||
ry = floor (ry) + 0.5;
|
||||
rw = ceil (rw) - 1.0;
|
||||
rh = ceil (rh) - 1.0;
|
||||
|
||||
top_and_bottom_handle_x_offset = (rw - private->corner_width) / 2;
|
||||
left_and_right_handle_y_offset = (rh - private->corner_height) / 2;
|
||||
|
||||
*w = private->corner_width;
|
||||
*h = private->corner_height;
|
||||
|
||||
switch (private->anchor)
|
||||
{
|
||||
case PIKA_HANDLE_ANCHOR_CENTER:
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH_WEST:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx - private->corner_width;
|
||||
*y = ry - private->corner_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx;
|
||||
*y = ry;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH_EAST:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx + rw;
|
||||
*y = ry - private->corner_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx + rw - private->corner_width;
|
||||
*y = ry;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH_WEST:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx - private->corner_width;
|
||||
*y = ry + rh;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx;
|
||||
*y = ry + rh - private->corner_height;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH_EAST:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx + rw;
|
||||
*y = ry + rh;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx + rw - private->corner_width;
|
||||
*y = ry + rh - private->corner_height;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx;
|
||||
*y = ry - private->corner_height;
|
||||
*w = rw;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx + top_and_bottom_handle_x_offset;
|
||||
*y = ry;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx;
|
||||
*y = ry + rh;
|
||||
*w = rw;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx + top_and_bottom_handle_x_offset;
|
||||
*y = ry + rh - private->corner_height;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_WEST:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx - private->corner_width;
|
||||
*y = ry;
|
||||
*h = rh;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx;
|
||||
*y = ry + left_and_right_handle_y_offset;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_EAST:
|
||||
if (private->outside)
|
||||
{
|
||||
*x = rx + rw;
|
||||
*y = ry;
|
||||
*h = rh;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = rx + rw - private->corner_width;
|
||||
*y = ry + left_and_right_handle_y_offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_corner_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_corner_transform (item, &x, &y, &w, &h);
|
||||
|
||||
cairo_rectangle (cr, x, y, w, h);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_corner_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_corner_transform (item, &x, &y, &w, &h);
|
||||
|
||||
rectangle.x = floor (x - 1.5);
|
||||
rectangle.y = floor (y - 1.5);
|
||||
rectangle.width = ceil (w + 3.0);
|
||||
rectangle.height = ceil (h + 3.0);
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_corner_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
PikaHandleAnchor anchor,
|
||||
gint corner_width,
|
||||
gint corner_height,
|
||||
gboolean outside)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_CORNER,
|
||||
"shell", shell,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"anchor", anchor,
|
||||
"corner-width", corner_width,
|
||||
"corner-height", corner_height,
|
||||
"outside", outside,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_corner_set (PikaCanvasItem *corner,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gint corner_width,
|
||||
gint corner_height,
|
||||
gboolean outside)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_CORNER (corner));
|
||||
|
||||
pika_canvas_item_begin_change (corner);
|
||||
g_object_set (corner,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"corner-width", corner_width,
|
||||
"corner-height", corner_height,
|
||||
"outside", outside,
|
||||
NULL);
|
||||
pika_canvas_item_end_change (corner);
|
||||
}
|
||||
76
app/display/pikacanvascorner.h
Normal file
76
app/display/pikacanvascorner.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvascorner.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_CORNER_H__
|
||||
#define __PIKA_CANVAS_CORNER_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_CORNER (pika_canvas_corner_get_type ())
|
||||
#define PIKA_CANVAS_CORNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_CORNER, PikaCanvasCorner))
|
||||
#define PIKA_CANVAS_CORNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_CORNER, PikaCanvasCornerClass))
|
||||
#define PIKA_IS_CANVAS_CORNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_CORNER))
|
||||
#define PIKA_IS_CANVAS_CORNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_CORNER))
|
||||
#define PIKA_CANVAS_CORNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_CORNER, PikaCanvasCornerClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasCorner PikaCanvasCorner;
|
||||
typedef struct _PikaCanvasCornerClass PikaCanvasCornerClass;
|
||||
|
||||
struct _PikaCanvasCorner
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasCornerClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_corner_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_corner_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
PikaHandleAnchor anchor,
|
||||
gint corner_width,
|
||||
gint corner_height,
|
||||
gboolean outside);
|
||||
|
||||
void pika_canvas_corner_set (PikaCanvasItem *corner,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gint corner_width,
|
||||
gint corner_height,
|
||||
gboolean outside);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_CORNER_H__ */
|
||||
232
app/display/pikacanvascursor.c
Normal file
232
app/display/pikacanvascursor.c
Normal file
@ -0,0 +1,232 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvascursor.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
|
||||
#include "pikacanvascursor.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define PIKA_CURSOR_SIZE 7
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasCursorPrivate PikaCanvasCursorPrivate;
|
||||
|
||||
struct _PikaCanvasCursorPrivate
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(cursor) \
|
||||
((PikaCanvasCursorPrivate *) pika_canvas_cursor_get_instance_private ((PikaCanvasCursor *) (cursor)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_cursor_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_cursor_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_cursor_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_cursor_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasCursor, pika_canvas_cursor,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_cursor_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_cursor_class_init (PikaCanvasCursorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_cursor_set_property;
|
||||
object_class->get_property = pika_canvas_cursor_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_cursor_draw;
|
||||
item_class->get_extents = pika_canvas_cursor_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_cursor_init (PikaCanvasCursor *cursor)
|
||||
{
|
||||
pika_canvas_item_set_line_cap (PIKA_CANVAS_ITEM (cursor),
|
||||
CAIRO_LINE_CAP_SQUARE);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_cursor_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasCursorPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_cursor_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasCursorPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_cursor_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasCursorPrivate *private = GET_PRIVATE (item);
|
||||
gdouble x, y;
|
||||
|
||||
x = floor (private->x) + 0.5;
|
||||
y = floor (private->y) + 0.5;
|
||||
|
||||
cairo_move_to (cr, x - PIKA_CURSOR_SIZE, y);
|
||||
cairo_line_to (cr, x + PIKA_CURSOR_SIZE, y);
|
||||
|
||||
cairo_move_to (cr, x, y - PIKA_CURSOR_SIZE);
|
||||
cairo_line_to (cr, x, y + PIKA_CURSOR_SIZE);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_cursor_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasCursorPrivate *private = GET_PRIVATE (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x, y;
|
||||
|
||||
x = floor (private->x) + 0.5;
|
||||
y = floor (private->y) + 0.5;
|
||||
|
||||
rectangle.x = floor (x - PIKA_CURSOR_SIZE - 1.5);
|
||||
rectangle.y = floor (y - PIKA_CURSOR_SIZE - 1.5);
|
||||
rectangle.width = ceil (x + PIKA_CURSOR_SIZE + 1.5) - rectangle.x;
|
||||
rectangle.height = ceil (y + PIKA_CURSOR_SIZE + 1.5) - rectangle.y;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_cursor_new (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_CURSOR,
|
||||
"shell", shell,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_cursor_set (PikaCanvasItem *cursor,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasCursorPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_CURSOR (cursor));
|
||||
|
||||
private = GET_PRIVATE (cursor);
|
||||
|
||||
if (private->x != x || private->y != y)
|
||||
{
|
||||
pika_canvas_item_begin_change (cursor);
|
||||
|
||||
g_object_set (cursor,
|
||||
"x", x,
|
||||
"y", y,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (cursor);
|
||||
}
|
||||
}
|
||||
63
app/display/pikacanvascursor.h
Normal file
63
app/display/pikacanvascursor.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvascursor.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_CURSOR_H__
|
||||
#define __PIKA_CANVAS_CURSOR_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_CURSOR (pika_canvas_cursor_get_type ())
|
||||
#define PIKA_CANVAS_CURSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_CURSOR, PikaCanvasCursor))
|
||||
#define PIKA_CANVAS_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_CURSOR, PikaCanvasCursorClass))
|
||||
#define PIKA_IS_CANVAS_CURSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_CURSOR))
|
||||
#define PIKA_IS_CANVAS_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_CURSOR))
|
||||
#define PIKA_CANVAS_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_CURSOR, PikaCanvasCursorClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasCursor PikaCanvasCursor;
|
||||
typedef struct _PikaCanvasCursorClass PikaCanvasCursorClass;
|
||||
|
||||
struct _PikaCanvasCursor
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasCursorClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_cursor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_cursor_new (PikaDisplayShell *shell);
|
||||
|
||||
void pika_canvas_cursor_set (PikaCanvasItem *cursor,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_CURSOR_H__ */
|
||||
418
app/display/pikacanvasgrid.c
Normal file
418
app/display/pikacanvasgrid.c
Normal file
@ -0,0 +1,418 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasgrid.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikagrid.h"
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvasgrid.h"
|
||||
#include "pikacanvasitem-utils.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-scale.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_GRID,
|
||||
PROP_GRID_STYLE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasGridPrivate PikaCanvasGridPrivate;
|
||||
|
||||
struct _PikaCanvasGridPrivate
|
||||
{
|
||||
PikaGrid *grid;
|
||||
gboolean grid_style;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(grid) \
|
||||
((PikaCanvasGridPrivate *) pika_canvas_grid_get_instance_private ((PikaCanvasGrid *) (grid)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_grid_finalize (GObject *object);
|
||||
static void pika_canvas_grid_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_grid_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_grid_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_grid_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_grid_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasGrid, pika_canvas_grid,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_grid_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_grid_class_init (PikaCanvasGridClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_grid_finalize;
|
||||
object_class->set_property = pika_canvas_grid_set_property;
|
||||
object_class->get_property = pika_canvas_grid_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_grid_draw;
|
||||
item_class->get_extents = pika_canvas_grid_get_extents;
|
||||
item_class->stroke = pika_canvas_grid_stroke;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GRID,
|
||||
g_param_spec_object ("grid", NULL, NULL,
|
||||
PIKA_TYPE_GRID,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GRID_STYLE,
|
||||
g_param_spec_boolean ("grid-style",
|
||||
NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_grid_init (PikaCanvasGrid *grid)
|
||||
{
|
||||
PikaCanvasGridPrivate *private = GET_PRIVATE (grid);
|
||||
|
||||
private->grid = g_object_new (PIKA_TYPE_GRID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_grid_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasGridPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_object (&private->grid);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_grid_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasGridPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GRID:
|
||||
{
|
||||
PikaGrid *grid = g_value_get_object (value);
|
||||
if (grid)
|
||||
pika_config_sync (G_OBJECT (grid), G_OBJECT (private->grid), 0);
|
||||
}
|
||||
break;
|
||||
case PROP_GRID_STYLE:
|
||||
private->grid_style = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_grid_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasGridPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GRID:
|
||||
g_value_set_object (value, private->grid);
|
||||
break;
|
||||
case PROP_GRID_STYLE:
|
||||
g_value_set_boolean (value, private->grid_style);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_grid_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasGridPrivate *private = GET_PRIVATE (item);
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
gdouble xspacing, yspacing;
|
||||
gdouble xoffset, yoffset;
|
||||
gboolean vert, horz;
|
||||
gdouble dx1, dy1, dx2, dy2;
|
||||
gint x1, y1, x2, y2;
|
||||
gdouble dx, dy;
|
||||
gint x, y;
|
||||
|
||||
#define CROSSHAIR 2
|
||||
|
||||
pika_grid_get_spacing (private->grid, &xspacing, &yspacing);
|
||||
pika_grid_get_offset (private->grid, &xoffset, &yoffset);
|
||||
|
||||
g_return_if_fail (xspacing >= 0.0 &&
|
||||
yspacing >= 0.0);
|
||||
|
||||
xspacing *= shell->scale_x;
|
||||
yspacing *= shell->scale_y;
|
||||
|
||||
xoffset *= shell->scale_x;
|
||||
yoffset *= shell->scale_y;
|
||||
|
||||
/* skip grid drawing when the space between grid lines starts
|
||||
* disappearing, see bug #599267.
|
||||
*/
|
||||
vert = (xspacing >= 2.0);
|
||||
horz = (yspacing >= 2.0);
|
||||
|
||||
if (! vert && ! horz)
|
||||
return;
|
||||
|
||||
cairo_clip_extents (cr, &dx1, &dy1, &dx2, &dy2);
|
||||
|
||||
x1 = floor (dx1) - 1;
|
||||
y1 = floor (dy1) - 1;
|
||||
x2 = ceil (dx2) + 1;
|
||||
y2 = ceil (dy2) + 1;
|
||||
|
||||
if (! pika_display_shell_get_infinite_canvas (shell))
|
||||
{
|
||||
GeglRectangle bounds;
|
||||
|
||||
pika_display_shell_scale_get_image_unrotated_bounds (
|
||||
shell,
|
||||
&bounds.x, &bounds.y, &bounds.width, &bounds.height);
|
||||
|
||||
if (! gegl_rectangle_intersect (&bounds,
|
||||
&bounds,
|
||||
GEGL_RECTANGLE (x1, y1,
|
||||
x2 - x1, y2 - y1)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
x1 = bounds.x;
|
||||
y1 = bounds.y;
|
||||
x2 = bounds.x + bounds.width;
|
||||
y2 = bounds.y + bounds.height;
|
||||
}
|
||||
|
||||
switch (pika_grid_get_style (private->grid))
|
||||
{
|
||||
case PIKA_GRID_INTERSECTIONS:
|
||||
x1 -= CROSSHAIR;
|
||||
y1 -= CROSSHAIR;
|
||||
x2 += CROSSHAIR;
|
||||
y2 += CROSSHAIR;
|
||||
break;
|
||||
|
||||
case PIKA_GRID_DOTS:
|
||||
case PIKA_GRID_ON_OFF_DASH:
|
||||
case PIKA_GRID_DOUBLE_DASH:
|
||||
case PIKA_GRID_SOLID:
|
||||
break;
|
||||
}
|
||||
|
||||
xoffset = fmod (xoffset - shell->offset_x - x1, xspacing);
|
||||
yoffset = fmod (yoffset - shell->offset_y - y1, yspacing);
|
||||
|
||||
if (xoffset < 0.0)
|
||||
xoffset += xspacing;
|
||||
|
||||
if (yoffset < 0.0)
|
||||
yoffset += yspacing;
|
||||
|
||||
switch (pika_grid_get_style (private->grid))
|
||||
{
|
||||
case PIKA_GRID_DOTS:
|
||||
if (vert && horz)
|
||||
{
|
||||
for (dx = x1 + xoffset; dx <= x2; dx += xspacing)
|
||||
{
|
||||
x = RINT (dx);
|
||||
|
||||
for (dy = y1 + yoffset; dy <= y2; dy += yspacing)
|
||||
{
|
||||
y = RINT (dy);
|
||||
|
||||
cairo_move_to (cr, x, y + 0.5);
|
||||
cairo_line_to (cr, x + 1.0, y + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GRID_INTERSECTIONS:
|
||||
if (vert && horz)
|
||||
{
|
||||
for (dx = x1 + xoffset; dx <= x2; dx += xspacing)
|
||||
{
|
||||
x = RINT (dx);
|
||||
|
||||
for (dy = y1 + yoffset; dy <= y2; dy += yspacing)
|
||||
{
|
||||
y = RINT (dy);
|
||||
|
||||
cairo_move_to (cr, x + 0.5, y - CROSSHAIR);
|
||||
cairo_line_to (cr, x + 0.5, y + CROSSHAIR + 1.0);
|
||||
|
||||
cairo_move_to (cr, x - CROSSHAIR, y + 0.5);
|
||||
cairo_line_to (cr, x + CROSSHAIR + 1.0, y + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GRID_ON_OFF_DASH:
|
||||
case PIKA_GRID_DOUBLE_DASH:
|
||||
case PIKA_GRID_SOLID:
|
||||
if (vert)
|
||||
{
|
||||
for (dx = x1 + xoffset; dx < x2; dx += xspacing)
|
||||
{
|
||||
x = RINT (dx);
|
||||
|
||||
cairo_move_to (cr, x + 0.5, y1);
|
||||
cairo_line_to (cr, x + 0.5, y2);
|
||||
}
|
||||
}
|
||||
|
||||
if (horz)
|
||||
{
|
||||
for (dy = y1 + yoffset; dy < y2; dy += yspacing)
|
||||
{
|
||||
y = RINT (dy);
|
||||
|
||||
cairo_move_to (cr, x1, y + 0.5);
|
||||
cairo_line_to (cr, x2, y + 0.5);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_grid_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
PikaImage *image = pika_canvas_item_get_image (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
|
||||
if (! image)
|
||||
return NULL;
|
||||
|
||||
if (! pika_display_shell_get_infinite_canvas (shell))
|
||||
{
|
||||
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
gint w, h;
|
||||
|
||||
w = pika_image_get_width (image);
|
||||
h = pika_image_get_height (image);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item, 0, 0, &x1, &y1);
|
||||
pika_canvas_item_transform_xy_f (item, w, h, &x2, &y2);
|
||||
|
||||
rectangle.x = floor (x1);
|
||||
rectangle.y = floor (y1);
|
||||
rectangle.width = ceil (x2) - rectangle.x;
|
||||
rectangle.height = ceil (y2) - rectangle.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_canvas_item_untransform_viewport (item,
|
||||
&rectangle.x,
|
||||
&rectangle.y,
|
||||
&rectangle.width,
|
||||
&rectangle.height);
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_grid_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasGridPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->grid_style)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
|
||||
pika_canvas_set_grid_style (pika_canvas_item_get_canvas (item), cr,
|
||||
private->grid,
|
||||
shell->offset_x, shell->offset_y);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->stroke (item, cr);
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_grid_new (PikaDisplayShell *shell,
|
||||
PikaGrid *grid)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (grid == NULL || PIKA_IS_GRID (grid), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_GRID,
|
||||
"shell", shell,
|
||||
"grid", grid,
|
||||
NULL);
|
||||
}
|
||||
60
app/display/pikacanvasgrid.h
Normal file
60
app/display/pikacanvasgrid.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasgrid.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_GRID_H__
|
||||
#define __PIKA_CANVAS_GRID_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_GRID (pika_canvas_grid_get_type ())
|
||||
#define PIKA_CANVAS_GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_GRID, PikaCanvasGrid))
|
||||
#define PIKA_CANVAS_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_GRID, PikaCanvasGridClass))
|
||||
#define PIKA_IS_CANVAS_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_GRID))
|
||||
#define PIKA_IS_CANVAS_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_GRID))
|
||||
#define PIKA_CANVAS_GRID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_GRID, PikaCanvasGridClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasGrid PikaCanvasGrid;
|
||||
typedef struct _PikaCanvasGridClass PikaCanvasGridClass;
|
||||
|
||||
struct _PikaCanvasGrid
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasGridClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_grid_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_grid_new (PikaDisplayShell *shell,
|
||||
PikaGrid *grid);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_GRID_H__ */
|
||||
391
app/display/pikacanvasgroup.c
Normal file
391
app/display/pikacanvasgroup.c
Normal file
@ -0,0 +1,391 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasgroup.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvasgroup.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_GROUP_STROKING,
|
||||
PROP_GROUP_FILLING
|
||||
};
|
||||
|
||||
|
||||
struct _PikaCanvasGroupPrivate
|
||||
{
|
||||
GQueue *items;
|
||||
gboolean group_stroking;
|
||||
gboolean group_filling;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_group_finalize (GObject *object);
|
||||
static void pika_canvas_group_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_group_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_group_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_group_get_extents (PikaCanvasItem *item);
|
||||
static gboolean pika_canvas_group_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
static void pika_canvas_group_child_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region,
|
||||
PikaCanvasGroup *group);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasGroup, pika_canvas_group,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_group_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_group_class_init (PikaCanvasGroupClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_group_finalize;
|
||||
object_class->set_property = pika_canvas_group_set_property;
|
||||
object_class->get_property = pika_canvas_group_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_group_draw;
|
||||
item_class->get_extents = pika_canvas_group_get_extents;
|
||||
item_class->hit = pika_canvas_group_hit;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GROUP_STROKING,
|
||||
g_param_spec_boolean ("group-stroking",
|
||||
NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GROUP_FILLING,
|
||||
g_param_spec_boolean ("group-filling",
|
||||
NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_group_init (PikaCanvasGroup *group)
|
||||
{
|
||||
group->priv = pika_canvas_group_get_instance_private (group);
|
||||
|
||||
group->priv->items = g_queue_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_group_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasGroup *group = PIKA_CANVAS_GROUP (object);
|
||||
PikaCanvasItem *item;
|
||||
|
||||
while ((item = g_queue_peek_head (group->priv->items)))
|
||||
pika_canvas_group_remove_item (group, item);
|
||||
|
||||
g_queue_free (group->priv->items);
|
||||
group->priv->items = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_group_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasGroup *group = PIKA_CANVAS_GROUP (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GROUP_STROKING:
|
||||
group->priv->group_stroking = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_GROUP_FILLING:
|
||||
group->priv->group_filling = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_group_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasGroup *group = PIKA_CANVAS_GROUP (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GROUP_STROKING:
|
||||
g_value_set_boolean (value, group->priv->group_stroking);
|
||||
break;
|
||||
case PROP_GROUP_FILLING:
|
||||
g_value_set_boolean (value, group->priv->group_filling);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_group_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasGroup *group = PIKA_CANVAS_GROUP (item);
|
||||
GList *list;
|
||||
|
||||
for (list = group->priv->items->head; list; list = g_list_next (list))
|
||||
{
|
||||
PikaCanvasItem *sub_item = list->data;
|
||||
|
||||
pika_canvas_item_draw (sub_item, cr);
|
||||
}
|
||||
|
||||
if (group->priv->group_stroking)
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
if (group->priv->group_filling)
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_group_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasGroup *group = PIKA_CANVAS_GROUP (item);
|
||||
cairo_region_t *region = NULL;
|
||||
GList *list;
|
||||
|
||||
for (list = group->priv->items->head; list; list = g_list_next (list))
|
||||
{
|
||||
PikaCanvasItem *sub_item = list->data;
|
||||
cairo_region_t *sub_region = pika_canvas_item_get_extents (sub_item);
|
||||
|
||||
if (! region)
|
||||
{
|
||||
region = sub_region;
|
||||
}
|
||||
else if (sub_region)
|
||||
{
|
||||
cairo_region_union (region, sub_region);
|
||||
cairo_region_destroy (sub_region);
|
||||
}
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_group_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasGroup *group = PIKA_CANVAS_GROUP (item);
|
||||
GList *list;
|
||||
|
||||
for (list = group->priv->items->head; list; list = g_list_next (list))
|
||||
{
|
||||
if (pika_canvas_item_hit (list->data, x, y))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_group_child_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region,
|
||||
PikaCanvasGroup *group)
|
||||
{
|
||||
if (_pika_canvas_item_needs_update (PIKA_CANVAS_ITEM (group)))
|
||||
_pika_canvas_item_update (PIKA_CANVAS_ITEM (group), region);
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_group_new (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_GROUP,
|
||||
"shell", shell,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_group_add_item (PikaCanvasGroup *group,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GROUP (group));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
g_return_if_fail (PIKA_CANVAS_ITEM (group) != item);
|
||||
|
||||
if (group->priv->group_stroking)
|
||||
pika_canvas_item_suspend_stroking (item);
|
||||
|
||||
if (group->priv->group_filling)
|
||||
pika_canvas_item_suspend_filling (item);
|
||||
|
||||
g_queue_push_tail (group->priv->items, g_object_ref (item));
|
||||
|
||||
if (_pika_canvas_item_needs_update (PIKA_CANVAS_ITEM (group)))
|
||||
{
|
||||
cairo_region_t *region = pika_canvas_item_get_extents (item);
|
||||
|
||||
if (region)
|
||||
{
|
||||
_pika_canvas_item_update (PIKA_CANVAS_ITEM (group), region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_connect (item, "update",
|
||||
G_CALLBACK (pika_canvas_group_child_update),
|
||||
group);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_group_remove_item (PikaCanvasGroup *group,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GROUP (group));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
list = g_queue_find (group->priv->items, item);
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
|
||||
g_queue_delete_link (group->priv->items, list);
|
||||
|
||||
if (group->priv->group_stroking)
|
||||
pika_canvas_item_resume_stroking (item);
|
||||
|
||||
if (group->priv->group_filling)
|
||||
pika_canvas_item_resume_filling (item);
|
||||
|
||||
if (_pika_canvas_item_needs_update (PIKA_CANVAS_ITEM (group)))
|
||||
{
|
||||
cairo_region_t *region = pika_canvas_item_get_extents (item);
|
||||
|
||||
if (region)
|
||||
{
|
||||
_pika_canvas_item_update (PIKA_CANVAS_ITEM (group), region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func (item,
|
||||
pika_canvas_group_child_update,
|
||||
group);
|
||||
|
||||
g_object_unref (item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_group_set_group_stroking (PikaCanvasGroup *group,
|
||||
gboolean group_stroking)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GROUP (group));
|
||||
|
||||
if (group->priv->group_stroking != group_stroking)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
pika_canvas_item_begin_change (PIKA_CANVAS_ITEM (group));
|
||||
|
||||
g_object_set (group,
|
||||
"group-stroking", group_stroking ? TRUE : FALSE,
|
||||
NULL);
|
||||
|
||||
for (list = group->priv->items->head; list; list = g_list_next (list))
|
||||
{
|
||||
if (group->priv->group_stroking)
|
||||
pika_canvas_item_suspend_stroking (list->data);
|
||||
else
|
||||
pika_canvas_item_resume_stroking (list->data);
|
||||
}
|
||||
|
||||
pika_canvas_item_end_change (PIKA_CANVAS_ITEM (group));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_group_set_group_filling (PikaCanvasGroup *group,
|
||||
gboolean group_filling)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GROUP (group));
|
||||
|
||||
if (group->priv->group_filling != group_filling)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
pika_canvas_item_begin_change (PIKA_CANVAS_ITEM (group));
|
||||
|
||||
g_object_set (group,
|
||||
"group-filling", group_filling ? TRUE : FALSE,
|
||||
NULL);
|
||||
|
||||
for (list = group->priv->items->head; list; list = g_list_next (list))
|
||||
{
|
||||
if (group->priv->group_filling)
|
||||
pika_canvas_item_suspend_filling (list->data);
|
||||
else
|
||||
pika_canvas_item_resume_filling (list->data);
|
||||
}
|
||||
|
||||
pika_canvas_item_end_change (PIKA_CANVAS_ITEM (group));
|
||||
}
|
||||
}
|
||||
72
app/display/pikacanvasgroup.h
Normal file
72
app/display/pikacanvasgroup.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasgroup.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_GROUP_H__
|
||||
#define __PIKA_CANVAS_GROUP_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_GROUP (pika_canvas_group_get_type ())
|
||||
#define PIKA_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_GROUP, PikaCanvasGroup))
|
||||
#define PIKA_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_GROUP, PikaCanvasGroupClass))
|
||||
#define PIKA_IS_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_GROUP))
|
||||
#define PIKA_IS_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_GROUP))
|
||||
#define PIKA_CANVAS_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_GROUP, PikaCanvasGroupClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasGroupPrivate PikaCanvasGroupPrivate;
|
||||
typedef struct _PikaCanvasGroupClass PikaCanvasGroupClass;
|
||||
|
||||
struct _PikaCanvasGroup
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
|
||||
PikaCanvasGroupPrivate *priv;
|
||||
|
||||
};
|
||||
|
||||
struct _PikaCanvasGroupClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_group_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_group_new (PikaDisplayShell *shell);
|
||||
|
||||
void pika_canvas_group_add_item (PikaCanvasGroup *group,
|
||||
PikaCanvasItem *item);
|
||||
void pika_canvas_group_remove_item (PikaCanvasGroup *group,
|
||||
PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_group_set_group_stroking (PikaCanvasGroup *group,
|
||||
gboolean group_stroking);
|
||||
void pika_canvas_group_set_group_filling (PikaCanvasGroup *group,
|
||||
gboolean group_filling);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_GROUP_H__ */
|
||||
299
app/display/pikacanvasguide.c
Normal file
299
app/display/pikacanvasguide.c
Normal file
@ -0,0 +1,299 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasguide.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvasguide.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ORIENTATION,
|
||||
PROP_POSITION,
|
||||
PROP_STYLE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasGuidePrivate PikaCanvasGuidePrivate;
|
||||
|
||||
struct _PikaCanvasGuidePrivate
|
||||
{
|
||||
PikaOrientationType orientation;
|
||||
gint position;
|
||||
|
||||
PikaGuideStyle style;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(guide) \
|
||||
((PikaCanvasGuidePrivate *) pika_canvas_guide_get_instance_private ((PikaCanvasGuide *) (guide)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_guide_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_guide_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_guide_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_guide_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_guide_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasGuide, pika_canvas_guide,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_guide_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_guide_class_init (PikaCanvasGuideClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_guide_set_property;
|
||||
object_class->get_property = pika_canvas_guide_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_guide_draw;
|
||||
item_class->get_extents = pika_canvas_guide_get_extents;
|
||||
item_class->stroke = pika_canvas_guide_stroke;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ORIENTATION,
|
||||
g_param_spec_enum ("orientation", NULL, NULL,
|
||||
PIKA_TYPE_ORIENTATION_TYPE,
|
||||
PIKA_ORIENTATION_HORIZONTAL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_POSITION,
|
||||
g_param_spec_int ("position", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_STYLE,
|
||||
g_param_spec_enum ("style", NULL, NULL,
|
||||
PIKA_TYPE_GUIDE_STYLE,
|
||||
PIKA_GUIDE_STYLE_NONE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_guide_init (PikaCanvasGuide *guide)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_guide_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasGuidePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
private->orientation = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_POSITION:
|
||||
private->position = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_STYLE:
|
||||
private->style = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_guide_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasGuidePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, private->orientation);
|
||||
break;
|
||||
case PROP_POSITION:
|
||||
g_value_set_int (value, private->position);
|
||||
break;
|
||||
case PROP_STYLE:
|
||||
g_value_set_enum (value, private->style);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_guide_transform (PikaCanvasItem *item,
|
||||
gdouble *x1,
|
||||
gdouble *y1,
|
||||
gdouble *x2,
|
||||
gdouble *y2)
|
||||
{
|
||||
PikaCanvasGuidePrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
GtkAllocation allocation;
|
||||
gint max_outside;
|
||||
gint x, y;
|
||||
|
||||
gtk_widget_get_allocation (canvas, &allocation);
|
||||
|
||||
max_outside = allocation.width + allocation.height;
|
||||
|
||||
*x1 = -max_outside;
|
||||
*y1 = -max_outside;
|
||||
*x2 = allocation.width + max_outside;
|
||||
*y2 = allocation.height + max_outside;
|
||||
|
||||
switch (private->orientation)
|
||||
{
|
||||
case PIKA_ORIENTATION_HORIZONTAL:
|
||||
pika_canvas_item_transform_xy (item, 0, private->position, &x, &y);
|
||||
*y1 = *y2 = y + 0.5;
|
||||
break;
|
||||
|
||||
case PIKA_ORIENTATION_VERTICAL:
|
||||
pika_canvas_item_transform_xy (item, private->position, 0, &x, &y);
|
||||
*x1 = *x2 = x + 0.5;
|
||||
break;
|
||||
|
||||
case PIKA_ORIENTATION_UNKNOWN:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_guide_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_guide_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
cairo_move_to (cr, x1, y1);
|
||||
cairo_line_to (cr, x2, y2);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_guide_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_guide_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
rectangle.x = MIN (x1, x2) - 1.5;
|
||||
rectangle.y = MIN (y1, y2) - 1.5;
|
||||
rectangle.width = ABS (x2 - x1) + 3.0;
|
||||
rectangle.height = ABS (y2 - y1) + 3.0;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_guide_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasGuidePrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->style != PIKA_GUIDE_STYLE_NONE)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
|
||||
pika_canvas_set_guide_style (pika_canvas_item_get_canvas (item), cr,
|
||||
private->style,
|
||||
pika_canvas_item_get_highlight (item),
|
||||
shell->offset_x, shell->offset_y);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->stroke (item, cr);
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_guide_new (PikaDisplayShell *shell,
|
||||
PikaOrientationType orientation,
|
||||
gint position,
|
||||
PikaGuideStyle style)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_GUIDE,
|
||||
"shell", shell,
|
||||
"orientation", orientation,
|
||||
"position", position,
|
||||
"style", style,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_guide_set (PikaCanvasItem *guide,
|
||||
PikaOrientationType orientation,
|
||||
gint position)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GUIDE (guide));
|
||||
|
||||
pika_canvas_item_begin_change (guide);
|
||||
|
||||
g_object_set (guide,
|
||||
"orientation", orientation,
|
||||
"position", position,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (guide);
|
||||
}
|
||||
66
app/display/pikacanvasguide.h
Normal file
66
app/display/pikacanvasguide.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasguide.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_GUIDE_H__
|
||||
#define __PIKA_CANVAS_GUIDE_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_GUIDE (pika_canvas_guide_get_type ())
|
||||
#define PIKA_CANVAS_GUIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_GUIDE, PikaCanvasGuide))
|
||||
#define PIKA_CANVAS_GUIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_GUIDE, PikaCanvasGuideClass))
|
||||
#define PIKA_IS_CANVAS_GUIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_GUIDE))
|
||||
#define PIKA_IS_CANVAS_GUIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_GUIDE))
|
||||
#define PIKA_CANVAS_GUIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_GUIDE, PikaCanvasGuideClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasGuide PikaCanvasGuide;
|
||||
typedef struct _PikaCanvasGuideClass PikaCanvasGuideClass;
|
||||
|
||||
struct _PikaCanvasGuide
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasGuideClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_guide_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_guide_new (PikaDisplayShell *shell,
|
||||
PikaOrientationType orientation,
|
||||
gint position,
|
||||
PikaGuideStyle style);
|
||||
|
||||
void pika_canvas_guide_set (PikaCanvasItem *guide,
|
||||
PikaOrientationType orientation,
|
||||
gint position);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_GUIDE_H__ */
|
||||
733
app/display/pikacanvashandle.c
Normal file
733
app/display/pikacanvashandle.c
Normal file
@ -0,0 +1,733 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvashandle.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
|
||||
#include "pikacanvashandle.h"
|
||||
#include "pikacanvasitem-utils.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define N_DASHES 8
|
||||
#define DASH_ON_RATIO 0.3
|
||||
#define DASH_OFF_RATIO 0.7
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TYPE,
|
||||
PROP_ANCHOR,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_START_ANGLE,
|
||||
PROP_SLICE_ANGLE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasHandlePrivate PikaCanvasHandlePrivate;
|
||||
|
||||
struct _PikaCanvasHandlePrivate
|
||||
{
|
||||
PikaHandleType type;
|
||||
PikaHandleAnchor anchor;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble start_angle;
|
||||
gdouble slice_angle;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(handle) \
|
||||
((PikaCanvasHandlePrivate *) pika_canvas_handle_get_instance_private ((PikaCanvasHandle *) (handle)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_handle_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_handle_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_handle_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_handle_get_extents (PikaCanvasItem *item);
|
||||
static gboolean pika_canvas_handle_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasHandle, pika_canvas_handle,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_handle_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_handle_class_init (PikaCanvasHandleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_handle_set_property;
|
||||
object_class->get_property = pika_canvas_handle_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_handle_draw;
|
||||
item_class->get_extents = pika_canvas_handle_get_extents;
|
||||
item_class->hit = pika_canvas_handle_hit;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TYPE,
|
||||
g_param_spec_enum ("type", NULL, NULL,
|
||||
PIKA_TYPE_HANDLE_TYPE,
|
||||
PIKA_HANDLE_CROSS,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ANCHOR,
|
||||
g_param_spec_enum ("anchor", NULL, NULL,
|
||||
PIKA_TYPE_HANDLE_ANCHOR,
|
||||
PIKA_HANDLE_ANCHOR_CENTER,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WIDTH,
|
||||
g_param_spec_int ("width", NULL, NULL,
|
||||
3, 1001, 7,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HEIGHT,
|
||||
g_param_spec_int ("height", NULL, NULL,
|
||||
3, 1001, 7,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_START_ANGLE,
|
||||
g_param_spec_double ("start-angle", NULL, NULL,
|
||||
-1000, 1000, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SLICE_ANGLE,
|
||||
g_param_spec_double ("slice-angle", NULL, NULL,
|
||||
-1000, 1000, 2 * G_PI,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_handle_init (PikaCanvasHandle *handle)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (handle);
|
||||
|
||||
pika_canvas_item_set_line_cap (PIKA_CANVAS_ITEM (handle),
|
||||
CAIRO_LINE_CAP_SQUARE);
|
||||
|
||||
private->start_angle = 0.0;
|
||||
private->slice_angle = 2.0 * G_PI;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_handle_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TYPE:
|
||||
private->type = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_ANCHOR:
|
||||
private->anchor = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
private->width = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
private->height = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_START_ANGLE:
|
||||
private->start_angle = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_SLICE_ANGLE:
|
||||
private->slice_angle = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_handle_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TYPE:
|
||||
g_value_set_enum (value, private->type);
|
||||
break;
|
||||
case PROP_ANCHOR:
|
||||
g_value_set_enum (value, private->anchor);
|
||||
break;
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
g_value_set_int (value, private->width);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_int (value, private->height);
|
||||
break;
|
||||
case PROP_START_ANGLE:
|
||||
g_value_set_double (value, private->start_angle);
|
||||
break;
|
||||
case PROP_SLICE_ANGLE:
|
||||
g_value_set_double (value, private->slice_angle);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_handle_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x, private->y,
|
||||
x, y);
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_HANDLE_SQUARE:
|
||||
case PIKA_HANDLE_DASHED_SQUARE:
|
||||
case PIKA_HANDLE_FILLED_SQUARE:
|
||||
pika_canvas_item_shift_to_north_west (private->anchor,
|
||||
*x, *y,
|
||||
private->width,
|
||||
private->height,
|
||||
x, y);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_CIRCLE:
|
||||
case PIKA_HANDLE_DASHED_CIRCLE:
|
||||
case PIKA_HANDLE_FILLED_CIRCLE:
|
||||
case PIKA_HANDLE_CROSS:
|
||||
case PIKA_HANDLE_CROSSHAIR:
|
||||
case PIKA_HANDLE_DIAMOND:
|
||||
case PIKA_HANDLE_DASHED_DIAMOND:
|
||||
case PIKA_HANDLE_FILLED_DIAMOND:
|
||||
case PIKA_HANDLE_DROP:
|
||||
case PIKA_HANDLE_FILLED_DROP:
|
||||
pika_canvas_item_shift_to_center (private->anchor,
|
||||
*x, *y,
|
||||
private->width,
|
||||
private->height,
|
||||
x, y);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*x = floor (*x) + 0.5;
|
||||
*y = floor (*y) + 0.5;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_handle_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (item);
|
||||
gdouble x, y, tx, ty;
|
||||
|
||||
pika_canvas_handle_transform (item, &x, &y);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x, private->y,
|
||||
&tx, &ty);
|
||||
|
||||
tx = floor (tx) + 0.5;
|
||||
ty = floor (ty) + 0.5;
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_HANDLE_SQUARE:
|
||||
case PIKA_HANDLE_DASHED_SQUARE:
|
||||
case PIKA_HANDLE_FILLED_SQUARE:
|
||||
case PIKA_HANDLE_DIAMOND:
|
||||
case PIKA_HANDLE_DASHED_DIAMOND:
|
||||
case PIKA_HANDLE_FILLED_DIAMOND:
|
||||
case PIKA_HANDLE_CROSS:
|
||||
case PIKA_HANDLE_DROP:
|
||||
case PIKA_HANDLE_FILLED_DROP:
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, tx, ty);
|
||||
cairo_rotate (cr, private->start_angle);
|
||||
cairo_translate (cr, -tx, -ty);
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_HANDLE_SQUARE:
|
||||
case PIKA_HANDLE_DASHED_SQUARE:
|
||||
if (private->type == PIKA_HANDLE_DASHED_SQUARE)
|
||||
{
|
||||
gdouble circ;
|
||||
gdouble dashes[2];
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
circ = 2.0 * ((private->width - 1.0) + (private->height - 1.0));
|
||||
|
||||
dashes[0] = (circ / N_DASHES) * DASH_ON_RATIO;
|
||||
dashes[1] = (circ / N_DASHES) * DASH_OFF_RATIO;
|
||||
|
||||
cairo_set_dash (cr, dashes, 2, dashes[0] / 2.0);
|
||||
}
|
||||
|
||||
cairo_rectangle (cr, x, y, private->width - 1.0, private->height - 1.0);
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
if (private->type == PIKA_HANDLE_DASHED_SQUARE)
|
||||
cairo_restore (cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_FILLED_SQUARE:
|
||||
cairo_rectangle (cr, x - 0.5, y - 0.5, private->width, private->height);
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_DIAMOND:
|
||||
case PIKA_HANDLE_DASHED_DIAMOND:
|
||||
case PIKA_HANDLE_FILLED_DIAMOND:
|
||||
if (private->type == PIKA_HANDLE_DASHED_DIAMOND)
|
||||
{
|
||||
gdouble circ;
|
||||
gdouble dashes[2];
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
circ = 4.0 * hypot ((gdouble) private->width / 2.0,
|
||||
(gdouble) private->height / 2.0);
|
||||
|
||||
dashes[0] = (circ / N_DASHES) * DASH_ON_RATIO;
|
||||
dashes[1] = (circ / N_DASHES) * DASH_OFF_RATIO;
|
||||
|
||||
cairo_set_dash (cr, dashes, 2, dashes[0] / 2.0);
|
||||
}
|
||||
|
||||
cairo_move_to (cr, x, y - (gdouble) private->height / 2.0);
|
||||
cairo_line_to (cr, x + (gdouble) private->width / 2.0, y);
|
||||
cairo_line_to (cr, x, y + (gdouble) private->height / 2.0);
|
||||
cairo_line_to (cr, x - (gdouble) private->width / 2.0, y);
|
||||
cairo_line_to (cr, x, y - (gdouble) private->height / 2.0);
|
||||
if (private->type == PIKA_HANDLE_DIAMOND ||
|
||||
private->type == PIKA_HANDLE_DASHED_DIAMOND)
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
else
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
|
||||
if (private->type == PIKA_HANDLE_DASHED_SQUARE)
|
||||
cairo_restore (cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_CROSS:
|
||||
cairo_move_to (cr, x - private->width / 2.0, y);
|
||||
cairo_line_to (cr, x + private->width / 2.0 - 0.5, y);
|
||||
cairo_move_to (cr, x, y - private->height / 2.0);
|
||||
cairo_line_to (cr, x, y + private->height / 2.0 - 0.5);
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_DROP:
|
||||
case PIKA_HANDLE_FILLED_DROP:
|
||||
cairo_move_to (cr, x + private->width, y);
|
||||
pika_cairo_arc (cr, x, y, (gdouble) private->width / 2.0,
|
||||
G_PI / 3, G_PI * 4 / 3.);
|
||||
cairo_close_path (cr);
|
||||
if (private->type == PIKA_HANDLE_DROP)
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
else
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
break;
|
||||
|
||||
default:
|
||||
pika_assert_not_reached ();
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_CIRCLE:
|
||||
case PIKA_HANDLE_DASHED_CIRCLE:
|
||||
if (private->type == PIKA_HANDLE_DASHED_CIRCLE)
|
||||
{
|
||||
gdouble circ;
|
||||
gdouble dashes[2];
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
circ = 2.0 * G_PI * (private->width / 2.0);
|
||||
|
||||
dashes[0] = (circ / N_DASHES) * DASH_ON_RATIO;
|
||||
dashes[1] = (circ / N_DASHES) * DASH_OFF_RATIO;
|
||||
|
||||
cairo_set_dash (cr, dashes, 2, dashes[0] / 2.0);
|
||||
}
|
||||
|
||||
pika_cairo_arc (cr, x, y, private->width / 2.0,
|
||||
private->start_angle,
|
||||
private->slice_angle);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
if (private->type == PIKA_HANDLE_DASHED_CIRCLE)
|
||||
cairo_restore (cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_FILLED_CIRCLE:
|
||||
cairo_move_to (cr, x, y);
|
||||
|
||||
pika_cairo_arc (cr, x, y, (gdouble) private->width / 2.0,
|
||||
private->start_angle,
|
||||
private->slice_angle);
|
||||
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_CROSSHAIR:
|
||||
cairo_move_to (cr, x - private->width / 2.0, y);
|
||||
cairo_line_to (cr, x - private->width * 0.4, y);
|
||||
|
||||
cairo_move_to (cr, x + private->width / 2.0 - 0.5, y);
|
||||
cairo_line_to (cr, x + private->width * 0.4, y);
|
||||
|
||||
cairo_move_to (cr, x, y - private->height / 2.0);
|
||||
cairo_line_to (cr, x, y - private->height * 0.4 - 0.5);
|
||||
|
||||
cairo_move_to (cr, x, y + private->height / 2.0 - 0.5);
|
||||
cairo_line_to (cr, x, y + private->height * 0.4 - 0.5);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_handle_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_handle_transform (item, &x, &y);
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_HANDLE_SQUARE:
|
||||
case PIKA_HANDLE_DASHED_SQUARE:
|
||||
case PIKA_HANDLE_FILLED_SQUARE:
|
||||
w = private->width * (sqrt(2) - 1) / 2;
|
||||
h = private->height * (sqrt(2) - 1) / 2;
|
||||
rectangle.x = x - 1.5 - w;
|
||||
rectangle.y = y - 1.5 - h;
|
||||
rectangle.width = private->width + 3.0 + w * 2;
|
||||
rectangle.height = private->height + 3.0 + h * 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_CIRCLE:
|
||||
case PIKA_HANDLE_DASHED_CIRCLE:
|
||||
case PIKA_HANDLE_FILLED_CIRCLE:
|
||||
case PIKA_HANDLE_CROSS:
|
||||
case PIKA_HANDLE_CROSSHAIR:
|
||||
case PIKA_HANDLE_DIAMOND:
|
||||
case PIKA_HANDLE_DASHED_DIAMOND:
|
||||
case PIKA_HANDLE_FILLED_DIAMOND:
|
||||
rectangle.x = x - private->width / 2.0 - 2.0;
|
||||
rectangle.y = y - private->height / 2.0 - 2.0;
|
||||
rectangle.width = private->width + 4.0;
|
||||
rectangle.height = private->height + 4.0;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_DROP:
|
||||
case PIKA_HANDLE_FILLED_DROP:
|
||||
rectangle.x = x - private->width / 2.0 - 2.0;
|
||||
rectangle.y = y - private->height / 2.0 - 2.0;
|
||||
rectangle.width = private->width * 1.5 + 4.0;
|
||||
rectangle.height = private->height + 4.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_handle_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasHandlePrivate *private = GET_PRIVATE (item);
|
||||
gdouble handle_tx, handle_ty;
|
||||
gdouble mx, my, tx, ty, mmx, mmy;
|
||||
gdouble diamond_offset_x = 0.0;
|
||||
gdouble diamond_offset_y = 0.0;
|
||||
gdouble angle = -private->start_angle;
|
||||
|
||||
pika_canvas_handle_transform (item, &handle_tx, &handle_ty);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
x, y,
|
||||
&mx, &my);
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_HANDLE_DIAMOND:
|
||||
case PIKA_HANDLE_DASHED_DIAMOND:
|
||||
case PIKA_HANDLE_FILLED_DIAMOND:
|
||||
angle -= G_PI / 4.0;
|
||||
diamond_offset_x = private->width / 2.0;
|
||||
diamond_offset_y = private->height / 2.0;
|
||||
case PIKA_HANDLE_SQUARE:
|
||||
case PIKA_HANDLE_DASHED_SQUARE:
|
||||
case PIKA_HANDLE_FILLED_SQUARE:
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x, private->y,
|
||||
&tx, &ty);
|
||||
mmx = mx - tx; mmy = my - ty;
|
||||
mx = cos (angle) * mmx - sin (angle) * mmy + tx + diamond_offset_x;
|
||||
my = sin (angle) * mmx + cos (angle) * mmy + ty + diamond_offset_y;
|
||||
return mx > handle_tx && mx < handle_tx + private->width &&
|
||||
my > handle_ty && my < handle_ty + private->height;
|
||||
|
||||
case PIKA_HANDLE_CIRCLE:
|
||||
case PIKA_HANDLE_DASHED_CIRCLE:
|
||||
case PIKA_HANDLE_FILLED_CIRCLE:
|
||||
case PIKA_HANDLE_CROSS:
|
||||
case PIKA_HANDLE_CROSSHAIR:
|
||||
case PIKA_HANDLE_DROP:
|
||||
case PIKA_HANDLE_FILLED_DROP:
|
||||
{
|
||||
gint width = private->width;
|
||||
|
||||
if (width != private->height)
|
||||
width = (width + private->height) / 2;
|
||||
|
||||
width /= 2;
|
||||
|
||||
return ((SQR (handle_tx - mx) + SQR (handle_ty - my)) < SQR (width));
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_handle_new (PikaDisplayShell *shell,
|
||||
PikaHandleType type,
|
||||
PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_HANDLE,
|
||||
"shell", shell,
|
||||
"type", type,
|
||||
"anchor", anchor,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_handle_get_position (PikaCanvasItem *handle,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_HANDLE (handle));
|
||||
g_return_if_fail (x != NULL);
|
||||
g_return_if_fail (y != NULL);
|
||||
|
||||
g_object_get (handle,
|
||||
"x", x,
|
||||
"y", y,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_handle_set_position (PikaCanvasItem *handle,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_HANDLE (handle));
|
||||
|
||||
pika_canvas_item_begin_change (handle);
|
||||
|
||||
g_object_set (handle,
|
||||
"x", x,
|
||||
"y", y,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (handle);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_canvas_handle_calc_size (PikaCanvasItem *item,
|
||||
gdouble mouse_x,
|
||||
gdouble mouse_y,
|
||||
gint normal_size,
|
||||
gint hover_size)
|
||||
{
|
||||
gdouble x, y;
|
||||
gdouble distance;
|
||||
gdouble size;
|
||||
gint full_threshold_sq = SQR (hover_size / 2) * 9;
|
||||
gint partial_threshold_sq = full_threshold_sq * 5;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_HANDLE (item), normal_size);
|
||||
|
||||
pika_canvas_handle_get_position (item, &x, &y);
|
||||
distance = pika_canvas_item_transform_distance_square (item,
|
||||
mouse_x,
|
||||
mouse_y,
|
||||
x, y);
|
||||
|
||||
/* calculate the handle size based on distance from the cursor */
|
||||
size = (1.0 - (distance - full_threshold_sq) /
|
||||
(partial_threshold_sq - full_threshold_sq));
|
||||
|
||||
size = CLAMP (size, 0.0, 1.0);
|
||||
|
||||
return (gint) CLAMP ((size * hover_size),
|
||||
normal_size,
|
||||
hover_size);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_handle_get_size (PikaCanvasItem *handle,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_HANDLE (handle));
|
||||
g_return_if_fail (width != NULL);
|
||||
g_return_if_fail (height != NULL);
|
||||
|
||||
g_object_get (handle,
|
||||
"width", width,
|
||||
"height", height,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_handle_set_size (PikaCanvasItem *handle,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_HANDLE (handle));
|
||||
|
||||
pika_canvas_item_begin_change (handle);
|
||||
|
||||
g_object_set (handle,
|
||||
"width", width,
|
||||
"height", height,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (handle);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_handle_set_angles (PikaCanvasItem *handle,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_HANDLE (handle));
|
||||
|
||||
pika_canvas_item_begin_change (handle);
|
||||
|
||||
g_object_set (handle,
|
||||
"start-angle", start_angle,
|
||||
"slice-angle", slice_angle,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (handle);
|
||||
}
|
||||
96
app/display/pikacanvashandle.h
Normal file
96
app/display/pikacanvashandle.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvashandle.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_HANDLE_H__
|
||||
#define __PIKA_CANVAS_HANDLE_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_CANVAS_HANDLE_SIZE_CIRCLE 13
|
||||
#define PIKA_CANVAS_HANDLE_SIZE_CROSS 15
|
||||
#define PIKA_CANVAS_HANDLE_SIZE_CROSSHAIR 43
|
||||
#define PIKA_CANVAS_HANDLE_SIZE_LARGE 25
|
||||
#define PIKA_CANVAS_HANDLE_SIZE_SMALL 7
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_HANDLE (pika_canvas_handle_get_type ())
|
||||
#define PIKA_CANVAS_HANDLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_HANDLE, PikaCanvasHandle))
|
||||
#define PIKA_CANVAS_HANDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_HANDLE, PikaCanvasHandleClass))
|
||||
#define PIKA_IS_CANVAS_HANDLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_HANDLE))
|
||||
#define PIKA_IS_CANVAS_HANDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_HANDLE))
|
||||
#define PIKA_CANVAS_HANDLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_HANDLE, PikaCanvasHandleClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasHandle PikaCanvasHandle;
|
||||
typedef struct _PikaCanvasHandleClass PikaCanvasHandleClass;
|
||||
|
||||
struct _PikaCanvasHandle
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasHandleClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_handle_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_handle_new (PikaDisplayShell *shell,
|
||||
PikaHandleType type,
|
||||
PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
void pika_canvas_handle_get_position (PikaCanvasItem *handle,
|
||||
gdouble *x,
|
||||
gdouble *y);
|
||||
void pika_canvas_handle_set_position (PikaCanvasItem *handle,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
gint pika_canvas_handle_calc_size (PikaCanvasItem *item,
|
||||
gdouble mouse_x,
|
||||
gdouble mouse_y,
|
||||
gint normal_size,
|
||||
gint hover_size);
|
||||
|
||||
void pika_canvas_handle_get_size (PikaCanvasItem *handle,
|
||||
gint *width,
|
||||
gint *height);
|
||||
void pika_canvas_handle_set_size (PikaCanvasItem *handle,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
void pika_canvas_handle_set_angles (PikaCanvasItem *handle,
|
||||
gdouble start_handle,
|
||||
gdouble slice_handle);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_HANDLE_H__ */
|
||||
478
app/display/pikacanvasitem-utils.c
Normal file
478
app/display/pikacanvasitem-utils.c
Normal file
@ -0,0 +1,478 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasitem-utils.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "vectors/pikaanchor.h"
|
||||
#include "vectors/pikabezierstroke.h"
|
||||
#include "vectors/pikavectors.h"
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
#include "pikacanvasitem-utils.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_on_handle (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
PikaHandleType type,
|
||||
gdouble handle_x,
|
||||
gdouble handle_y,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaHandleAnchor anchor)
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
gdouble tx, ty;
|
||||
gdouble handle_tx, handle_ty;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
|
||||
shell = pika_canvas_item_get_shell (item);
|
||||
|
||||
pika_display_shell_zoom_xy_f (shell,
|
||||
x, y,
|
||||
&tx, &ty);
|
||||
pika_display_shell_zoom_xy_f (shell,
|
||||
handle_x, handle_y,
|
||||
&handle_tx, &handle_ty);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PIKA_HANDLE_SQUARE:
|
||||
case PIKA_HANDLE_FILLED_SQUARE:
|
||||
case PIKA_HANDLE_CROSS:
|
||||
case PIKA_HANDLE_CROSSHAIR:
|
||||
pika_canvas_item_shift_to_north_west (anchor,
|
||||
handle_tx, handle_ty,
|
||||
width, height,
|
||||
&handle_tx, &handle_ty);
|
||||
|
||||
return (tx == CLAMP (tx, handle_tx, handle_tx + width) &&
|
||||
ty == CLAMP (ty, handle_ty, handle_ty + height));
|
||||
|
||||
case PIKA_HANDLE_CIRCLE:
|
||||
case PIKA_HANDLE_FILLED_CIRCLE:
|
||||
pika_canvas_item_shift_to_center (anchor,
|
||||
handle_tx, handle_ty,
|
||||
width, height,
|
||||
&handle_tx, &handle_ty);
|
||||
|
||||
/* FIXME */
|
||||
if (width != height)
|
||||
width = (width + height) / 2;
|
||||
|
||||
width /= 2;
|
||||
|
||||
return ((SQR (handle_tx - tx) + SQR (handle_ty - ty)) < SQR (width));
|
||||
|
||||
default:
|
||||
g_warning ("%s: invalid handle type %d", G_STRFUNC, type);
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_on_vectors_handle (PikaCanvasItem *item,
|
||||
PikaVectors *vectors,
|
||||
const PikaCoords *coord,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaAnchorType preferred,
|
||||
gboolean exclusive,
|
||||
PikaAnchor **ret_anchor,
|
||||
PikaStroke **ret_stroke)
|
||||
{
|
||||
PikaStroke *stroke = NULL;
|
||||
PikaStroke *pref_stroke = NULL;
|
||||
PikaAnchor *anchor = NULL;
|
||||
PikaAnchor *pref_anchor = NULL;
|
||||
gdouble dx, dy;
|
||||
gdouble pref_mindist = -1;
|
||||
gdouble mindist = -1;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_VECTORS (vectors), FALSE);
|
||||
g_return_val_if_fail (coord != NULL, FALSE);
|
||||
|
||||
if (ret_anchor) *ret_anchor = NULL;
|
||||
if (ret_stroke) *ret_stroke = NULL;
|
||||
|
||||
while ((stroke = pika_vectors_stroke_get_next (vectors, stroke)))
|
||||
{
|
||||
GList *anchor_list;
|
||||
GList *list;
|
||||
|
||||
anchor_list = g_list_concat (pika_stroke_get_draw_anchors (stroke),
|
||||
pika_stroke_get_draw_controls (stroke));
|
||||
|
||||
for (list = anchor_list; list; list = g_list_next (list))
|
||||
{
|
||||
dx = coord->x - PIKA_ANCHOR (list->data)->position.x;
|
||||
dy = coord->y - PIKA_ANCHOR (list->data)->position.y;
|
||||
|
||||
if (mindist < 0 || mindist > dx * dx + dy * dy)
|
||||
{
|
||||
mindist = dx * dx + dy * dy;
|
||||
anchor = PIKA_ANCHOR (list->data);
|
||||
|
||||
if (ret_stroke)
|
||||
*ret_stroke = stroke;
|
||||
}
|
||||
|
||||
if ((pref_mindist < 0 || pref_mindist > dx * dx + dy * dy) &&
|
||||
PIKA_ANCHOR (list->data)->type == preferred)
|
||||
{
|
||||
pref_mindist = dx * dx + dy * dy;
|
||||
pref_anchor = PIKA_ANCHOR (list->data);
|
||||
pref_stroke = stroke;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (anchor_list);
|
||||
}
|
||||
|
||||
/* If the data passed into ret_anchor is a preferred anchor, return it. */
|
||||
if (ret_anchor && *ret_anchor &&
|
||||
pika_canvas_item_on_handle (item,
|
||||
coord->x,
|
||||
coord->y,
|
||||
PIKA_HANDLE_CIRCLE,
|
||||
(*ret_anchor)->position.x,
|
||||
(*ret_anchor)->position.y,
|
||||
width, height,
|
||||
PIKA_HANDLE_ANCHOR_CENTER) &&
|
||||
(*ret_anchor)->type == preferred)
|
||||
{
|
||||
if (ret_stroke) *ret_stroke = pref_stroke;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pref_anchor && pika_canvas_item_on_handle (item,
|
||||
coord->x,
|
||||
coord->y,
|
||||
PIKA_HANDLE_CIRCLE,
|
||||
pref_anchor->position.x,
|
||||
pref_anchor->position.y,
|
||||
width, height,
|
||||
PIKA_HANDLE_ANCHOR_CENTER))
|
||||
{
|
||||
if (ret_anchor) *ret_anchor = pref_anchor;
|
||||
if (ret_stroke) *ret_stroke = pref_stroke;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (!exclusive && anchor &&
|
||||
pika_canvas_item_on_handle (item,
|
||||
coord->x,
|
||||
coord->y,
|
||||
PIKA_HANDLE_CIRCLE,
|
||||
anchor->position.x,
|
||||
anchor->position.y,
|
||||
width, height,
|
||||
PIKA_HANDLE_ANCHOR_CENTER))
|
||||
{
|
||||
if (ret_anchor)
|
||||
*ret_anchor = anchor;
|
||||
|
||||
/* *ret_stroke already set correctly. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (ret_anchor)
|
||||
*ret_anchor = NULL;
|
||||
if (ret_stroke)
|
||||
*ret_stroke = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_on_vectors_curve (PikaCanvasItem *item,
|
||||
PikaVectors *vectors,
|
||||
const PikaCoords *coord,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaCoords *ret_coords,
|
||||
gdouble *ret_pos,
|
||||
PikaAnchor **ret_segment_start,
|
||||
PikaAnchor **ret_segment_end,
|
||||
PikaStroke **ret_stroke)
|
||||
{
|
||||
PikaStroke *stroke = NULL;
|
||||
PikaAnchor *segment_start;
|
||||
PikaAnchor *segment_end;
|
||||
PikaCoords min_coords = PIKA_COORDS_DEFAULT_VALUES;
|
||||
PikaCoords cur_coords;
|
||||
gdouble min_dist, cur_dist, cur_pos;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_VECTORS (vectors), FALSE);
|
||||
g_return_val_if_fail (coord != NULL, FALSE);
|
||||
|
||||
if (ret_coords) *ret_coords = *coord;
|
||||
if (ret_pos) *ret_pos = -1.0;
|
||||
if (ret_segment_start) *ret_segment_start = NULL;
|
||||
if (ret_segment_end) *ret_segment_end = NULL;
|
||||
if (ret_stroke) *ret_stroke = NULL;
|
||||
|
||||
min_dist = -1.0;
|
||||
|
||||
while ((stroke = pika_vectors_stroke_get_next (vectors, stroke)))
|
||||
{
|
||||
cur_dist = pika_stroke_nearest_point_get (stroke, coord, 1.0,
|
||||
&cur_coords,
|
||||
&segment_start,
|
||||
&segment_end,
|
||||
&cur_pos);
|
||||
|
||||
if (cur_dist >= 0 && (min_dist < 0 || cur_dist < min_dist))
|
||||
{
|
||||
min_dist = cur_dist;
|
||||
min_coords = cur_coords;
|
||||
|
||||
if (ret_coords) *ret_coords = cur_coords;
|
||||
if (ret_pos) *ret_pos = cur_pos;
|
||||
if (ret_segment_start) *ret_segment_start = segment_start;
|
||||
if (ret_segment_end) *ret_segment_end = segment_end;
|
||||
if (ret_stroke) *ret_stroke = stroke;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_dist >= 0 &&
|
||||
pika_canvas_item_on_handle (item,
|
||||
coord->x,
|
||||
coord->y,
|
||||
PIKA_HANDLE_CIRCLE,
|
||||
min_coords.x,
|
||||
min_coords.y,
|
||||
width, height,
|
||||
PIKA_HANDLE_ANCHOR_CENTER))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_on_vectors (PikaCanvasItem *item,
|
||||
const PikaCoords *coords,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaCoords *ret_coords,
|
||||
gdouble *ret_pos,
|
||||
PikaAnchor **ret_segment_start,
|
||||
PikaAnchor **ret_segment_end,
|
||||
PikaStroke **ret_stroke,
|
||||
PikaVectors **ret_vectors)
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
PikaImage *image;
|
||||
GList *all_vectors;
|
||||
GList *list;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
g_return_val_if_fail (coords != NULL, FALSE);
|
||||
|
||||
shell = pika_canvas_item_get_shell (item);
|
||||
image = pika_display_get_image (shell->display);
|
||||
|
||||
if (ret_coords) *ret_coords = *coords;
|
||||
if (ret_pos) *ret_pos = -1.0;
|
||||
if (ret_segment_start) *ret_segment_start = NULL;
|
||||
if (ret_segment_end) *ret_segment_end = NULL;
|
||||
if (ret_stroke) *ret_stroke = NULL;
|
||||
if (ret_vectors) *ret_vectors = NULL;
|
||||
|
||||
all_vectors = pika_image_get_vectors_list (image);
|
||||
|
||||
for (list = all_vectors; list; list = g_list_next (list))
|
||||
{
|
||||
PikaVectors *vectors = list->data;
|
||||
|
||||
if (! pika_item_get_visible (PIKA_ITEM (vectors)))
|
||||
continue;
|
||||
|
||||
if (pika_canvas_item_on_vectors_curve (item,
|
||||
vectors, coords,
|
||||
width, height,
|
||||
ret_coords,
|
||||
ret_pos,
|
||||
ret_segment_start,
|
||||
ret_segment_end,
|
||||
ret_stroke))
|
||||
{
|
||||
if (ret_vectors)
|
||||
*ret_vectors = vectors;
|
||||
|
||||
g_list_free (all_vectors);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (all_vectors);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_shift_to_north_west (PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble *shifted_x,
|
||||
gdouble *shifted_y)
|
||||
{
|
||||
switch (anchor)
|
||||
{
|
||||
case PIKA_HANDLE_ANCHOR_CENTER:
|
||||
x -= width / 2;
|
||||
y -= height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH:
|
||||
x -= width / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH_WEST:
|
||||
/* nothing, this is the default */
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH_EAST:
|
||||
x -= width;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH:
|
||||
x -= width / 2;
|
||||
y -= height;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH_WEST:
|
||||
y -= height;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH_EAST:
|
||||
x -= width;
|
||||
y -= height;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_WEST:
|
||||
y -= height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_EAST:
|
||||
x -= width;
|
||||
y -= height / 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (shifted_x)
|
||||
*shifted_x = x;
|
||||
|
||||
if (shifted_y)
|
||||
*shifted_y = y;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_shift_to_center (PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble *shifted_x,
|
||||
gdouble *shifted_y)
|
||||
{
|
||||
switch (anchor)
|
||||
{
|
||||
case PIKA_HANDLE_ANCHOR_CENTER:
|
||||
/* nothing, this is the default */
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH:
|
||||
y += height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH_WEST:
|
||||
x += width / 2;
|
||||
y += height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_NORTH_EAST:
|
||||
x -= width / 2;
|
||||
y += height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH:
|
||||
y -= height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH_WEST:
|
||||
x += width / 2;
|
||||
y -= height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_SOUTH_EAST:
|
||||
x -= width / 2;
|
||||
y -= height / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_WEST:
|
||||
x += width / 2;
|
||||
break;
|
||||
|
||||
case PIKA_HANDLE_ANCHOR_EAST:
|
||||
x -= width / 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (shifted_x)
|
||||
*shifted_x = x;
|
||||
|
||||
if (shifted_y)
|
||||
*shifted_y = y;
|
||||
}
|
||||
85
app/display/pikacanvasitem-utils.h
Normal file
85
app/display/pikacanvasitem-utils.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasitem-utils.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_ITEM_UTILS_H__
|
||||
#define __PIKA_CANVAS_ITEM_UTILS_H__
|
||||
|
||||
|
||||
gboolean pika_canvas_item_on_handle (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
PikaHandleType type,
|
||||
gdouble handle_x,
|
||||
gdouble handle_y,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaHandleAnchor anchor);
|
||||
|
||||
gboolean pika_canvas_item_on_vectors_handle (PikaCanvasItem *item,
|
||||
PikaVectors *vectors,
|
||||
const PikaCoords *coord,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaAnchorType preferred,
|
||||
gboolean exclusive,
|
||||
PikaAnchor **ret_anchor,
|
||||
PikaStroke **ret_stroke);
|
||||
gboolean pika_canvas_item_on_vectors_curve (PikaCanvasItem *item,
|
||||
PikaVectors *vectors,
|
||||
const PikaCoords *coord,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaCoords *ret_coords,
|
||||
gdouble *ret_pos,
|
||||
PikaAnchor **ret_segment_start,
|
||||
PikaAnchor **ret_segment_end,
|
||||
PikaStroke **ret_stroke);
|
||||
gboolean pika_canvas_item_on_vectors (PikaCanvasItem *item,
|
||||
const PikaCoords *coords,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaCoords *ret_coords,
|
||||
gdouble *ret_pos,
|
||||
PikaAnchor **ret_segment_start,
|
||||
PikaAnchor **ret_segment_end,
|
||||
PikaStroke **ret_stroke,
|
||||
PikaVectors **ret_vectors);
|
||||
|
||||
void pika_canvas_item_shift_to_north_west (PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble *shifted_x,
|
||||
gdouble *shifted_y);
|
||||
void pika_canvas_item_shift_to_center (PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble *shifted_x,
|
||||
gdouble *shifted_y);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_ITEM_UTILS_H__ */
|
||||
733
app/display/pikacanvasitem.c
Normal file
733
app/display/pikacanvasitem.c
Normal file
@ -0,0 +1,733 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasitem.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvasitem.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SHELL,
|
||||
PROP_VISIBLE,
|
||||
PROP_LINE_CAP,
|
||||
PROP_HIGHLIGHT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
UPDATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
||||
struct _PikaCanvasItemPrivate
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
gboolean visible;
|
||||
cairo_line_cap_t line_cap;
|
||||
gboolean highlight;
|
||||
gint suspend_stroking;
|
||||
gint suspend_filling;
|
||||
gint change_count;
|
||||
cairo_region_t *change_region;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_item_dispose (GObject *object);
|
||||
static void pika_canvas_item_constructed (GObject *object);
|
||||
static void pika_canvas_item_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_item_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_item_dispatch_properties_changed (GObject *object,
|
||||
guint n_pspecs,
|
||||
GParamSpec **pspecs);
|
||||
|
||||
static void pika_canvas_item_real_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_item_real_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_item_real_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static void pika_canvas_item_real_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static gboolean pika_canvas_item_real_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasItem, pika_canvas_item, PIKA_TYPE_OBJECT)
|
||||
|
||||
#define parent_class pika_canvas_item_parent_class
|
||||
|
||||
static guint item_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_item_class_init (PikaCanvasItemClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = pika_canvas_item_dispose;
|
||||
object_class->constructed = pika_canvas_item_constructed;
|
||||
object_class->set_property = pika_canvas_item_set_property;
|
||||
object_class->get_property = pika_canvas_item_get_property;
|
||||
object_class->dispatch_properties_changed = pika_canvas_item_dispatch_properties_changed;
|
||||
|
||||
klass->update = NULL;
|
||||
klass->draw = pika_canvas_item_real_draw;
|
||||
klass->get_extents = pika_canvas_item_real_get_extents;
|
||||
klass->stroke = pika_canvas_item_real_stroke;
|
||||
klass->fill = pika_canvas_item_real_fill;
|
||||
klass->hit = pika_canvas_item_real_hit;
|
||||
|
||||
item_signals[UPDATE] =
|
||||
g_signal_new ("update",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (PikaCanvasItemClass, update),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_POINTER);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SHELL,
|
||||
g_param_spec_object ("shell",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_DISPLAY_SHELL,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_VISIBLE,
|
||||
g_param_spec_boolean ("visible",
|
||||
NULL, NULL,
|
||||
TRUE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_LINE_CAP,
|
||||
g_param_spec_int ("line-cap",
|
||||
NULL, NULL,
|
||||
CAIRO_LINE_CAP_BUTT,
|
||||
CAIRO_LINE_CAP_SQUARE,
|
||||
CAIRO_LINE_CAP_ROUND,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HIGHLIGHT,
|
||||
g_param_spec_boolean ("highlight",
|
||||
NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_init (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasItemPrivate *private;
|
||||
|
||||
item->private = pika_canvas_item_get_instance_private (item);
|
||||
private = item->private;
|
||||
|
||||
private->shell = NULL;
|
||||
private->visible = TRUE;
|
||||
private->line_cap = CAIRO_LINE_CAP_ROUND;
|
||||
private->highlight = FALSE;
|
||||
private->suspend_stroking = 0;
|
||||
private->suspend_filling = 0;
|
||||
private->change_count = 1; /* avoid emissions during construction */
|
||||
private->change_region = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_constructed (GObject *object)
|
||||
{
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (object);
|
||||
|
||||
pika_assert (PIKA_IS_DISPLAY_SHELL (item->private->shell));
|
||||
|
||||
item->private->change_count = 0; /* undo hack from init() */
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_dispose (GObject *object)
|
||||
{
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (object);
|
||||
|
||||
item->private->change_count++; /* avoid emissions during destruction */
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (object);
|
||||
PikaCanvasItemPrivate *private = item->private;
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SHELL:
|
||||
private->shell = g_value_get_object (value); /* don't ref */
|
||||
break;
|
||||
case PROP_VISIBLE:
|
||||
private->visible = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_LINE_CAP:
|
||||
private->line_cap = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_HIGHLIGHT:
|
||||
private->highlight = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (object);
|
||||
PikaCanvasItemPrivate *private = item->private;
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SHELL:
|
||||
g_value_set_object (value, private->shell);
|
||||
break;
|
||||
case PROP_VISIBLE:
|
||||
g_value_set_boolean (value, private->visible);
|
||||
break;
|
||||
case PROP_LINE_CAP:
|
||||
g_value_set_int (value, private->line_cap);
|
||||
break;
|
||||
case PROP_HIGHLIGHT:
|
||||
g_value_set_boolean (value, private->highlight);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_dispatch_properties_changed (GObject *object,
|
||||
guint n_pspecs,
|
||||
GParamSpec **pspecs)
|
||||
{
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
|
||||
n_pspecs,
|
||||
pspecs);
|
||||
|
||||
if (_pika_canvas_item_needs_update (item))
|
||||
{
|
||||
cairo_region_t *region = pika_canvas_item_get_extents (item);
|
||||
|
||||
if (region)
|
||||
{
|
||||
g_signal_emit (object, item_signals[UPDATE], 0,
|
||||
region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_real_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
g_warn_if_reached ();
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_item_real_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_real_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
cairo_set_line_cap (cr, item->private->line_cap);
|
||||
|
||||
pika_canvas_set_tool_bg_style (pika_canvas_item_get_canvas (item), cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
pika_canvas_set_tool_fg_style (pika_canvas_item_get_canvas (item), cr,
|
||||
item->private->highlight);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_item_real_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
pika_canvas_set_tool_bg_style (pika_canvas_item_get_canvas (item), cr);
|
||||
cairo_set_line_width (cr, 2.0);
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
pika_canvas_set_tool_fg_style (pika_canvas_item_get_canvas (item), cr,
|
||||
item->private->highlight);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_item_real_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaDisplayShell *
|
||||
pika_canvas_item_get_shell (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), NULL);
|
||||
|
||||
return item->private->shell;
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
pika_canvas_item_get_image (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), NULL);
|
||||
|
||||
return pika_display_get_image (item->private->shell->display);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
pika_canvas_item_get_canvas (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), NULL);
|
||||
|
||||
return item->private->shell->canvas;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
if (item->private->visible)
|
||||
{
|
||||
cairo_save (cr);
|
||||
PIKA_CANVAS_ITEM_GET_CLASS (item)->draw (item, cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_region_t *
|
||||
pika_canvas_item_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), NULL);
|
||||
|
||||
if (item->private->visible)
|
||||
return PIKA_CANVAS_ITEM_GET_CLASS (item)->get_extents (item);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
|
||||
if (item->private->visible)
|
||||
return PIKA_CANVAS_ITEM_GET_CLASS (item)->hit (item, x, y);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_set_visible (PikaCanvasItem *item,
|
||||
gboolean visible)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
if (item->private->visible != visible)
|
||||
{
|
||||
pika_canvas_item_begin_change (item);
|
||||
g_object_set (G_OBJECT (item),
|
||||
"visible", visible,
|
||||
NULL);
|
||||
pika_canvas_item_end_change (item);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_get_visible (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
|
||||
return item->private->visible;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_set_line_cap (PikaCanvasItem *item,
|
||||
cairo_line_cap_t line_cap)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
if (item->private->line_cap != line_cap)
|
||||
{
|
||||
pika_canvas_item_begin_change (item);
|
||||
g_object_set (G_OBJECT (item),
|
||||
"line-cap", line_cap,
|
||||
NULL);
|
||||
pika_canvas_item_end_change (item);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_set_highlight (PikaCanvasItem *item,
|
||||
gboolean highlight)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
if (item->private->highlight != highlight)
|
||||
{
|
||||
g_object_set (G_OBJECT (item),
|
||||
"highlight", highlight,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_item_get_highlight (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), FALSE);
|
||||
|
||||
return item->private->highlight;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_begin_change (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasItemPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
private = item->private;
|
||||
|
||||
private->change_count++;
|
||||
|
||||
if (private->change_count == 1 &&
|
||||
g_signal_has_handler_pending (item, item_signals[UPDATE], 0, FALSE))
|
||||
{
|
||||
private->change_region = pika_canvas_item_get_extents (item);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_end_change (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasItemPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
private = item->private;
|
||||
|
||||
g_return_if_fail (private->change_count > 0);
|
||||
|
||||
private->change_count--;
|
||||
|
||||
if (private->change_count == 0)
|
||||
{
|
||||
if (g_signal_has_handler_pending (item, item_signals[UPDATE], 0, FALSE))
|
||||
{
|
||||
cairo_region_t *region = pika_canvas_item_get_extents (item);
|
||||
|
||||
if (! region)
|
||||
{
|
||||
region = private->change_region;
|
||||
}
|
||||
else if (private->change_region)
|
||||
{
|
||||
cairo_region_union (region, private->change_region);
|
||||
cairo_region_destroy (private->change_region);
|
||||
}
|
||||
|
||||
private->change_region = NULL;
|
||||
|
||||
if (region)
|
||||
{
|
||||
g_signal_emit (item, item_signals[UPDATE], 0,
|
||||
region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_pointer (&private->change_region, cairo_region_destroy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_suspend_stroking (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
item->private->suspend_stroking++;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_resume_stroking (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
g_return_if_fail (item->private->suspend_stroking > 0);
|
||||
|
||||
item->private->suspend_stroking--;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_suspend_filling (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
item->private->suspend_filling++;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_resume_filling (PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
g_return_if_fail (item->private->suspend_filling > 0);
|
||||
|
||||
item->private->suspend_filling--;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_transform (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasItemPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
private = item->private;
|
||||
|
||||
cairo_translate (cr, -private->shell->offset_x, -private->shell->offset_y);
|
||||
cairo_scale (cr, private->shell->scale_x, private->shell->scale_y);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_transform_xy (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint *tx,
|
||||
gint *ty)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_display_shell_zoom_xy (item->private->shell, x, y, tx, ty);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_transform_xy_f (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *tx,
|
||||
gdouble *ty)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_display_shell_zoom_xy_f (item->private->shell, x, y, tx, ty);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_canvas_item_transform_distance:
|
||||
* @item: a #PikaCanvasItem
|
||||
* @x1: start point X in image coordinates
|
||||
* @y1: start point Y in image coordinates
|
||||
* @x2: end point X in image coordinates
|
||||
* @y2: end point Y in image coordinates
|
||||
*
|
||||
* If you just need to compare distances, consider to use
|
||||
* pika_canvas_item_transform_distance_square() instead.
|
||||
*
|
||||
* Returns: the distance between the given points in display coordinates
|
||||
**/
|
||||
gdouble
|
||||
pika_canvas_item_transform_distance (PikaCanvasItem *item,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2)
|
||||
{
|
||||
return sqrt (pika_canvas_item_transform_distance_square (item,
|
||||
x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_canvas_item_transform_distance_square:
|
||||
* @item: a #PikaCanvasItem
|
||||
* @x1: start point X in image coordinates
|
||||
* @y1: start point Y in image coordinates
|
||||
* @x2: end point X in image coordinates
|
||||
* @y2: end point Y in image coordinates
|
||||
*
|
||||
* This function is more effective than
|
||||
* pika_canvas_item_transform_distance() as it doesn't perform a
|
||||
* sqrt(). Use this if you just need to compare distances.
|
||||
*
|
||||
* Returns: the square of the distance between the given points in
|
||||
* display coordinates
|
||||
**/
|
||||
gdouble
|
||||
pika_canvas_item_transform_distance_square (PikaCanvasItem *item,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2)
|
||||
{
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_ITEM (item), 0.0);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item, x1, y1, &tx1, &ty1);
|
||||
pika_canvas_item_transform_xy_f (item, x2, y2, &tx2, &ty2);
|
||||
|
||||
return SQR (tx2 - tx1) + SQR (ty2 - ty1);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_item_untransform_viewport (PikaCanvasItem *item,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gint *w,
|
||||
gint *h)
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
shell = item->private->shell;
|
||||
|
||||
pika_display_shell_unrotate_bounds (shell,
|
||||
0.0, 0.0,
|
||||
shell->disp_width, shell->disp_height,
|
||||
&x1, &y1,
|
||||
&x2, &y2);
|
||||
|
||||
*x = floor (x1);
|
||||
*y = floor (y1);
|
||||
*w = ceil (x2) - *x;
|
||||
*h = ceil (y2) - *y;
|
||||
}
|
||||
|
||||
|
||||
/* protected functions */
|
||||
|
||||
void
|
||||
_pika_canvas_item_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
g_signal_emit (item, item_signals[UPDATE], 0,
|
||||
region);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_pika_canvas_item_needs_update (PikaCanvasItem *item)
|
||||
{
|
||||
return (item->private->change_count == 0 &&
|
||||
g_signal_has_handler_pending (item, item_signals[UPDATE], 0, FALSE));
|
||||
}
|
||||
|
||||
void
|
||||
_pika_canvas_item_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
if (item->private->suspend_filling > 0)
|
||||
g_warning ("_pika_canvas_item_stroke() on an item that is in a filling group");
|
||||
|
||||
if (item->private->suspend_stroking == 0)
|
||||
{
|
||||
PIKA_CANVAS_ITEM_GET_CLASS (item)->stroke (item, cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_new_sub_path (cr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_pika_canvas_item_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
if (item->private->suspend_stroking > 0)
|
||||
g_warning ("_pika_canvas_item_fill() on an item that is in a stroking group");
|
||||
|
||||
if (item->private->suspend_filling == 0)
|
||||
{
|
||||
PIKA_CANVAS_ITEM_GET_CLASS (item)->fill (item, cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_new_sub_path (cr);
|
||||
}
|
||||
}
|
||||
151
app/display/pikacanvasitem.h
Normal file
151
app/display/pikacanvasitem.h
Normal file
@ -0,0 +1,151 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasitem.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_ITEM_H__
|
||||
#define __PIKA_CANVAS_ITEM_H__
|
||||
|
||||
|
||||
#include "core/pikaobject.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_ITEM (pika_canvas_item_get_type ())
|
||||
#define PIKA_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_ITEM, PikaCanvasItem))
|
||||
#define PIKA_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_ITEM, PikaCanvasItemClass))
|
||||
#define PIKA_IS_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_ITEM))
|
||||
#define PIKA_IS_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_ITEM))
|
||||
#define PIKA_CANVAS_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_ITEM, PikaCanvasItemClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasItemPrivate PikaCanvasItemPrivate;
|
||||
typedef struct _PikaCanvasItemClass PikaCanvasItemClass;
|
||||
|
||||
struct _PikaCanvasItem
|
||||
{
|
||||
PikaObject parent_instance;
|
||||
|
||||
PikaCanvasItemPrivate *private;
|
||||
};
|
||||
|
||||
struct _PikaCanvasItemClass
|
||||
{
|
||||
PikaObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (* update) (PikaCanvasItem *item,
|
||||
cairo_region_t *region);
|
||||
|
||||
/* virtual functions */
|
||||
void (* draw) (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
cairo_region_t * (* get_extents) (PikaCanvasItem *item);
|
||||
|
||||
void (* stroke) (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
void (* fill) (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
gboolean (* hit) (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_item_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaDisplayShell * pika_canvas_item_get_shell (PikaCanvasItem *item);
|
||||
PikaImage * pika_canvas_item_get_image (PikaCanvasItem *item);
|
||||
GtkWidget * pika_canvas_item_get_canvas (PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_item_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
cairo_region_t * pika_canvas_item_get_extents (PikaCanvasItem *item);
|
||||
|
||||
gboolean pika_canvas_item_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
void pika_canvas_item_set_visible (PikaCanvasItem *item,
|
||||
gboolean visible);
|
||||
gboolean pika_canvas_item_get_visible (PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_item_set_line_cap (PikaCanvasItem *item,
|
||||
cairo_line_cap_t line_cap);
|
||||
|
||||
void pika_canvas_item_set_highlight (PikaCanvasItem *item,
|
||||
gboolean highlight);
|
||||
gboolean pika_canvas_item_get_highlight (PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_item_begin_change (PikaCanvasItem *item);
|
||||
void pika_canvas_item_end_change (PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_item_suspend_stroking (PikaCanvasItem *item);
|
||||
void pika_canvas_item_resume_stroking (PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_item_suspend_filling (PikaCanvasItem *item);
|
||||
void pika_canvas_item_resume_filling (PikaCanvasItem *item);
|
||||
|
||||
void pika_canvas_item_transform (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
void pika_canvas_item_transform_xy (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint *tx,
|
||||
gint *ty);
|
||||
void pika_canvas_item_transform_xy_f (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *tx,
|
||||
gdouble *ty);
|
||||
gdouble pika_canvas_item_transform_distance
|
||||
(PikaCanvasItem *item,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2);
|
||||
gdouble pika_canvas_item_transform_distance_square
|
||||
(PikaCanvasItem *item,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2);
|
||||
void pika_canvas_item_untransform_viewport
|
||||
(PikaCanvasItem *item,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gint *w,
|
||||
gint *h);
|
||||
|
||||
|
||||
/* protected */
|
||||
|
||||
void _pika_canvas_item_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region);
|
||||
gboolean _pika_canvas_item_needs_update (PikaCanvasItem *item);
|
||||
void _pika_canvas_item_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
void _pika_canvas_item_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_ITEM_H__ */
|
||||
404
app/display/pikacanvaslayerboundary.c
Normal file
404
app/display/pikacanvaslayerboundary.c
Normal file
@ -0,0 +1,404 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaslayerboundary.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikachannel.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikalayer-floating-selection.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvaslayerboundary.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LAYERS,
|
||||
PROP_EDIT_MASK
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasLayerBoundaryPrivate PikaCanvasLayerBoundaryPrivate;
|
||||
|
||||
struct _PikaCanvasLayerBoundaryPrivate
|
||||
{
|
||||
GList *layers;
|
||||
gboolean edit_mask;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(layer_boundary) \
|
||||
((PikaCanvasLayerBoundaryPrivate *) pika_canvas_layer_boundary_get_instance_private ((PikaCanvasLayerBoundary *) (layer_boundary)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_layer_boundary_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_layer_boundary_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_layer_boundary_finalize (GObject *object);
|
||||
static void pika_canvas_layer_boundary_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_layer_boundary_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_layer_boundary_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasLayerBoundary, pika_canvas_layer_boundary,
|
||||
PIKA_TYPE_CANVAS_RECTANGLE)
|
||||
|
||||
#define parent_class pika_canvas_layer_boundary_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_class_init (PikaCanvasLayerBoundaryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_layer_boundary_set_property;
|
||||
object_class->get_property = pika_canvas_layer_boundary_get_property;
|
||||
object_class->finalize = pika_canvas_layer_boundary_finalize;
|
||||
|
||||
item_class->draw = pika_canvas_layer_boundary_draw;
|
||||
item_class->get_extents = pika_canvas_layer_boundary_get_extents;
|
||||
item_class->stroke = pika_canvas_layer_boundary_stroke;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_LAYERS,
|
||||
g_param_spec_pointer ("layers", NULL, NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_EDIT_MASK,
|
||||
g_param_spec_boolean ("edit-mask", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_init (PikaCanvasLayerBoundary *layer_boundary)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
if (private->layers)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = private->layers; iter; iter = iter->next)
|
||||
g_clear_weak_pointer (&iter->data);
|
||||
|
||||
g_list_free (private->layers);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_LAYERS:
|
||||
if (private->layers)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = private->layers; iter; iter = iter->next)
|
||||
g_clear_weak_pointer (&iter->data);
|
||||
|
||||
g_list_free (private->layers);
|
||||
}
|
||||
|
||||
private->layers = g_list_copy (g_value_get_pointer (value));
|
||||
|
||||
if (private->layers)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = private->layers; iter; iter = iter->next)
|
||||
/* NOT g_set_weak_pointer() because the pointer is already set */
|
||||
g_object_add_weak_pointer (G_OBJECT (iter->data),
|
||||
(gpointer) &iter->data);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_EDIT_MASK:
|
||||
private->edit_mask = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_LAYERS:
|
||||
g_value_set_pointer (value, private->layers);
|
||||
break;
|
||||
case PROP_EDIT_MASK:
|
||||
g_value_set_boolean (value, private->edit_mask);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->layers)
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->draw (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_layer_boundary_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->layers)
|
||||
return PIKA_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_layer_boundary_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
GList *iter;
|
||||
|
||||
for (iter = private->layers; iter; iter = iter->next)
|
||||
{
|
||||
pika_canvas_set_layer_style (pika_canvas_item_get_canvas (item), cr,
|
||||
iter->data, shell->offset_x, shell->offset_y);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_layer_boundary_new (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_LAYER_BOUNDARY,
|
||||
"shell", shell,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_layer_boundary_set_layers (PikaCanvasLayerBoundary *boundary,
|
||||
GList *layers)
|
||||
{
|
||||
PikaCanvasLayerBoundaryPrivate *private;
|
||||
GList *shown_layers;
|
||||
GList *iter;
|
||||
gboolean changed;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_LAYER_BOUNDARY (boundary));
|
||||
|
||||
private = GET_PRIVATE (boundary);
|
||||
|
||||
if (g_list_length (layers) == 1 && pika_layer_is_floating_sel (layers->data))
|
||||
{
|
||||
PikaDrawable *drawable;
|
||||
|
||||
drawable = pika_layer_get_floating_sel_drawable (layers->data);
|
||||
|
||||
if (PIKA_IS_CHANNEL (drawable))
|
||||
{
|
||||
/* if the owner drawable is a channel, show no outline */
|
||||
|
||||
shown_layers = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, set the layer to the owner drawable */
|
||||
|
||||
shown_layers = g_list_prepend (NULL, PIKA_LAYER (drawable));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shown_layers = g_list_copy (layers);
|
||||
}
|
||||
|
||||
changed = (g_list_length (shown_layers) != g_list_length (private->layers));
|
||||
if (! changed)
|
||||
{
|
||||
for (iter = shown_layers; iter; iter = iter->next)
|
||||
{
|
||||
if (! g_list_find (private->layers, iter->data))
|
||||
{
|
||||
changed = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
gboolean edit_mask = FALSE;
|
||||
gint x1 = G_MAXINT;
|
||||
gint x2 = G_MININT;
|
||||
gint y1 = G_MAXINT;
|
||||
gint y2 = G_MININT;
|
||||
|
||||
for (iter = layers; iter; iter = iter->next)
|
||||
{
|
||||
if (iter->data)
|
||||
{
|
||||
PikaItem *item = PIKA_ITEM (iter->data);
|
||||
|
||||
x1 = MIN (x1, pika_item_get_offset_x (item));
|
||||
y1 = MIN (y1, pika_item_get_offset_y (item));
|
||||
|
||||
x2 = MAX (x2,
|
||||
pika_item_get_offset_x (item) +
|
||||
pika_item_get_width (item));
|
||||
y2 = MAX (y2,
|
||||
pika_item_get_offset_y (item) +
|
||||
pika_item_get_height (item));
|
||||
|
||||
/* We can only edit one layer mask at a time. */
|
||||
if (pika_layer_get_mask (iter->data) &&
|
||||
pika_layer_get_edit_mask (iter->data))
|
||||
edit_mask = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
pika_canvas_item_begin_change (PIKA_CANVAS_ITEM (boundary));
|
||||
|
||||
if (layers)
|
||||
g_object_set (boundary,
|
||||
"x", (gdouble) x1,
|
||||
"y", (gdouble) y1,
|
||||
"width", (gdouble) (x2 - x1),
|
||||
"height", (gdouble) (y2 - y1),
|
||||
NULL);
|
||||
g_object_set (boundary,
|
||||
"layers", layers,
|
||||
"edit-mask", edit_mask,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (PIKA_CANVAS_ITEM (boundary));
|
||||
}
|
||||
else if (layers)
|
||||
{
|
||||
gboolean edit_mask = FALSE;
|
||||
gint x1 = G_MAXINT;
|
||||
gint x2 = G_MININT;
|
||||
gint y1 = G_MAXINT;
|
||||
gint y2 = G_MININT;
|
||||
gdouble x, y, w, h;
|
||||
|
||||
g_object_get (boundary,
|
||||
"x", &x,
|
||||
"y", &y,
|
||||
"width", &w,
|
||||
"height", &h,
|
||||
NULL);
|
||||
|
||||
for (iter = layers; iter; iter = iter->next)
|
||||
{
|
||||
if (iter->data)
|
||||
{
|
||||
PikaItem *item = PIKA_ITEM (iter->data);
|
||||
|
||||
x1 = MIN (x1, pika_item_get_offset_x (item));
|
||||
y1 = MIN (y1, pika_item_get_offset_y (item));
|
||||
|
||||
x2 = MAX (x2,
|
||||
pika_item_get_offset_x (item) +
|
||||
pika_item_get_width (item));
|
||||
y2 = MAX (y2,
|
||||
pika_item_get_offset_y (item) +
|
||||
pika_item_get_height (item));
|
||||
|
||||
if (pika_layer_get_mask (iter->data) &&
|
||||
pika_layer_get_edit_mask (iter->data))
|
||||
edit_mask = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (x1 != (gint) x ||
|
||||
x1 != (gint) y ||
|
||||
(x2 - x1) != (gint) w ||
|
||||
(y2 - y1) != (gint) h ||
|
||||
edit_mask != private->edit_mask)
|
||||
{
|
||||
pika_canvas_item_begin_change (PIKA_CANVAS_ITEM (boundary));
|
||||
|
||||
g_object_set (boundary,
|
||||
"x", (gdouble) x1,
|
||||
"y", (gdouble) y1,
|
||||
"width", (gdouble) (x2 - x1),
|
||||
"height", (gdouble) (y2 - y1),
|
||||
"edit-mask", edit_mask,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (PIKA_CANVAS_ITEM (boundary));
|
||||
}
|
||||
}
|
||||
g_list_free (shown_layers);
|
||||
}
|
||||
62
app/display/pikacanvaslayerboundary.h
Normal file
62
app/display/pikacanvaslayerboundary.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvaslayerboundary.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_LAYER_BOUNDARY_H__
|
||||
#define __PIKA_CANVAS_LAYER_BOUNDARY_H__
|
||||
|
||||
|
||||
#include "pikacanvasrectangle.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_LAYER_BOUNDARY (pika_canvas_layer_boundary_get_type ())
|
||||
#define PIKA_CANVAS_LAYER_BOUNDARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_LAYER_BOUNDARY, PikaCanvasLayerBoundary))
|
||||
#define PIKA_CANVAS_LAYER_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_LAYER_BOUNDARY, PikaCanvasLayerBoundaryClass))
|
||||
#define PIKA_IS_CANVAS_LAYER_BOUNDARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_LAYER_BOUNDARY))
|
||||
#define PIKA_IS_CANVAS_LAYER_BOUNDARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_LAYER_BOUNDARY))
|
||||
#define PIKA_CANVAS_LAYER_BOUNDARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_LAYER_BOUNDARY, PikaCanvasLayerBoundaryClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasLayerBoundary PikaCanvasLayerBoundary;
|
||||
typedef struct _PikaCanvasLayerBoundaryClass PikaCanvasLayerBoundaryClass;
|
||||
|
||||
struct _PikaCanvasLayerBoundary
|
||||
{
|
||||
PikaCanvasRectangle parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasLayerBoundaryClass
|
||||
{
|
||||
PikaCanvasRectangleClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_layer_boundary_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_layer_boundary_new (PikaDisplayShell *shell);
|
||||
|
||||
void pika_canvas_layer_boundary_set_layers (PikaCanvasLayerBoundary *boundary,
|
||||
GList *layers);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_LAYER_BOUNDARY_H__ */
|
||||
764
app/display/pikacanvaslimit.c
Normal file
764
app/display/pikacanvaslimit.c
Normal file
@ -0,0 +1,764 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaslimit.c
|
||||
* Copyright (C) 2020 Ell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
|
||||
#include "pikacanvaslimit.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define DASH_LENGTH 4.0
|
||||
#define HIT_DISTANCE 16.0
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TYPE,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_RADIUS,
|
||||
PROP_ASPECT_RATIO,
|
||||
PROP_ANGLE,
|
||||
PROP_DASHED
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasLimitPrivate PikaCanvasLimitPrivate;
|
||||
|
||||
struct _PikaCanvasLimitPrivate
|
||||
{
|
||||
PikaLimitType type;
|
||||
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble radius;
|
||||
gdouble aspect_ratio;
|
||||
gdouble angle;
|
||||
|
||||
gboolean dashed;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(limit) \
|
||||
((PikaCanvasLimitPrivate *) pika_canvas_limit_get_instance_private ((PikaCanvasLimit *) (limit)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_limit_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_limit_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_canvas_limit_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_limit_get_extents (PikaCanvasItem *item);
|
||||
static gboolean pika_canvas_limit_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasLimit, pika_canvas_limit,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_limit_parent_class
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_canvas_limit_class_init (PikaCanvasLimitClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_limit_set_property;
|
||||
object_class->get_property = pika_canvas_limit_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_limit_draw;
|
||||
item_class->get_extents = pika_canvas_limit_get_extents;
|
||||
item_class->hit = pika_canvas_limit_hit;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TYPE,
|
||||
g_param_spec_enum ("type", NULL, NULL,
|
||||
PIKA_TYPE_LIMIT_TYPE,
|
||||
PIKA_LIMIT_CIRCLE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-G_MAXDOUBLE,
|
||||
+G_MAXDOUBLE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-G_MAXDOUBLE,
|
||||
+G_MAXDOUBLE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RADIUS,
|
||||
g_param_spec_double ("radius", NULL, NULL,
|
||||
0.0,
|
||||
+G_MAXDOUBLE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ASPECT_RATIO,
|
||||
g_param_spec_double ("aspect-ratio", NULL, NULL,
|
||||
-1.0,
|
||||
+1.0,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ANGLE,
|
||||
g_param_spec_double ("angle", NULL, NULL,
|
||||
-G_MAXDOUBLE,
|
||||
+G_MAXDOUBLE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_DASHED,
|
||||
g_param_spec_boolean ("dashed", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_limit_init (PikaCanvasLimit *limit)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_limit_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TYPE:
|
||||
priv->type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_X:
|
||||
priv->x = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_Y:
|
||||
priv->y = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_RADIUS:
|
||||
priv->radius = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_ASPECT_RATIO:
|
||||
priv->aspect_ratio = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_ANGLE:
|
||||
priv->angle = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_DASHED:
|
||||
priv->dashed = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_limit_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TYPE:
|
||||
g_value_set_enum (value, priv->type);
|
||||
break;
|
||||
|
||||
case PROP_X:
|
||||
g_value_set_double (value, priv->x);
|
||||
break;
|
||||
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, priv->y);
|
||||
break;
|
||||
|
||||
case PROP_RADIUS:
|
||||
g_value_set_double (value, priv->radius);
|
||||
break;
|
||||
|
||||
case PROP_ASPECT_RATIO:
|
||||
g_value_set_double (value, priv->aspect_ratio);
|
||||
break;
|
||||
|
||||
case PROP_ANGLE:
|
||||
g_value_set_double (value, priv->angle);
|
||||
break;
|
||||
|
||||
case PROP_DASHED:
|
||||
g_value_set_boolean (value, priv->dashed);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_limit_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y,
|
||||
gdouble *rx,
|
||||
gdouble *ry)
|
||||
{
|
||||
PikaCanvasLimit *limit = PIKA_CANVAS_LIMIT (item);
|
||||
PikaCanvasLimitPrivate *priv = GET_PRIVATE (item);
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
gdouble min_radius = 0.0;
|
||||
|
||||
pika_canvas_limit_get_radii (limit, rx, ry);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
priv->x - *rx, priv->y - *ry,
|
||||
&x1, &y1);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
priv->x + *rx, priv->y + *ry,
|
||||
&x2, &y2);
|
||||
|
||||
x1 = floor (x1) + 0.5;
|
||||
y1 = floor (y1) + 0.5;
|
||||
|
||||
x2 = floor (x2) + 0.5;
|
||||
y2 = floor (y2) + 0.5;
|
||||
|
||||
*x = (x1 + x2) / 2.0;
|
||||
*y = (y1 + y2) / 2.0;
|
||||
|
||||
*rx = (x2 - x1) / 2.0;
|
||||
*ry = (y2 - y1) / 2.0;
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
case PIKA_LIMIT_CIRCLE:
|
||||
case PIKA_LIMIT_SQUARE:
|
||||
min_radius = 2.0;
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_DIAMOND:
|
||||
min_radius = 3.0;
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_HORIZONTAL:
|
||||
case PIKA_LIMIT_VERTICAL:
|
||||
min_radius = 1.0;
|
||||
break;
|
||||
}
|
||||
|
||||
*rx = MAX (*rx, min_radius);
|
||||
*ry = MAX (*ry, min_radius);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_limit_paint (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv = GET_PRIVATE (item);
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
gdouble x, y;
|
||||
gdouble rx, ry;
|
||||
gdouble inf;
|
||||
|
||||
pika_canvas_limit_transform (item,
|
||||
&x, &y,
|
||||
&rx, &ry);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_translate (cr, x, y);
|
||||
cairo_rotate (cr, priv->angle);
|
||||
cairo_scale (cr, rx, ry);
|
||||
|
||||
inf = MAX (x, shell->disp_width - x) +
|
||||
MAX (y, shell->disp_height - y);
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
case PIKA_LIMIT_CIRCLE:
|
||||
cairo_arc (cr, 0.0, 0.0, 1.0, 0.0, 2.0 * G_PI);
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_SQUARE:
|
||||
cairo_rectangle (cr, -1.0, -1.0, 2.0, 2.0);
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_DIAMOND:
|
||||
cairo_move_to (cr, 0.0, -1.0);
|
||||
cairo_line_to (cr, +1.0, 0.0);
|
||||
cairo_line_to (cr, 0.0, +1.0);
|
||||
cairo_line_to (cr, -1.0, 0.0);
|
||||
cairo_close_path (cr);
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_HORIZONTAL:
|
||||
cairo_move_to (cr, -inf / rx, -1.0);
|
||||
cairo_line_to (cr, +inf / rx, -1.0);
|
||||
|
||||
cairo_move_to (cr, -inf / rx, +1.0);
|
||||
cairo_line_to (cr, +inf / rx, +1.0);
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_VERTICAL:
|
||||
cairo_move_to (cr, -1.0, -inf / ry);
|
||||
cairo_line_to (cr, -1.0, +inf / ry);
|
||||
|
||||
cairo_move_to (cr, +1.0, -inf / ry);
|
||||
cairo_line_to (cr, +1.0, +inf / ry);
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_limit_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_limit_paint (item, cr);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
if (priv->dashed)
|
||||
cairo_set_dash (cr, (const gdouble[]) {DASH_LENGTH}, 1, 0.0);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_limit_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
pika_canvas_limit_paint (item, cr);
|
||||
|
||||
cairo_path_extents (cr,
|
||||
&x1, &y1,
|
||||
&x2, &y2);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
rectangle.x = floor (x1 - 1.5);
|
||||
rectangle.y = floor (y1 - 1.5);
|
||||
rectangle.width = ceil (x2 + 1.5) - rectangle.x;
|
||||
rectangle.height = ceil (y2 + 1.5) - rectangle.y;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_limit_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasLimit *limit = PIKA_CANVAS_LIMIT (item);
|
||||
gdouble bx, by;
|
||||
|
||||
pika_canvas_limit_boundary_point (limit,
|
||||
x, y,
|
||||
&bx, &by);
|
||||
|
||||
return pika_canvas_item_transform_distance (item,
|
||||
x, y,
|
||||
bx, by) <= HIT_DISTANCE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_limit_new (PikaDisplayShell *shell,
|
||||
PikaLimitType type,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble radius,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean dashed)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_LIMIT,
|
||||
"shell", shell,
|
||||
"type", type,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"radius", radius,
|
||||
"aspect-ratio", aspect_ratio,
|
||||
"angle", angle,
|
||||
"dashed", dashed,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_limit_get_radii (PikaCanvasLimit *limit,
|
||||
gdouble *rx,
|
||||
gdouble *ry)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_LIMIT (limit));
|
||||
|
||||
priv = GET_PRIVATE (limit);
|
||||
|
||||
if (priv->aspect_ratio >= 0.0)
|
||||
{
|
||||
if (rx) *rx = priv->radius;
|
||||
if (ry) *ry = priv->radius * (1.0 - priv->aspect_ratio);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rx) *rx = priv->radius * (1.0 + priv->aspect_ratio);
|
||||
if (ry) *ry = priv->radius;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_canvas_limit_is_inside (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv;
|
||||
PikaVector2 p;
|
||||
gdouble rx, ry;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_LIMIT (limit), FALSE);
|
||||
|
||||
priv = GET_PRIVATE (limit);
|
||||
|
||||
pika_canvas_limit_get_radii (limit, &rx, &ry);
|
||||
|
||||
if (rx == 0.0 || ry == 0.0)
|
||||
return FALSE;
|
||||
|
||||
p.x = x - priv->x;
|
||||
p.y = y - priv->y;
|
||||
|
||||
pika_vector2_rotate (&p, +priv->angle);
|
||||
|
||||
p.x = fabs (p.x / rx);
|
||||
p.y = fabs (p.y / ry);
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
case PIKA_LIMIT_CIRCLE:
|
||||
return pika_vector2_length (&p) < 1.0;
|
||||
|
||||
case PIKA_LIMIT_SQUARE:
|
||||
return p.x < 1.0 && p.y < 1.0;
|
||||
|
||||
case PIKA_LIMIT_DIAMOND:
|
||||
return p.x + p.y < 1.0;
|
||||
|
||||
case PIKA_LIMIT_HORIZONTAL:
|
||||
return p.y < 1.0;
|
||||
|
||||
case PIKA_LIMIT_VERTICAL:
|
||||
return p.x < 1.0;
|
||||
}
|
||||
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_limit_boundary_point (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *bx,
|
||||
gdouble *by)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv;
|
||||
PikaVector2 p;
|
||||
gdouble rx, ry;
|
||||
gboolean flip_x = FALSE;
|
||||
gboolean flip_y = FALSE;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_LIMIT (limit));
|
||||
g_return_if_fail (bx != NULL);
|
||||
g_return_if_fail (by != NULL);
|
||||
|
||||
priv = GET_PRIVATE (limit);
|
||||
|
||||
pika_canvas_limit_get_radii (limit, &rx, &ry);
|
||||
|
||||
p.x = x - priv->x;
|
||||
p.y = y - priv->y;
|
||||
|
||||
pika_vector2_rotate (&p, +priv->angle);
|
||||
|
||||
if (p.x < 0.0)
|
||||
{
|
||||
p.x = -p.x;
|
||||
|
||||
flip_x = TRUE;
|
||||
}
|
||||
|
||||
if (p.y < 0.0)
|
||||
{
|
||||
p.y = -p.y;
|
||||
|
||||
flip_y = TRUE;
|
||||
}
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
case PIKA_LIMIT_CIRCLE:
|
||||
if (rx == ry)
|
||||
{
|
||||
pika_vector2_normalize (&p);
|
||||
|
||||
pika_vector2_mul (&p, rx);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdouble a0 = 0.0;
|
||||
gdouble a1 = G_PI / 2.0;
|
||||
gdouble a;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
PikaVector2 r;
|
||||
PikaVector2 n;
|
||||
|
||||
a = (a0 + a1) / 2.0;
|
||||
|
||||
r.x = p.x - rx * cos (a);
|
||||
r.y = p.y - ry * sin (a);
|
||||
|
||||
n.x = 1.0;
|
||||
n.y = tan (a) * rx / ry;
|
||||
|
||||
if (pika_vector2_cross_product (&r, &n).x >= 0.0)
|
||||
a1 = a;
|
||||
else
|
||||
a0 = a;
|
||||
}
|
||||
|
||||
a = (a0 + a1) / 2.0;
|
||||
|
||||
p.x = rx * cos (a);
|
||||
p.y = ry * sin (a);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_SQUARE:
|
||||
if (p.x <= rx || p.y <= ry)
|
||||
{
|
||||
if (rx - p.x <= ry - p.y)
|
||||
p.x = rx;
|
||||
else
|
||||
p.y = ry;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.x = rx;
|
||||
p.y = ry;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_DIAMOND:
|
||||
{
|
||||
PikaVector2 l;
|
||||
PikaVector2 r;
|
||||
gdouble t;
|
||||
|
||||
l.x = rx;
|
||||
l.y = -ry;
|
||||
|
||||
r.x = p.x;
|
||||
r.y = p.y - ry;
|
||||
|
||||
t = pika_vector2_inner_product (&r, &l) /
|
||||
pika_vector2_inner_product (&l, &l);
|
||||
t = CLAMP (t, 0.0, 1.0);
|
||||
|
||||
p.x = rx * t;
|
||||
p.y = ry * (1.0 - t);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_HORIZONTAL:
|
||||
p.y = ry;
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_VERTICAL:
|
||||
p.x = rx;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flip_x)
|
||||
p.x = -p.x;
|
||||
|
||||
if (flip_y)
|
||||
p.y = -p.y;
|
||||
|
||||
pika_vector2_rotate (&p, -priv->angle);
|
||||
|
||||
*bx = priv->x + p.x;
|
||||
*by = priv->y + p.y;
|
||||
}
|
||||
|
||||
gdouble
|
||||
pika_canvas_limit_boundary_radius (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv;
|
||||
PikaVector2 p;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_LIMIT (limit), 0.0);
|
||||
|
||||
priv = GET_PRIVATE (limit);
|
||||
|
||||
p.x = x - priv->x;
|
||||
p.y = y - priv->y;
|
||||
|
||||
pika_vector2_rotate (&p, +priv->angle);
|
||||
|
||||
p.x = fabs (p.x);
|
||||
p.y = fabs (p.y);
|
||||
|
||||
if (priv->aspect_ratio >= 0.0)
|
||||
p.y /= 1.0 - priv->aspect_ratio;
|
||||
else
|
||||
p.x /= 1.0 + priv->aspect_ratio;
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
case PIKA_LIMIT_CIRCLE:
|
||||
return pika_vector2_length (&p);
|
||||
|
||||
case PIKA_LIMIT_SQUARE:
|
||||
return MAX (p.x, p.y);
|
||||
|
||||
case PIKA_LIMIT_DIAMOND:
|
||||
return p.x + p.y;
|
||||
|
||||
case PIKA_LIMIT_HORIZONTAL:
|
||||
return p.y;
|
||||
|
||||
case PIKA_LIMIT_VERTICAL:
|
||||
return p.x;
|
||||
}
|
||||
|
||||
g_return_val_if_reached (0.0);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_limit_center_point (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *cx,
|
||||
gdouble *cy)
|
||||
{
|
||||
PikaCanvasLimitPrivate *priv;
|
||||
PikaVector2 p;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_LIMIT (limit));
|
||||
g_return_if_fail (cx != NULL);
|
||||
g_return_if_fail (cy != NULL);
|
||||
|
||||
priv = GET_PRIVATE (limit);
|
||||
|
||||
p.x = x - priv->x;
|
||||
p.y = y - priv->y;
|
||||
|
||||
pika_vector2_rotate (&p, +priv->angle);
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
case PIKA_LIMIT_CIRCLE:
|
||||
case PIKA_LIMIT_SQUARE:
|
||||
case PIKA_LIMIT_DIAMOND:
|
||||
p.x = 0.0;
|
||||
p.y = 0.0;
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_HORIZONTAL:
|
||||
p.y = 0.0;
|
||||
break;
|
||||
|
||||
case PIKA_LIMIT_VERTICAL:
|
||||
p.x = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
pika_vector2_rotate (&p, -priv->angle);
|
||||
|
||||
*cx = priv->x + p.x;
|
||||
*cy = priv->y + p.y;
|
||||
}
|
||||
88
app/display/pikacanvaslimit.h
Normal file
88
app/display/pikacanvaslimit.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaslimit.h
|
||||
* Copyright (C) 2020 Ell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_LIMIT_H__
|
||||
#define __PIKA_CANVAS_LIMIT_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_LIMIT (pika_canvas_limit_get_type ())
|
||||
#define PIKA_CANVAS_LIMIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_LIMIT, PikaCanvasLimit))
|
||||
#define PIKA_CANVAS_LIMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_LIMIT, PikaCanvasLimitClass))
|
||||
#define PIKA_IS_CANVAS_LIMIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_LIMIT))
|
||||
#define PIKA_IS_CANVAS_LIMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_LIMIT))
|
||||
#define PIKA_CANVAS_LIMIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_LIMIT, PikaCanvasLimitClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasLimit PikaCanvasLimit;
|
||||
typedef struct _PikaCanvasLimitClass PikaCanvasLimitClass;
|
||||
|
||||
struct _PikaCanvasLimit
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasLimitClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_limit_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_limit_new (PikaDisplayShell *shell,
|
||||
PikaLimitType type,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble radius,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean dashed);
|
||||
|
||||
void pika_canvas_limit_get_radii (PikaCanvasLimit *limit,
|
||||
gdouble *rx,
|
||||
gdouble *ry);
|
||||
|
||||
gboolean pika_canvas_limit_is_inside (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
void pika_canvas_limit_boundary_point (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *bx,
|
||||
gdouble *by);
|
||||
gdouble pika_canvas_limit_boundary_radius (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
void pika_canvas_limit_center_point (PikaCanvasLimit *limit,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *cx,
|
||||
gdouble *cy);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_LIMIT_H__ */
|
||||
285
app/display/pikacanvasline.c
Normal file
285
app/display/pikacanvasline.c
Normal file
@ -0,0 +1,285 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasline.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvasline.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X1,
|
||||
PROP_Y1,
|
||||
PROP_X2,
|
||||
PROP_Y2
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasLinePrivate PikaCanvasLinePrivate;
|
||||
|
||||
struct _PikaCanvasLinePrivate
|
||||
{
|
||||
gdouble x1;
|
||||
gdouble y1;
|
||||
gdouble x2;
|
||||
gdouble y2;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(line) \
|
||||
((PikaCanvasLinePrivate *) pika_canvas_line_get_instance_private ((PikaCanvasLine *) (line)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_line_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_line_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_line_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_line_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasLine, pika_canvas_line,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_line_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_line_class_init (PikaCanvasLineClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_line_set_property;
|
||||
object_class->get_property = pika_canvas_line_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_line_draw;
|
||||
item_class->get_extents = pika_canvas_line_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X1,
|
||||
g_param_spec_double ("x1", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y1,
|
||||
g_param_spec_double ("y1", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X2,
|
||||
g_param_spec_double ("x2", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y2,
|
||||
g_param_spec_double ("y2", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_line_init (PikaCanvasLine *line)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_line_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasLinePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X1:
|
||||
private->x1 = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y1:
|
||||
private->y1 = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_X2:
|
||||
private->x2 = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y2:
|
||||
private->y2 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_line_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasLinePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X1:
|
||||
g_value_set_double (value, private->x1);
|
||||
break;
|
||||
case PROP_Y1:
|
||||
g_value_set_double (value, private->y1);
|
||||
break;
|
||||
case PROP_X2:
|
||||
g_value_set_double (value, private->x2);
|
||||
break;
|
||||
case PROP_Y2:
|
||||
g_value_set_double (value, private->y2);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_line_transform (PikaCanvasItem *item,
|
||||
gdouble *x1,
|
||||
gdouble *y1,
|
||||
gdouble *x2,
|
||||
gdouble *y2)
|
||||
{
|
||||
PikaCanvasLinePrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x1, private->y1,
|
||||
x1, y1);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x2, private->y2,
|
||||
x2, y2);
|
||||
|
||||
*x1 = floor (*x1) + 0.5;
|
||||
*y1 = floor (*y1) + 0.5;
|
||||
*x2 = floor (*x2) + 0.5;
|
||||
*y2 = floor (*y2) + 0.5;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_line_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_line_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
cairo_move_to (cr, x1, y1);
|
||||
cairo_line_to (cr, x2, y2);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_line_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_line_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
if (x1 == x2 || y1 == y2)
|
||||
{
|
||||
rectangle.x = MIN (x1, x2) - 1.5;
|
||||
rectangle.y = MIN (y1, y2) - 1.5;
|
||||
rectangle.width = ABS (x2 - x1) + 3.0;
|
||||
rectangle.height = ABS (y2 - y1) + 3.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangle.x = floor (MIN (x1, x2) - 2.5);
|
||||
rectangle.y = floor (MIN (y1, y2) - 2.5);
|
||||
rectangle.width = ceil (ABS (x2 - x1) + 5.0);
|
||||
rectangle.height = ceil (ABS (y2 - y1) + 5.0);
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_line_new (PikaDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_LINE,
|
||||
"shell", shell,
|
||||
"x1", x1,
|
||||
"y1", y1,
|
||||
"x2", x2,
|
||||
"y2", y2,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_line_set (PikaCanvasItem *line,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_LINE (line));
|
||||
|
||||
pika_canvas_item_begin_change (line);
|
||||
|
||||
g_object_set (line,
|
||||
"x1", x1,
|
||||
"y1", y1,
|
||||
"x2", x2,
|
||||
"y2", y2,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (line);
|
||||
}
|
||||
69
app/display/pikacanvasline.h
Normal file
69
app/display/pikacanvasline.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasline.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_LINE_H__
|
||||
#define __PIKA_CANVAS_LINE_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_LINE (pika_canvas_line_get_type ())
|
||||
#define PIKA_CANVAS_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_LINE, PikaCanvasLine))
|
||||
#define PIKA_CANVAS_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_LINE, PikaCanvasLineClass))
|
||||
#define PIKA_IS_CANVAS_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_LINE))
|
||||
#define PIKA_IS_CANVAS_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_LINE))
|
||||
#define PIKA_CANVAS_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_LINE, PikaCanvasLineClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasLine PikaCanvasLine;
|
||||
typedef struct _PikaCanvasLineClass PikaCanvasLineClass;
|
||||
|
||||
struct _PikaCanvasLine
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasLineClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_line_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_line_new (PikaDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2);
|
||||
|
||||
void pika_canvas_line_set (PikaCanvasItem *line,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_LINE_H__ */
|
||||
241
app/display/pikacanvaspassepartout.c
Normal file
241
app/display/pikacanvaspassepartout.c
Normal file
@ -0,0 +1,241 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaspassepartout.c
|
||||
* Copyright (C) 2010 Sven Neumann <sven@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvasitem-utils.h"
|
||||
#include "pikacanvaspassepartout.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-scale.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_OPACITY,
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPassePartoutPrivate PikaCanvasPassePartoutPrivate;
|
||||
|
||||
struct _PikaCanvasPassePartoutPrivate
|
||||
{
|
||||
gdouble opacity;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(item) \
|
||||
((PikaCanvasPassePartoutPrivate *) pika_canvas_passe_partout_get_instance_private ((PikaCanvasPassePartout *) (item)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_passe_partout_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_passe_partout_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_passe_partout_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_passe_partout_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_passe_partout_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasPassePartout, pika_canvas_passe_partout,
|
||||
PIKA_TYPE_CANVAS_RECTANGLE)
|
||||
|
||||
#define parent_class pika_canvas_passe_partout_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_passe_partout_class_init (PikaCanvasPassePartoutClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_passe_partout_set_property;
|
||||
object_class->get_property = pika_canvas_passe_partout_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_passe_partout_draw;
|
||||
item_class->get_extents = pika_canvas_passe_partout_get_extents;
|
||||
item_class->fill = pika_canvas_passe_partout_fill;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OPACITY,
|
||||
g_param_spec_double ("opacity", NULL, NULL,
|
||||
0.0,
|
||||
1.0, 0.5,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_passe_partout_init (PikaCanvasPassePartout *passe_partout)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_passe_partout_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPassePartoutPrivate *priv = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_OPACITY:
|
||||
priv->opacity = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_passe_partout_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPassePartoutPrivate *priv = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_OPACITY:
|
||||
g_value_set_double (value, priv->opacity);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_passe_partout_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
gint x, y;
|
||||
gint w, h;
|
||||
|
||||
if (! pika_display_shell_get_infinite_canvas (shell))
|
||||
{
|
||||
x = -shell->offset_x;
|
||||
y = -shell->offset_y;
|
||||
|
||||
pika_display_shell_scale_get_image_size (shell, &w, &h);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_canvas_item_untransform_viewport (item, &x, &y, &w, &h);
|
||||
}
|
||||
|
||||
cairo_rectangle (cr, x, y, w, h);
|
||||
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->draw (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_passe_partout_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
|
||||
if (! pika_display_shell_get_infinite_canvas (shell))
|
||||
{
|
||||
cairo_region_t *inner;
|
||||
cairo_region_t *outer;
|
||||
|
||||
rectangle.x = - shell->offset_x;
|
||||
rectangle.y = - shell->offset_y;
|
||||
pika_display_shell_scale_get_image_size (shell,
|
||||
&rectangle.width,
|
||||
&rectangle.height);
|
||||
|
||||
outer = cairo_region_create_rectangle (&rectangle);
|
||||
|
||||
inner = PIKA_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
|
||||
|
||||
cairo_region_xor (outer, inner);
|
||||
|
||||
cairo_region_destroy (inner);
|
||||
|
||||
return outer;
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_canvas_item_untransform_viewport (item,
|
||||
&rectangle.x,
|
||||
&rectangle.y,
|
||||
&rectangle.width,
|
||||
&rectangle.height);
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_passe_partout_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasPassePartoutPrivate *priv = GET_PRIVATE (item);
|
||||
|
||||
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
|
||||
cairo_clip (cr);
|
||||
|
||||
pika_canvas_set_passe_partout_style (pika_canvas_item_get_canvas (item), cr);
|
||||
cairo_paint_with_alpha (cr, priv->opacity);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_passe_partout_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_PASSE_PARTOUT,
|
||||
"shell", shell,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"filled", TRUE,
|
||||
NULL);
|
||||
}
|
||||
63
app/display/pikacanvaspassepartout.h
Normal file
63
app/display/pikacanvaspassepartout.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaspassepartout.h
|
||||
* Copyright (C) 2010 Sven Neumann <sven@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_PASSE_PARTOUT_H__
|
||||
#define __PIKA_CANVAS_PASSE_PARTOUT_H__
|
||||
|
||||
|
||||
#include "pikacanvasrectangle.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_PASSE_PARTOUT (pika_canvas_passe_partout_get_type ())
|
||||
#define PIKA_CANVAS_PASSE_PARTOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_PASSE_PARTOUT, PikaCanvasPassePartout))
|
||||
#define PIKA_CANVAS_PASSE_PARTOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_PASSE_PARTOUT, PikaCanvasPassePartoutClass))
|
||||
#define PIKA_IS_CANVAS_PASSE_PARTOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_PASSE_PARTOUT))
|
||||
#define PIKA_IS_CANVAS_PASSE_PARTOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_PASSE_PARTOUT))
|
||||
#define PIKA_CANVAS_PASSE_PARTOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_PASSE_PARTOUT, PikaCanvasPassePartoutClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPassePartout PikaCanvasPassePartout;
|
||||
typedef struct _PikaCanvasPassePartoutClass PikaCanvasPassePartoutClass;
|
||||
|
||||
struct _PikaCanvasPassePartout
|
||||
{
|
||||
PikaCanvasRectangle parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasPassePartoutClass
|
||||
{
|
||||
PikaCanvasRectangleClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_passe_partout_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_passe_partout_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_PASSE_PARTOUT_H__ */
|
||||
359
app/display/pikacanvaspath.c
Normal file
359
app/display/pikacanvaspath.c
Normal file
@ -0,0 +1,359 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvaspath.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikabezierdesc.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvaspath.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_FILLED,
|
||||
PROP_PATH_STYLE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPathPrivate PikaCanvasPathPrivate;
|
||||
|
||||
struct _PikaCanvasPathPrivate
|
||||
{
|
||||
cairo_path_t *path;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gboolean filled;
|
||||
PikaPathStyle path_style;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(path) \
|
||||
((PikaCanvasPathPrivate *) pika_canvas_path_get_instance_private ((PikaCanvasPath *) (path)))
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_path_finalize (GObject *object);
|
||||
static void pika_canvas_path_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_path_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_path_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_path_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_path_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasPath, pika_canvas_path,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_path_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_path_class_init (PikaCanvasPathClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_path_finalize;
|
||||
object_class->set_property = pika_canvas_path_set_property;
|
||||
object_class->get_property = pika_canvas_path_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_path_draw;
|
||||
item_class->get_extents = pika_canvas_path_get_extents;
|
||||
item_class->stroke = pika_canvas_path_stroke;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PATH,
|
||||
g_param_spec_boxed ("path", NULL, NULL,
|
||||
PIKA_TYPE_BEZIER_DESC,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FILLED,
|
||||
g_param_spec_boolean ("filled", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PATH_STYLE,
|
||||
g_param_spec_enum ("path-style", NULL, NULL,
|
||||
PIKA_TYPE_PATH_STYLE,
|
||||
PIKA_PATH_STYLE_DEFAULT,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_path_init (PikaCanvasPath *path)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_path_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasPathPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
if (private->path)
|
||||
{
|
||||
pika_bezier_desc_free (private->path);
|
||||
private->path = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_path_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPathPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
if (private->path)
|
||||
pika_bezier_desc_free (private->path);
|
||||
private->path = g_value_dup_boxed (value);
|
||||
break;
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_FILLED:
|
||||
private->filled = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PATH_STYLE:
|
||||
private->path_style = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_path_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPathPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_value_set_boxed (value, private->path);
|
||||
break;
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
case PROP_FILLED:
|
||||
g_value_set_boolean (value, private->filled);
|
||||
break;
|
||||
case PROP_PATH_STYLE:
|
||||
g_value_set_enum (value, private->path_style);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_path_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasPathPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->path)
|
||||
{
|
||||
cairo_save (cr);
|
||||
pika_canvas_item_transform (item, cr);
|
||||
cairo_translate (cr, private->x, private->y);
|
||||
|
||||
cairo_append_path (cr, private->path);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (private->filled)
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
else
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_path_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasPathPrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
|
||||
if (private->path && gtk_widget_get_realized (canvas))
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x1, y1, x2, y2;
|
||||
|
||||
surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR, NULL);
|
||||
cr = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_save (cr);
|
||||
pika_canvas_item_transform (item, cr);
|
||||
cairo_translate (cr, private->x, private->y);
|
||||
|
||||
cairo_append_path (cr, private->path);
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_path_extents (cr, &x1, &y1, &x2, &y2);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
if (private->filled)
|
||||
{
|
||||
rectangle.x = floor (x1 - 1.0);
|
||||
rectangle.y = floor (y1 - 1.0);
|
||||
rectangle.width = ceil (x2 + 1.0) - rectangle.x;
|
||||
rectangle.height = ceil (y2 + 1.0) - rectangle.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangle.x = floor (x1 - 1.5);
|
||||
rectangle.y = floor (y1 - 1.5);
|
||||
rectangle.width = ceil (x2 + 1.5) - rectangle.x;
|
||||
rectangle.height = ceil (y2 + 1.5) - rectangle.y;
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_path_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasPathPrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
gboolean active;
|
||||
|
||||
switch (private->path_style)
|
||||
{
|
||||
case PIKA_PATH_STYLE_VECTORS:
|
||||
active = pika_canvas_item_get_highlight (item);
|
||||
|
||||
pika_canvas_set_vectors_bg_style (canvas, cr, active);
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
pika_canvas_set_vectors_fg_style (canvas, cr, active);
|
||||
cairo_stroke (cr);
|
||||
break;
|
||||
|
||||
case PIKA_PATH_STYLE_OUTLINE:
|
||||
pika_canvas_set_outline_bg_style (canvas, cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
pika_canvas_set_outline_fg_style (canvas, cr);
|
||||
cairo_stroke (cr);
|
||||
break;
|
||||
|
||||
case PIKA_PATH_STYLE_DEFAULT:
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->stroke (item, cr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_path_new (PikaDisplayShell *shell,
|
||||
const PikaBezierDesc *bezier,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gboolean filled,
|
||||
PikaPathStyle style)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_PATH,
|
||||
"shell", shell,
|
||||
"path", bezier,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"filled", filled,
|
||||
"path-style", style,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_path_set (PikaCanvasItem *path,
|
||||
const PikaBezierDesc *bezier)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_PATH (path));
|
||||
|
||||
pika_canvas_item_begin_change (path);
|
||||
|
||||
g_object_set (path,
|
||||
"path", bezier,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (path);
|
||||
}
|
||||
67
app/display/pikacanvaspath.h
Normal file
67
app/display/pikacanvaspath.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvaspolygon.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_PATH_H__
|
||||
#define __PIKA_CANVAS_PATH_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_PATH (pika_canvas_path_get_type ())
|
||||
#define PIKA_CANVAS_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_PATH, PikaCanvasPath))
|
||||
#define PIKA_CANVAS_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_PATH, PikaCanvasPathClass))
|
||||
#define PIKA_IS_CANVAS_PATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_PATH))
|
||||
#define PIKA_IS_CANVAS_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_PATH))
|
||||
#define PIKA_CANVAS_PATH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_PATH, PikaCanvasPathClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPath PikaCanvasPath;
|
||||
typedef struct _PikaCanvasPathClass PikaCanvasPathClass;
|
||||
|
||||
struct _PikaCanvasPath
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasPathClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_path_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_path_new (PikaDisplayShell *shell,
|
||||
const PikaBezierDesc *bezier,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gboolean filled,
|
||||
PikaPathStyle style);
|
||||
|
||||
void pika_canvas_path_set (PikaCanvasItem *path,
|
||||
const PikaBezierDesc *bezier);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_PATH_H__ */
|
||||
235
app/display/pikacanvaspen.c
Normal file
235
app/display/pikacanvaspen.c
Normal file
@ -0,0 +1,235 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaspen.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvaspen.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_COLOR,
|
||||
PROP_WIDTH
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPenPrivate PikaCanvasPenPrivate;
|
||||
|
||||
struct _PikaCanvasPenPrivate
|
||||
{
|
||||
PikaRGB color;
|
||||
gint width;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(pen) \
|
||||
((PikaCanvasPenPrivate *) pika_canvas_pen_get_instance_private ((PikaCanvasPen *) (pen)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_pen_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_pen_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static cairo_region_t * pika_canvas_pen_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_pen_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasPen, pika_canvas_pen,
|
||||
PIKA_TYPE_CANVAS_POLYGON)
|
||||
|
||||
#define parent_class pika_canvas_pen_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_pen_class_init (PikaCanvasPenClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_pen_set_property;
|
||||
object_class->get_property = pika_canvas_pen_get_property;
|
||||
|
||||
item_class->get_extents = pika_canvas_pen_get_extents;
|
||||
item_class->stroke = pika_canvas_pen_stroke;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_COLOR,
|
||||
pika_param_spec_rgb ("color", NULL, NULL,
|
||||
FALSE, NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WIDTH,
|
||||
g_param_spec_int ("width", NULL, NULL,
|
||||
1, G_MAXINT, 1,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_pen_init (PikaCanvasPen *pen)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_pen_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPenPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_COLOR:
|
||||
pika_value_get_rgb (value, &private->color);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
private->width = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_pen_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPenPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_COLOR:
|
||||
pika_value_set_rgb (value, &private->color);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
g_value_set_int (value, private->width);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_pen_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasPenPrivate *private = GET_PRIVATE (item);
|
||||
cairo_region_t *region;
|
||||
|
||||
region = PIKA_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
|
||||
|
||||
if (region)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
|
||||
cairo_region_get_extents (region, &rectangle);
|
||||
|
||||
rectangle.x -= ceil (private->width / 2.0);
|
||||
rectangle.y -= ceil (private->width / 2.0);
|
||||
rectangle.width += private->width + 1;
|
||||
rectangle.height += private->width + 1;
|
||||
|
||||
cairo_region_union_rectangle (region, &rectangle);
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_pen_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasPenPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_set_pen_style (pika_canvas_item_get_canvas (item), cr,
|
||||
&private->color, private->width);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_pen_new (PikaDisplayShell *shell,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaContext *context,
|
||||
PikaActiveColor color,
|
||||
gint width)
|
||||
{
|
||||
PikaCanvasItem *item;
|
||||
PikaArray *array;
|
||||
PikaRGB rgb;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (points != NULL && n_points > 1, NULL);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
|
||||
|
||||
array = pika_array_new ((const guint8 *) points,
|
||||
n_points * sizeof (PikaVector2), TRUE);
|
||||
|
||||
switch (color)
|
||||
{
|
||||
case PIKA_ACTIVE_COLOR_FOREGROUND:
|
||||
pika_context_get_foreground (context, &rgb);
|
||||
break;
|
||||
|
||||
case PIKA_ACTIVE_COLOR_BACKGROUND:
|
||||
pika_context_get_background (context, &rgb);
|
||||
break;
|
||||
}
|
||||
|
||||
item = g_object_new (PIKA_TYPE_CANVAS_PEN,
|
||||
"shell", shell,
|
||||
"points", array,
|
||||
"color", &rgb,
|
||||
"width", width,
|
||||
NULL);
|
||||
|
||||
pika_array_free (array);
|
||||
|
||||
return item;
|
||||
}
|
||||
64
app/display/pikacanvaspen.h
Normal file
64
app/display/pikacanvaspen.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvaspen.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_PEN_H__
|
||||
#define __PIKA_CANVAS_PEN_H__
|
||||
|
||||
|
||||
#include "pikacanvaspolygon.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_PEN (pika_canvas_pen_get_type ())
|
||||
#define PIKA_CANVAS_PEN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_PEN, PikaCanvasPen))
|
||||
#define PIKA_CANVAS_PEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_PEN, PikaCanvasPenClass))
|
||||
#define PIKA_IS_CANVAS_PEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_PEN))
|
||||
#define PIKA_IS_CANVAS_PEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_PEN))
|
||||
#define PIKA_CANVAS_PEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_PEN, PikaCanvasPenClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPen PikaCanvasPen;
|
||||
typedef struct _PikaCanvasPenClass PikaCanvasPenClass;
|
||||
|
||||
struct _PikaCanvasPen
|
||||
{
|
||||
PikaCanvasPolygon parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasPenClass
|
||||
{
|
||||
PikaCanvasPolygonClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_pen_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_pen_new (PikaDisplayShell *shell,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaContext *context,
|
||||
PikaActiveColor color,
|
||||
gint width);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_PEN_H__ */
|
||||
509
app/display/pikacanvaspolygon.c
Normal file
509
app/display/pikacanvaspolygon.c
Normal file
@ -0,0 +1,509 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvaspolygon.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-transform-utils.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
|
||||
#include "pikacanvaspolygon.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_POINTS,
|
||||
PROP_TRANSFORM,
|
||||
PROP_FILLED
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPolygonPrivate PikaCanvasPolygonPrivate;
|
||||
|
||||
struct _PikaCanvasPolygonPrivate
|
||||
{
|
||||
PikaVector2 *points;
|
||||
gint n_points;
|
||||
PikaMatrix3 *transform;
|
||||
gboolean filled;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(polygon) \
|
||||
((PikaCanvasPolygonPrivate *) pika_canvas_polygon_get_instance_private ((PikaCanvasPolygon *) (polygon)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_polygon_finalize (GObject *object);
|
||||
static void pika_canvas_polygon_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_polygon_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_polygon_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_polygon_get_extents (PikaCanvasItem *item);
|
||||
static gboolean pika_canvas_polygon_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasPolygon, pika_canvas_polygon,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_polygon_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_class_init (PikaCanvasPolygonClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_polygon_finalize;
|
||||
object_class->set_property = pika_canvas_polygon_set_property;
|
||||
object_class->get_property = pika_canvas_polygon_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_polygon_draw;
|
||||
item_class->get_extents = pika_canvas_polygon_get_extents;
|
||||
item_class->hit = pika_canvas_polygon_hit;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_POINTS,
|
||||
pika_param_spec_array ("points", NULL, NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TRANSFORM,
|
||||
g_param_spec_pointer ("transform", NULL, NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FILLED,
|
||||
g_param_spec_boolean ("filled", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_init (PikaCanvasPolygon *polygon)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_pointer (&private->points, g_free);
|
||||
private->n_points = 0;
|
||||
|
||||
g_clear_pointer (&private->transform, g_free);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_POINTS:
|
||||
{
|
||||
PikaArray *array = g_value_get_boxed (value);
|
||||
|
||||
g_clear_pointer (&private->points, g_free);
|
||||
private->n_points = 0;
|
||||
|
||||
if (array)
|
||||
{
|
||||
private->points = g_memdup2 (array->data, array->length);
|
||||
private->n_points = array->length / sizeof (PikaVector2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_TRANSFORM:
|
||||
{
|
||||
PikaMatrix3 *transform = g_value_get_pointer (value);
|
||||
if (private->transform)
|
||||
g_free (private->transform);
|
||||
if (transform)
|
||||
private->transform = g_memdup2 (transform, sizeof (PikaMatrix3));
|
||||
else
|
||||
private->transform = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_FILLED:
|
||||
private->filled = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_POINTS:
|
||||
if (private->points)
|
||||
{
|
||||
PikaArray *array;
|
||||
|
||||
array = pika_array_new ((const guint8 *) private->points,
|
||||
private->n_points * sizeof (PikaVector2),
|
||||
FALSE);
|
||||
g_value_take_boxed (value, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_value_set_boxed (value, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_TRANSFORM:
|
||||
g_value_set_pointer (value, private->transform);
|
||||
break;
|
||||
|
||||
case PROP_FILLED:
|
||||
g_value_set_boolean (value, private->filled);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_transform (PikaCanvasItem *item,
|
||||
PikaVector2 *points,
|
||||
gint *n_points)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (item);
|
||||
gint i;
|
||||
|
||||
if (private->transform)
|
||||
{
|
||||
pika_transform_polygon (private->transform,
|
||||
private->points, private->n_points, FALSE,
|
||||
points, n_points);
|
||||
|
||||
for (i = 0; i < *n_points; i++)
|
||||
{
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
points[i].x,
|
||||
points[i].y,
|
||||
&points[i].x,
|
||||
&points[i].y);
|
||||
|
||||
points[i].x = floor (points[i].x) + 0.5;
|
||||
points[i].y = floor (points[i].y) + 0.5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < private->n_points; i++)
|
||||
{
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->points[i].x,
|
||||
private->points[i].y,
|
||||
&points[i].x,
|
||||
&points[i].y);
|
||||
|
||||
points[i].x = floor (points[i].x) + 0.5;
|
||||
points[i].y = floor (points[i].y) + 0.5;
|
||||
}
|
||||
|
||||
*n_points = private->n_points;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_polygon_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (item);
|
||||
PikaVector2 *points;
|
||||
gint n_points;
|
||||
gint i;
|
||||
|
||||
if (! private->points)
|
||||
return;
|
||||
|
||||
n_points = private->n_points;
|
||||
|
||||
if (private->transform)
|
||||
n_points = 3 * n_points / 2;
|
||||
|
||||
points = g_new0 (PikaVector2, n_points);
|
||||
|
||||
pika_canvas_polygon_transform (item, points, &n_points);
|
||||
|
||||
if (n_points < 2)
|
||||
{
|
||||
g_free (points);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_move_to (cr, points[0].x, points[0].y);
|
||||
|
||||
for (i = 1; i < n_points; i++)
|
||||
{
|
||||
cairo_line_to (cr, points[i].x, points[i].y);
|
||||
}
|
||||
|
||||
if (private->filled)
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
else
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
g_free (points);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_polygon_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
PikaVector2 *points;
|
||||
gint n_points;
|
||||
gint x1, y1, x2, y2;
|
||||
gint i;
|
||||
|
||||
if (! private->points)
|
||||
return NULL;
|
||||
|
||||
n_points = private->n_points;
|
||||
|
||||
if (private->transform)
|
||||
n_points = 3 * n_points / 2;
|
||||
|
||||
points = g_new0 (PikaVector2, n_points);
|
||||
|
||||
pika_canvas_polygon_transform (item, points, &n_points);
|
||||
|
||||
if (n_points < 2)
|
||||
{
|
||||
g_free (points);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x1 = floor (points[0].x - 1.5);
|
||||
y1 = floor (points[0].y - 1.5);
|
||||
x2 = x1 + 3;
|
||||
y2 = y1 + 3;
|
||||
|
||||
for (i = 1; i < n_points; i++)
|
||||
{
|
||||
gint x3 = floor (points[i].x - 1.5);
|
||||
gint y3 = floor (points[i].y - 1.5);
|
||||
gint x4 = x3 + 3;
|
||||
gint y4 = y3 + 3;
|
||||
|
||||
x1 = MIN (x1, x3);
|
||||
y1 = MIN (y1, y3);
|
||||
x2 = MAX (x2, x4);
|
||||
y2 = MAX (y2, y4);
|
||||
}
|
||||
|
||||
g_free (points);
|
||||
|
||||
rectangle.x = x1;
|
||||
rectangle.y = y1;
|
||||
rectangle.width = x2 - x1;
|
||||
rectangle.height = y2 - y1;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_polygon_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCanvasPolygonPrivate *private = GET_PRIVATE (item);
|
||||
PikaVector2 *points;
|
||||
gint n_points;
|
||||
gdouble tx, ty;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
gboolean hit;
|
||||
gint i;
|
||||
|
||||
if (! private->points)
|
||||
return FALSE;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item, x, y, &tx, &ty);
|
||||
|
||||
n_points = private->n_points;
|
||||
|
||||
if (private->transform)
|
||||
n_points = 3 * n_points / 2;
|
||||
|
||||
points = g_new0 (PikaVector2, n_points);
|
||||
|
||||
pika_canvas_polygon_transform (item, points, &n_points);
|
||||
|
||||
if (n_points < 2)
|
||||
{
|
||||
g_free (points);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
|
||||
cr = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_move_to (cr, points[0].x, points[0].y);
|
||||
|
||||
for (i = 1; i < private->n_points; i++)
|
||||
{
|
||||
cairo_line_to (cr, points[i].x, points[i].y);
|
||||
}
|
||||
|
||||
g_free (points);
|
||||
|
||||
hit = cairo_in_fill (cr, tx, ty);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_polygon_new (PikaDisplayShell *shell,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaMatrix3 *transform,
|
||||
gboolean filled)
|
||||
{
|
||||
PikaCanvasItem *item;
|
||||
PikaArray *array;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (points == NULL || n_points > 0, NULL);
|
||||
|
||||
array = pika_array_new ((const guint8 *) points,
|
||||
n_points * sizeof (PikaVector2), TRUE);
|
||||
|
||||
item = g_object_new (PIKA_TYPE_CANVAS_POLYGON,
|
||||
"shell", shell,
|
||||
"transform", transform,
|
||||
"filled", filled,
|
||||
"points", array,
|
||||
NULL);
|
||||
|
||||
pika_array_free (array);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_polygon_new_from_coords (PikaDisplayShell *shell,
|
||||
const PikaCoords *coords,
|
||||
gint n_coords,
|
||||
PikaMatrix3 *transform,
|
||||
gboolean filled)
|
||||
{
|
||||
PikaCanvasItem *item;
|
||||
PikaVector2 *points;
|
||||
PikaArray *array;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (coords == NULL || n_coords > 0, NULL);
|
||||
|
||||
points = g_new (PikaVector2, n_coords);
|
||||
|
||||
for (i = 0; i < n_coords; i++)
|
||||
{
|
||||
points[i].x = coords[i].x;
|
||||
points[i].y = coords[i].y;
|
||||
}
|
||||
|
||||
array = pika_array_new ((const guint8 *) points,
|
||||
n_coords * sizeof (PikaVector2), TRUE);
|
||||
|
||||
item = g_object_new (PIKA_TYPE_CANVAS_POLYGON,
|
||||
"shell", shell,
|
||||
"transform", transform,
|
||||
"filled", filled,
|
||||
"points", array,
|
||||
NULL);
|
||||
|
||||
pika_array_free (array);
|
||||
g_free (points);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_polygon_set_points (PikaCanvasItem *polygon,
|
||||
const PikaVector2 *points,
|
||||
gint n_points)
|
||||
{
|
||||
PikaArray *array;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_POLYGON (polygon));
|
||||
g_return_if_fail (points == NULL || n_points > 0);
|
||||
|
||||
array = pika_array_new ((const guint8 *) points,
|
||||
n_points * sizeof (PikaVector2), TRUE);
|
||||
|
||||
pika_canvas_item_begin_change (polygon);
|
||||
g_object_set (polygon,
|
||||
"points", array,
|
||||
NULL);
|
||||
pika_canvas_item_end_change (polygon);
|
||||
|
||||
pika_array_free (array);
|
||||
}
|
||||
72
app/display/pikacanvaspolygon.h
Normal file
72
app/display/pikacanvaspolygon.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* 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):
|
||||
* Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvaspolygon.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_POLYGON_H__
|
||||
#define __PIKA_CANVAS_POLYGON_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_POLYGON (pika_canvas_polygon_get_type ())
|
||||
#define PIKA_CANVAS_POLYGON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_POLYGON, PikaCanvasPolygon))
|
||||
#define PIKA_CANVAS_POLYGON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_POLYGON, PikaCanvasPolygonClass))
|
||||
#define PIKA_IS_CANVAS_POLYGON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_POLYGON))
|
||||
#define PIKA_IS_CANVAS_POLYGON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_POLYGON))
|
||||
#define PIKA_CANVAS_POLYGON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_POLYGON, PikaCanvasPolygonClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasPolygon PikaCanvasPolygon;
|
||||
typedef struct _PikaCanvasPolygonClass PikaCanvasPolygonClass;
|
||||
|
||||
struct _PikaCanvasPolygon
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasPolygonClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_polygon_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_polygon_new (PikaDisplayShell *shell,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaMatrix3 *transform,
|
||||
gboolean filled);
|
||||
PikaCanvasItem * pika_canvas_polygon_new_from_coords (PikaDisplayShell *shell,
|
||||
const PikaCoords *coords,
|
||||
gint n_coords,
|
||||
PikaMatrix3 *transform,
|
||||
gboolean filled);
|
||||
|
||||
void pika_canvas_polygon_set_points (PikaCanvasItem *polygon,
|
||||
const PikaVector2 *points,
|
||||
gint n_points);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_POLYGON_H__ */
|
||||
463
app/display/pikacanvasprogress.c
Normal file
463
app/display/pikacanvasprogress.c
Normal file
@ -0,0 +1,463 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasprogress.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvasitem-utils.h"
|
||||
#include "pikacanvasprogress.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define BORDER 5
|
||||
#define RADIUS 20
|
||||
|
||||
#define MIN_UPDATE_INTERVAL 50000 /* microseconds */
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ANCHOR,
|
||||
PROP_X,
|
||||
PROP_Y
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasProgressPrivate PikaCanvasProgressPrivate;
|
||||
|
||||
struct _PikaCanvasProgressPrivate
|
||||
{
|
||||
PikaHandleAnchor anchor;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
|
||||
gchar *text;
|
||||
gdouble value;
|
||||
|
||||
guint64 last_update_time;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(progress) \
|
||||
((PikaCanvasProgressPrivate *) pika_canvas_progress_get_instance_private ((PikaCanvasProgress *) (progress)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_progress_iface_init (PikaProgressInterface *iface);
|
||||
|
||||
static void pika_canvas_progress_finalize (GObject *object);
|
||||
static void pika_canvas_progress_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_progress_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_progress_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_progress_get_extents (PikaCanvasItem *item);
|
||||
static gboolean pika_canvas_progress_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
static PikaProgress * pika_canvas_progress_start (PikaProgress *progress,
|
||||
gboolean cancellable,
|
||||
const gchar *message);
|
||||
static void pika_canvas_progress_end (PikaProgress *progress);
|
||||
static gboolean pika_canvas_progress_is_active (PikaProgress *progress);
|
||||
static void pika_canvas_progress_set_text (PikaProgress *progress,
|
||||
const gchar *message);
|
||||
static void pika_canvas_progress_set_value (PikaProgress *progress,
|
||||
gdouble percentage);
|
||||
static gdouble pika_canvas_progress_get_value (PikaProgress *progress);
|
||||
static void pika_canvas_progress_pulse (PikaProgress *progress);
|
||||
static gboolean pika_canvas_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaCanvasProgress, pika_canvas_progress,
|
||||
PIKA_TYPE_CANVAS_ITEM,
|
||||
G_ADD_PRIVATE (PikaCanvasProgress)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_PROGRESS,
|
||||
pika_canvas_progress_iface_init))
|
||||
|
||||
#define parent_class pika_canvas_progress_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_progress_class_init (PikaCanvasProgressClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_progress_finalize;
|
||||
object_class->set_property = pika_canvas_progress_set_property;
|
||||
object_class->get_property = pika_canvas_progress_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_progress_draw;
|
||||
item_class->get_extents = pika_canvas_progress_get_extents;
|
||||
item_class->hit = pika_canvas_progress_hit;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ANCHOR,
|
||||
g_param_spec_enum ("anchor", NULL, NULL,
|
||||
PIKA_TYPE_HANDLE_ANCHOR,
|
||||
PIKA_HANDLE_ANCHOR_CENTER,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_iface_init (PikaProgressInterface *iface)
|
||||
{
|
||||
iface->start = pika_canvas_progress_start;
|
||||
iface->end = pika_canvas_progress_end;
|
||||
iface->is_active = pika_canvas_progress_is_active;
|
||||
iface->set_text = pika_canvas_progress_set_text;
|
||||
iface->set_value = pika_canvas_progress_set_value;
|
||||
iface->get_value = pika_canvas_progress_get_value;
|
||||
iface->pulse = pika_canvas_progress_pulse;
|
||||
iface->message = pika_canvas_progress_message;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_init (PikaCanvasProgress *progress)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_pointer (&private->text, g_free);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ANCHOR:
|
||||
private->anchor = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ANCHOR:
|
||||
g_value_set_enum (value, private->anchor);
|
||||
break;
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static PangoLayout *
|
||||
pika_canvas_progress_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
PangoLayout *layout;
|
||||
|
||||
layout = pika_canvas_get_layout (PIKA_CANVAS (canvas), "%s",
|
||||
private->text);
|
||||
|
||||
pango_layout_get_pixel_size (layout, width, height);
|
||||
|
||||
*width = MAX (*width, 2 * RADIUS);
|
||||
|
||||
*width += 2 * BORDER;
|
||||
*height += 3 * BORDER + 2 * RADIUS;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x, private->y,
|
||||
x, y);
|
||||
|
||||
pika_canvas_item_shift_to_north_west (private->anchor,
|
||||
*x, *y,
|
||||
*width,
|
||||
*height,
|
||||
x, y);
|
||||
|
||||
*x = floor (*x);
|
||||
*y = floor (*y);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
gdouble x, y;
|
||||
gint width, height;
|
||||
|
||||
pika_canvas_progress_transform (item, &x, &y, &width, &height);
|
||||
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_line_to (cr, x + width, y);
|
||||
cairo_line_to (cr, x + width, y + height - BORDER - 2 * RADIUS);
|
||||
cairo_line_to (cr, x + 2 * BORDER + 2 * RADIUS, y + height - BORDER - 2 * RADIUS);
|
||||
cairo_arc (cr, x + BORDER + RADIUS, y + height - BORDER - RADIUS,
|
||||
BORDER + RADIUS, 0, G_PI);
|
||||
cairo_close_path (cr);
|
||||
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
|
||||
cairo_move_to (cr, x + BORDER, y + BORDER);
|
||||
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
|
||||
pango_cairo_show_layout (cr,
|
||||
pika_canvas_get_layout (PIKA_CANVAS (canvas),
|
||||
"%s", private->text));
|
||||
|
||||
pika_canvas_set_tool_bg_style (pika_canvas_item_get_canvas (item), cr);
|
||||
cairo_arc (cr, x + BORDER + RADIUS, y + height - BORDER - RADIUS,
|
||||
RADIUS, - G_PI / 2.0, 2 * G_PI - G_PI / 2.0);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 1.0);
|
||||
cairo_move_to (cr, x + BORDER + RADIUS, y + height - BORDER - RADIUS);
|
||||
cairo_arc (cr, x + BORDER + RADIUS, y + height - BORDER - RADIUS,
|
||||
RADIUS, - G_PI / 2.0, 2 * G_PI * private->value - G_PI / 2.0);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_progress_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x, y;
|
||||
gint width, height;
|
||||
|
||||
pika_canvas_progress_transform (item, &x, &y, &width, &height);
|
||||
|
||||
/* add 1px on each side because fill()'s default impl does the same */
|
||||
rectangle.x = (gint) x - 1;
|
||||
rectangle.y = (gint) y - 1;
|
||||
rectangle.width = width + 2;
|
||||
rectangle.height = height + 2;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_progress_hit (PikaCanvasItem *item,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
gdouble px, py;
|
||||
gint pwidth, pheight;
|
||||
gdouble tx, ty;
|
||||
|
||||
pika_canvas_progress_transform (item, &px, &py, &pwidth, &pheight);
|
||||
pika_canvas_item_transform_xy_f (item, x, y, &tx, &ty);
|
||||
|
||||
pheight -= BORDER + 2 * RADIUS;
|
||||
|
||||
return (tx >= px && tx < (px + pwidth) &&
|
||||
ty >= py && ty < (py + pheight));
|
||||
}
|
||||
|
||||
static PikaProgress *
|
||||
pika_canvas_progress_start (PikaProgress *progress,
|
||||
gboolean cancellable,
|
||||
const gchar *message)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (progress);
|
||||
|
||||
pika_canvas_progress_set_text (progress, message);
|
||||
|
||||
private->last_update_time = g_get_monotonic_time ();
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_end (PikaProgress *progress)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_progress_is_active (PikaProgress *progress)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_set_text (PikaProgress *progress,
|
||||
const gchar *message)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (progress);
|
||||
cairo_region_t *old_region;
|
||||
cairo_region_t *new_region;
|
||||
|
||||
old_region = pika_canvas_item_get_extents (PIKA_CANVAS_ITEM (progress));
|
||||
|
||||
if (private->text)
|
||||
g_free (private->text);
|
||||
|
||||
private->text = g_strdup (message);
|
||||
|
||||
new_region = pika_canvas_item_get_extents (PIKA_CANVAS_ITEM (progress));
|
||||
|
||||
cairo_region_union (new_region, old_region);
|
||||
cairo_region_destroy (old_region);
|
||||
|
||||
_pika_canvas_item_update (PIKA_CANVAS_ITEM (progress), new_region);
|
||||
|
||||
cairo_region_destroy (new_region);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_set_value (PikaProgress *progress,
|
||||
gdouble percentage)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (progress);
|
||||
|
||||
if (percentage != private->value)
|
||||
{
|
||||
guint64 time = g_get_monotonic_time ();
|
||||
|
||||
private->value = percentage;
|
||||
|
||||
if (time - private->last_update_time >= MIN_UPDATE_INTERVAL)
|
||||
{
|
||||
cairo_region_t *region;
|
||||
|
||||
private->last_update_time = time;
|
||||
|
||||
region = pika_canvas_item_get_extents (PIKA_CANVAS_ITEM (progress));
|
||||
|
||||
_pika_canvas_item_update (PIKA_CANVAS_ITEM (progress), region);
|
||||
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gdouble
|
||||
pika_canvas_progress_get_value (PikaProgress *progress)
|
||||
{
|
||||
PikaCanvasProgressPrivate *private = GET_PRIVATE (progress);
|
||||
|
||||
return private->value;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_progress_pulse (PikaProgress *progress)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_progress_new (PikaDisplayShell *shell,
|
||||
PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_PROGRESS,
|
||||
"shell", shell,
|
||||
"anchor", anchor,
|
||||
"x", x,
|
||||
"y", y,
|
||||
NULL);
|
||||
}
|
||||
62
app/display/pikacanvasprogress.h
Normal file
62
app/display/pikacanvasprogress.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasprogress.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_PROGRESS_H__
|
||||
#define __PIKA_CANVAS_PROGRESS_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_PROGRESS (pika_canvas_progress_get_type ())
|
||||
#define PIKA_CANVAS_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_PROGRESS, PikaCanvasProgress))
|
||||
#define PIKA_CANVAS_PROGRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_PROGRESS, PikaCanvasProgressClass))
|
||||
#define PIKA_IS_CANVAS_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_PROGRESS))
|
||||
#define PIKA_IS_CANVAS_PROGRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_PROGRESS))
|
||||
#define PIKA_CANVAS_PROGRESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_PROGRESS, PikaCanvasProgressClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasProgress PikaCanvasProgress;
|
||||
typedef struct _PikaCanvasProgressClass PikaCanvasProgressClass;
|
||||
|
||||
struct _PikaCanvasProgress
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasProgressClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_progress_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_progress_new (PikaDisplayShell *shell,
|
||||
PikaHandleAnchor anchor,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_PROGRESS_H__ */
|
||||
201
app/display/pikacanvasproxygroup.c
Normal file
201
app/display/pikacanvasproxygroup.c
Normal file
@ -0,0 +1,201 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasproxygroup.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvasproxygroup.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasProxyGroupPrivate PikaCanvasProxyGroupPrivate;
|
||||
|
||||
struct _PikaCanvasProxyGroupPrivate
|
||||
{
|
||||
GHashTable *proxy_hash;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(proxy_group) \
|
||||
((PikaCanvasProxyGroupPrivate *) pika_canvas_proxy_group_get_instance_private ((PikaCanvasProxyGroup *) (proxy_group)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_proxy_group_finalize (GObject *object);
|
||||
static void pika_canvas_proxy_group_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_proxy_group_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasProxyGroup, pika_canvas_proxy_group,
|
||||
PIKA_TYPE_CANVAS_GROUP)
|
||||
|
||||
#define parent_class pika_canvas_proxy_group_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_proxy_group_class_init (PikaCanvasProxyGroupClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_proxy_group_finalize;
|
||||
object_class->set_property = pika_canvas_proxy_group_set_property;
|
||||
object_class->get_property = pika_canvas_proxy_group_get_property;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_proxy_group_init (PikaCanvasProxyGroup *proxy_group)
|
||||
{
|
||||
PikaCanvasProxyGroupPrivate *private = GET_PRIVATE (proxy_group);
|
||||
|
||||
private->proxy_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_proxy_group_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasProxyGroupPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_pointer (&private->proxy_hash, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_proxy_group_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
/* PikaCanvasProxyGroupPrivate *private = GET_PRIVATE (object); */
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_proxy_group_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
/* PikaCanvasProxyGroupPrivate *private = GET_PRIVATE (object); */
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_proxy_group_new (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_PROXY_GROUP,
|
||||
"shell", shell,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_proxy_group_add_item (PikaCanvasProxyGroup *group,
|
||||
gpointer object,
|
||||
PikaCanvasItem *proxy_item)
|
||||
{
|
||||
PikaCanvasProxyGroupPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GROUP (group));
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (proxy_item));
|
||||
g_return_if_fail (PIKA_CANVAS_ITEM (group) != proxy_item);
|
||||
|
||||
private = GET_PRIVATE (group);
|
||||
|
||||
g_return_if_fail (g_hash_table_lookup (private->proxy_hash, object) ==
|
||||
NULL);
|
||||
|
||||
g_hash_table_insert (private->proxy_hash, object, proxy_item);
|
||||
|
||||
pika_canvas_group_add_item (PIKA_CANVAS_GROUP (group), proxy_item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_proxy_group_remove_item (PikaCanvasProxyGroup *group,
|
||||
gpointer object)
|
||||
{
|
||||
PikaCanvasProxyGroupPrivate *private;
|
||||
PikaCanvasItem *proxy_item;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CANVAS_GROUP (group));
|
||||
g_return_if_fail (object != NULL);
|
||||
|
||||
private = GET_PRIVATE (group);
|
||||
|
||||
proxy_item = g_hash_table_lookup (private->proxy_hash, object);
|
||||
|
||||
g_return_if_fail (proxy_item != NULL);
|
||||
|
||||
g_hash_table_remove (private->proxy_hash, object);
|
||||
|
||||
pika_canvas_group_remove_item (PIKA_CANVAS_GROUP (group), proxy_item);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_proxy_group_get_item (PikaCanvasProxyGroup *group,
|
||||
gpointer object)
|
||||
{
|
||||
PikaCanvasProxyGroupPrivate *private;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CANVAS_GROUP (group), NULL);
|
||||
g_return_val_if_fail (object != NULL, NULL);
|
||||
|
||||
private = GET_PRIVATE (group);
|
||||
|
||||
return g_hash_table_lookup (private->proxy_hash, object);
|
||||
}
|
||||
67
app/display/pikacanvasproxygroup.h
Normal file
67
app/display/pikacanvasproxygroup.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasproxygroup.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_PROXY_GROUP_H__
|
||||
#define __PIKA_CANVAS_PROXY_GROUP_H__
|
||||
|
||||
|
||||
#include "pikacanvasgroup.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_PROXY_GROUP (pika_canvas_proxy_group_get_type ())
|
||||
#define PIKA_CANVAS_PROXY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_PROXY_GROUP, PikaCanvasProxyGroup))
|
||||
#define PIKA_CANVAS_PROXY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_PROXY_GROUP, PikaCanvasProxyGroupClass))
|
||||
#define PIKA_IS_CANVAS_PROXY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_PROXY_GROUP))
|
||||
#define PIKA_IS_CANVAS_PROXY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_PROXY_GROUP))
|
||||
#define PIKA_CANVAS_PROXY_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_PROXY_GROUP, PikaCanvasProxyGroupClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasProxyGroup PikaCanvasProxyGroup;
|
||||
typedef struct _PikaCanvasProxyGroupClass PikaCanvasProxyGroupClass;
|
||||
|
||||
struct _PikaCanvasProxyGroup
|
||||
{
|
||||
PikaCanvasGroup parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasProxyGroupClass
|
||||
{
|
||||
PikaCanvasGroupClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_proxy_group_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_proxy_group_new (PikaDisplayShell *shell);
|
||||
|
||||
void pika_canvas_proxy_group_add_item (PikaCanvasProxyGroup *group,
|
||||
gpointer object,
|
||||
PikaCanvasItem *proxy_item);
|
||||
void pika_canvas_proxy_group_remove_item (PikaCanvasProxyGroup *group,
|
||||
gpointer object);
|
||||
PikaCanvasItem * pika_canvas_proxy_group_get_item (PikaCanvasProxyGroup *group,
|
||||
gpointer object);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_PROXY_GROUP_H__ */
|
||||
364
app/display/pikacanvasrectangle.c
Normal file
364
app/display/pikacanvasrectangle.c
Normal file
@ -0,0 +1,364 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasrectangle.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvasrectangle.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_FILLED
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasRectanglePrivate PikaCanvasRectanglePrivate;
|
||||
|
||||
struct _PikaCanvasRectanglePrivate
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble width;
|
||||
gdouble height;
|
||||
gboolean filled;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(rectangle) \
|
||||
((PikaCanvasRectanglePrivate *) pika_canvas_rectangle_get_instance_private ((PikaCanvasRectangle *) (rectangle)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_rectangle_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_rectangle_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_rectangle_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_rectangle_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasRectangle, pika_canvas_rectangle,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_rectangle_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_class_init (PikaCanvasRectangleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_rectangle_set_property;
|
||||
object_class->get_property = pika_canvas_rectangle_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_rectangle_draw;
|
||||
item_class->get_extents = pika_canvas_rectangle_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WIDTH,
|
||||
g_param_spec_double ("width", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HEIGHT,
|
||||
g_param_spec_double ("height", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FILLED,
|
||||
g_param_spec_boolean ("filled", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_init (PikaCanvasRectangle *rectangle)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasRectanglePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
private->width = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
private->height = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_FILLED:
|
||||
private->filled = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasRectanglePrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
g_value_set_double (value, private->width);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_double (value, private->height);
|
||||
break;
|
||||
case PROP_FILLED:
|
||||
g_value_set_boolean (value, private->filled);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y,
|
||||
gdouble *w,
|
||||
gdouble *h)
|
||||
{
|
||||
PikaCanvasRectanglePrivate *private = GET_PRIVATE (item);
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MIN (private->x,
|
||||
private->x + private->width),
|
||||
MIN (private->y,
|
||||
private->y + private->height),
|
||||
&x1, &y1);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MAX (private->x,
|
||||
private->x + private->width),
|
||||
MAX (private->y,
|
||||
private->y + private->height),
|
||||
&x2, &y2);
|
||||
|
||||
x1 = floor (x1);
|
||||
y1 = floor (y1);
|
||||
x2 = ceil (x2);
|
||||
y2 = ceil (y2);
|
||||
|
||||
if (private->filled)
|
||||
{
|
||||
*x = x1;
|
||||
*y = y1;
|
||||
*w = x2 - x1;
|
||||
*h = y2 - y1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = x1 + 0.5;
|
||||
*y = y1 + 0.5;
|
||||
*w = x2 - 0.5 - *x;
|
||||
*h = y2 - 0.5 - *y;
|
||||
|
||||
*w = MAX (0.0, *w);
|
||||
*h = MAX (0.0, *h);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasRectanglePrivate *private = GET_PRIVATE (item);
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_rectangle_transform (item, &x, &y, &w, &h);
|
||||
|
||||
cairo_rectangle (cr, x, y, w, h);
|
||||
|
||||
if (private->filled)
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
else
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_rectangle_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasRectanglePrivate *private = GET_PRIVATE (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_rectangle_transform (item, &x, &y, &w, &h);
|
||||
|
||||
if (private->filled)
|
||||
{
|
||||
rectangle.x = floor (x - 1.0);
|
||||
rectangle.y = floor (y - 1.0);
|
||||
rectangle.width = ceil (w + 2.0);
|
||||
rectangle.height = ceil (h + 2.0);
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
else if (w > 64 && h > 64)
|
||||
{
|
||||
cairo_region_t *region;
|
||||
|
||||
/* left */
|
||||
rectangle.x = floor (x - 1.5);
|
||||
rectangle.y = floor (y - 1.5);
|
||||
rectangle.width = 3.0;
|
||||
rectangle.height = ceil (h + 3.0);
|
||||
|
||||
region = cairo_region_create_rectangle (&rectangle);
|
||||
|
||||
/* right */
|
||||
rectangle.x = floor (x + w - 1.5);
|
||||
|
||||
cairo_region_union_rectangle (region, &rectangle);
|
||||
|
||||
/* top */
|
||||
rectangle.x = floor (x - 1.5);
|
||||
rectangle.y = floor (y - 1.5);
|
||||
rectangle.width = ceil (w + 3.0);
|
||||
rectangle.height = 3.0;
|
||||
|
||||
cairo_region_union_rectangle (region, &rectangle);
|
||||
|
||||
/* bottom */
|
||||
rectangle.y = floor (y + h - 1.5);
|
||||
|
||||
cairo_region_union_rectangle (region, &rectangle);
|
||||
|
||||
return region;
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangle.x = floor (x - 1.5);
|
||||
rectangle.y = floor (y - 1.5);
|
||||
rectangle.width = ceil (w + 3.0);
|
||||
rectangle.height = ceil (h + 3.0);
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_rectangle_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gboolean filled)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_RECTANGLE,
|
||||
"shell", shell,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"filled", filled,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_rectangle_set (PikaCanvasItem *rectangle,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_RECTANGLE (rectangle));
|
||||
|
||||
pika_canvas_item_begin_change (rectangle);
|
||||
|
||||
g_object_set (rectangle,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (rectangle);
|
||||
}
|
||||
70
app/display/pikacanvasrectangle.h
Normal file
70
app/display/pikacanvasrectangle.h
Normal file
@ -0,0 +1,70 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasrectangle.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_RECTANGLE_H__
|
||||
#define __PIKA_CANVAS_RECTANGLE_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_RECTANGLE (pika_canvas_rectangle_get_type ())
|
||||
#define PIKA_CANVAS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_RECTANGLE, PikaCanvasRectangle))
|
||||
#define PIKA_CANVAS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_RECTANGLE, PikaCanvasRectangleClass))
|
||||
#define PIKA_IS_CANVAS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_RECTANGLE))
|
||||
#define PIKA_IS_CANVAS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_RECTANGLE))
|
||||
#define PIKA_CANVAS_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_RECTANGLE, PikaCanvasRectangleClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasRectangle PikaCanvasRectangle;
|
||||
typedef struct _PikaCanvasRectangleClass PikaCanvasRectangleClass;
|
||||
|
||||
struct _PikaCanvasRectangle
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasRectangleClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_rectangle_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_rectangle_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gboolean filled);
|
||||
|
||||
void pika_canvas_rectangle_set (PikaCanvasItem *rectangle,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_RECTANGLE_H__ */
|
||||
426
app/display/pikacanvasrectangleguides.c
Normal file
426
app/display/pikacanvasrectangleguides.c
Normal file
@ -0,0 +1,426 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvasrectangleguides.c
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvasrectangleguides.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define SQRT5 2.236067977
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_TYPE,
|
||||
PROP_N_GUIDES
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasRectangleGuidesPrivate PikaCanvasRectangleGuidesPrivate;
|
||||
|
||||
struct _PikaCanvasRectangleGuidesPrivate
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble width;
|
||||
gdouble height;
|
||||
PikaGuidesType type;
|
||||
gint n_guides;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(rectangle) \
|
||||
((PikaCanvasRectangleGuidesPrivate *) pika_canvas_rectangle_guides_get_instance_private ((PikaCanvasRectangleGuides *) (rectangle)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_rectangle_guides_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_rectangle_guides_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_rectangle_guides_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_rectangle_guides_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasRectangleGuides,
|
||||
pika_canvas_rectangle_guides, PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_rectangle_guides_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_guides_class_init (PikaCanvasRectangleGuidesClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_rectangle_guides_set_property;
|
||||
object_class->get_property = pika_canvas_rectangle_guides_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_rectangle_guides_draw;
|
||||
item_class->get_extents = pika_canvas_rectangle_guides_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WIDTH,
|
||||
g_param_spec_double ("width", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HEIGHT,
|
||||
g_param_spec_double ("height", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TYPE,
|
||||
g_param_spec_enum ("type", NULL, NULL,
|
||||
PIKA_TYPE_GUIDES_TYPE,
|
||||
PIKA_GUIDES_NONE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_N_GUIDES,
|
||||
g_param_spec_int ("n-guides", NULL, NULL,
|
||||
1, 128, 4,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_guides_init (PikaCanvasRectangleGuides *rectangle)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_guides_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasRectangleGuidesPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
private->width = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
private->height = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_TYPE:
|
||||
private->type = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_N_GUIDES:
|
||||
private->n_guides = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_guides_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasRectangleGuidesPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
g_value_set_double (value, private->width);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_double (value, private->height);
|
||||
break;
|
||||
case PROP_TYPE:
|
||||
g_value_set_enum (value, private->type);
|
||||
break;
|
||||
case PROP_N_GUIDES:
|
||||
g_value_set_int (value, private->n_guides);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_guides_transform (PikaCanvasItem *item,
|
||||
gdouble *x1,
|
||||
gdouble *y1,
|
||||
gdouble *x2,
|
||||
gdouble *y2)
|
||||
{
|
||||
PikaCanvasRectangleGuidesPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MIN (private->x,
|
||||
private->x + private->width),
|
||||
MIN (private->y,
|
||||
private->y + private->height),
|
||||
x1, y1);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MAX (private->x,
|
||||
private->x + private->width),
|
||||
MAX (private->y,
|
||||
private->y + private->height),
|
||||
x2, y2);
|
||||
|
||||
*x1 = floor (*x1) + 0.5;
|
||||
*y1 = floor (*y1) + 0.5;
|
||||
*x2 = ceil (*x2) - 0.5;
|
||||
*y2 = ceil (*y2) - 0.5;
|
||||
|
||||
*x2 = MAX (*x1, *x2);
|
||||
*y2 = MAX (*y1, *y2);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_hline (cairo_t *cr,
|
||||
gdouble x1,
|
||||
gdouble x2,
|
||||
gdouble y)
|
||||
{
|
||||
y = floor (y) + 0.5;
|
||||
|
||||
cairo_move_to (cr, x1, y);
|
||||
cairo_line_to (cr, x2, y);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_vline (cairo_t *cr,
|
||||
gdouble y1,
|
||||
gdouble y2,
|
||||
gdouble x)
|
||||
{
|
||||
x = floor (x) + 0.5;
|
||||
|
||||
cairo_move_to (cr, x, y1);
|
||||
cairo_line_to (cr, x, y2);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_rectangle_guides_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasRectangleGuidesPrivate *private = GET_PRIVATE (item);
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
gint i;
|
||||
|
||||
pika_canvas_rectangle_guides_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_GUIDES_NONE:
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_CENTER_LINES:
|
||||
draw_hline (cr, x1, x2, (y1 + y2) / 2);
|
||||
draw_vline (cr, y1, y2, (x1 + x2) / 2);
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_THIRDS:
|
||||
draw_hline (cr, x1, x2, (2 * y1 + y2) / 3);
|
||||
draw_hline (cr, x1, x2, ( y1 + 2 * y2) / 3);
|
||||
|
||||
draw_vline (cr, y1, y2, (2 * x1 + x2) / 3);
|
||||
draw_vline (cr, y1, y2, ( x1 + 2 * x2) / 3);
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_FIFTHS:
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
draw_hline (cr, x1, x2, y1 + i * (y2 - y1) / 5);
|
||||
draw_vline (cr, y1, y2, x1 + i * (x2 - x1) / 5);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_GOLDEN:
|
||||
draw_hline (cr, x1, x2, (2 * y1 + (1 + SQRT5) * y2) / (3 + SQRT5));
|
||||
draw_hline (cr, x1, x2, ((1 + SQRT5) * y1 + 2 * y2) / (3 + SQRT5));
|
||||
|
||||
draw_vline (cr, y1, y2, (2 * x1 + (1 + SQRT5) * x2) / (3 + SQRT5));
|
||||
draw_vline (cr, y1, y2, ((1 + SQRT5) * x1 + 2 * x2) / (3 + SQRT5));
|
||||
break;
|
||||
|
||||
/* This code implements the method of diagonals discovered by
|
||||
* Edwin Westhoff - see http://www.diagonalmethod.info/
|
||||
*/
|
||||
case PIKA_GUIDES_DIAGONALS:
|
||||
{
|
||||
/* the side of the largest square that can be
|
||||
* fitted in whole into the rectangle (x1, y1), (x2, y2)
|
||||
*/
|
||||
const gdouble square_side = MIN (x2 - x1, y2 - y1);
|
||||
|
||||
/* diagonal from the top-left edge */
|
||||
cairo_move_to (cr, x1, y1);
|
||||
cairo_line_to (cr, x1 + square_side, y1 + square_side);
|
||||
|
||||
/* diagonal from the top-right edge */
|
||||
cairo_move_to (cr, x2, y1);
|
||||
cairo_line_to (cr, x2 - square_side, y1 + square_side);
|
||||
|
||||
/* diagonal from the bottom-left edge */
|
||||
cairo_move_to (cr, x1, y2);
|
||||
cairo_line_to (cr, x1 + square_side, y2 - square_side);
|
||||
|
||||
/* diagonal from the bottom-right edge */
|
||||
cairo_move_to (cr, x2, y2);
|
||||
cairo_line_to (cr, x2 - square_side, y2 - square_side);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_N_LINES:
|
||||
for (i = 0; i < private->n_guides; i++)
|
||||
{
|
||||
draw_hline (cr, x1, x2, y1 + i * (y2 - y1) / private->n_guides);
|
||||
draw_vline (cr, y1, y2, x1 + i * (x2 - x1) / private->n_guides);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_SPACING:
|
||||
break;
|
||||
}
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_rectangle_guides_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasRectangleGuidesPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->type != PIKA_GUIDES_NONE)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_canvas_rectangle_guides_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
rectangle.x = floor (x1 - 1.5);
|
||||
rectangle.y = floor (y1 - 1.5);
|
||||
rectangle.width = ceil (x2 - x1 + 3.0);
|
||||
rectangle.height = ceil (y2 - y1 + 3.0);
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_rectangle_guides_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
PikaGuidesType type,
|
||||
gint n_guides)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_RECTANGLE_GUIDES,
|
||||
"shell", shell,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"type", type,
|
||||
"n-guides", n_guides,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_rectangle_guides_set (PikaCanvasItem *rectangle,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
PikaGuidesType type,
|
||||
gint n_guides)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_RECTANGLE_GUIDES (rectangle));
|
||||
|
||||
pika_canvas_item_begin_change (rectangle);
|
||||
|
||||
g_object_set (rectangle,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"type", type,
|
||||
"n-guides", n_guides,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (rectangle);
|
||||
}
|
||||
73
app/display/pikacanvasrectangleguides.h
Normal file
73
app/display/pikacanvasrectangleguides.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvasrectangleguides.h
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_RECTANGLE_GUIDES_H__
|
||||
#define __PIKA_CANVAS_RECTANGLE_GUIDES_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_RECTANGLE_GUIDES (pika_canvas_rectangle_guides_get_type ())
|
||||
#define PIKA_CANVAS_RECTANGLE_GUIDES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_RECTANGLE_GUIDES, PikaCanvasRectangleGuides))
|
||||
#define PIKA_CANVAS_RECTANGLE_GUIDES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_RECTANGLE_GUIDES, PikaCanvasRectangleGuidesClass))
|
||||
#define PIKA_IS_CANVAS_RECTANGLE_GUIDES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_RECTANGLE_GUIDES))
|
||||
#define PIKA_IS_CANVAS_RECTANGLE_GUIDES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_RECTANGLE_GUIDES))
|
||||
#define PIKA_CANVAS_RECTANGLE_GUIDES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_RECTANGLE_GUIDES, PikaCanvasRectangleGuidesClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasRectangleGuides PikaCanvasRectangleGuides;
|
||||
typedef struct _PikaCanvasRectangleGuidesClass PikaCanvasRectangleGuidesClass;
|
||||
|
||||
struct _PikaCanvasRectangleGuides
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasRectangleGuidesClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_rectangle_guides_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_rectangle_guides_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
PikaGuidesType type,
|
||||
gint n_guides);
|
||||
|
||||
void pika_canvas_rectangle_guides_set (PikaCanvasItem *rectangle,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
PikaGuidesType type,
|
||||
gint n_guides);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_RECTANGLE_GUIDES_H__ */
|
||||
360
app/display/pikacanvassamplepoint.c
Normal file
360
app/display/pikacanvassamplepoint.c
Normal file
@ -0,0 +1,360 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvassamplepoint.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikacanvassamplepoint.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define PIKA_SAMPLE_POINT_DRAW_SIZE 14
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_INDEX,
|
||||
PROP_SAMPLE_POINT_STYLE
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasSamplePointPrivate PikaCanvasSamplePointPrivate;
|
||||
|
||||
struct _PikaCanvasSamplePointPrivate
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
gint index;
|
||||
gboolean sample_point_style;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(sample_point) \
|
||||
((PikaCanvasSamplePointPrivate *) pika_canvas_sample_point_get_instance_private ((PikaCanvasSamplePoint *) (sample_point)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_sample_point_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_sample_point_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_sample_point_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_sample_point_get_extents (PikaCanvasItem *item);
|
||||
static void pika_canvas_sample_point_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static void pika_canvas_sample_point_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasSamplePoint, pika_canvas_sample_point,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_sample_point_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_class_init (PikaCanvasSamplePointClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_sample_point_set_property;
|
||||
object_class->get_property = pika_canvas_sample_point_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_sample_point_draw;
|
||||
item_class->get_extents = pika_canvas_sample_point_get_extents;
|
||||
item_class->stroke = pika_canvas_sample_point_stroke;
|
||||
item_class->fill = pika_canvas_sample_point_fill;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_int ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_int ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_INDEX,
|
||||
g_param_spec_int ("index", NULL, NULL,
|
||||
0, G_MAXINT, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SAMPLE_POINT_STYLE,
|
||||
g_param_spec_boolean ("sample-point-style",
|
||||
NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_init (PikaCanvasSamplePoint *sample_point)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_INDEX:
|
||||
private->index = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_SAMPLE_POINT_STYLE:
|
||||
private->sample_point_style = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_int (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_int (value, private->x);
|
||||
break;
|
||||
case PROP_INDEX:
|
||||
g_value_set_int (value, private->x);
|
||||
break;
|
||||
case PROP_SAMPLE_POINT_STYLE:
|
||||
g_value_set_boolean (value, private->sample_point_style);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x + 0.5,
|
||||
private->y + 0.5,
|
||||
x, y);
|
||||
|
||||
*x = floor (*x) + 0.5;
|
||||
*y = floor (*y) + 0.5;
|
||||
}
|
||||
|
||||
#define HALF_SIZE (PIKA_SAMPLE_POINT_DRAW_SIZE / 2)
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
PangoLayout *layout;
|
||||
gdouble x, y;
|
||||
gint x1, x2, y1, y2;
|
||||
|
||||
pika_canvas_sample_point_transform (item, &x, &y);
|
||||
|
||||
x1 = x - PIKA_SAMPLE_POINT_DRAW_SIZE;
|
||||
x2 = x + PIKA_SAMPLE_POINT_DRAW_SIZE;
|
||||
y1 = y - PIKA_SAMPLE_POINT_DRAW_SIZE;
|
||||
y2 = y + PIKA_SAMPLE_POINT_DRAW_SIZE;
|
||||
|
||||
cairo_move_to (cr, x, y1);
|
||||
cairo_line_to (cr, x, y1 + HALF_SIZE);
|
||||
|
||||
cairo_move_to (cr, x, y2);
|
||||
cairo_line_to (cr, x, y2 - HALF_SIZE);
|
||||
|
||||
cairo_move_to (cr, x1, y);
|
||||
cairo_line_to (cr, x1 + HALF_SIZE, y);
|
||||
|
||||
cairo_move_to (cr, x2, y);
|
||||
cairo_line_to (cr, x2 - HALF_SIZE, y);
|
||||
|
||||
cairo_arc_negative (cr, x, y, HALF_SIZE, 0.0, 0.5 * G_PI);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
|
||||
layout = pika_canvas_get_layout (PIKA_CANVAS (canvas),
|
||||
"%d", private->index);
|
||||
|
||||
cairo_move_to (cr, x + 3, y + 3);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_sample_point_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (item);
|
||||
GtkWidget *canvas = pika_canvas_item_get_canvas (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle ink;
|
||||
gdouble x, y;
|
||||
gint x1, x2, y1, y2;
|
||||
|
||||
pika_canvas_sample_point_transform (item, &x, &y);
|
||||
|
||||
x1 = floor (x - PIKA_SAMPLE_POINT_DRAW_SIZE);
|
||||
x2 = ceil (x + PIKA_SAMPLE_POINT_DRAW_SIZE);
|
||||
y1 = floor (y - PIKA_SAMPLE_POINT_DRAW_SIZE);
|
||||
y2 = ceil (y + PIKA_SAMPLE_POINT_DRAW_SIZE);
|
||||
|
||||
layout = pika_canvas_get_layout (PIKA_CANVAS (canvas),
|
||||
"%d", private->index);
|
||||
|
||||
pango_layout_get_extents (layout, &ink, NULL);
|
||||
|
||||
x2 = MAX (x2, 3 + ink.width);
|
||||
y2 = MAX (y2, 3 + ink.height);
|
||||
|
||||
rectangle.x = x1 - 1.5;
|
||||
rectangle.y = y1 - 1.5;
|
||||
rectangle.width = x2 - x1 + 3.0;
|
||||
rectangle.height = y2 - y1 + 3.0;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_stroke (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->sample_point_style)
|
||||
{
|
||||
pika_canvas_set_tool_bg_style (pika_canvas_item_get_canvas (item), cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
pika_canvas_set_sample_point_style (pika_canvas_item_get_canvas (item), cr,
|
||||
pika_canvas_item_get_highlight (item));
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->stroke (item, cr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_sample_point_fill (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasSamplePointPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
if (private->sample_point_style)
|
||||
{
|
||||
pika_canvas_set_sample_point_style (pika_canvas_item_get_canvas (item), cr,
|
||||
pika_canvas_item_get_highlight (item));
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIKA_CANVAS_ITEM_CLASS (parent_class)->fill (item, cr);
|
||||
}
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_sample_point_new (PikaDisplayShell *shell,
|
||||
gint x,
|
||||
gint y,
|
||||
gint index,
|
||||
gboolean sample_point_style)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_SAMPLE_POINT,
|
||||
"shell", shell,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"index", index,
|
||||
"sample-point-style", sample_point_style,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_sample_point_set (PikaCanvasItem *sample_point,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_SAMPLE_POINT (sample_point));
|
||||
|
||||
pika_canvas_item_begin_change (sample_point);
|
||||
|
||||
g_object_set (sample_point,
|
||||
"x", x,
|
||||
"y", y,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (sample_point);
|
||||
}
|
||||
67
app/display/pikacanvassamplepoint.h
Normal file
67
app/display/pikacanvassamplepoint.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvassamplepoint.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_SAMPLE_POINT_H__
|
||||
#define __PIKA_CANVAS_SAMPLE_POINT_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_SAMPLE_POINT (pika_canvas_sample_point_get_type ())
|
||||
#define PIKA_CANVAS_SAMPLE_POINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_SAMPLE_POINT, PikaCanvasSamplePoint))
|
||||
#define PIKA_CANVAS_SAMPLE_POINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_SAMPLE_POINT, PikaCanvasSamplePointClass))
|
||||
#define PIKA_IS_CANVAS_SAMPLE_POINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_SAMPLE_POINT))
|
||||
#define PIKA_IS_CANVAS_SAMPLE_POINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_SAMPLE_POINT))
|
||||
#define PIKA_CANVAS_SAMPLE_POINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_SAMPLE_POINT, PikaCanvasSamplePointClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasSamplePoint PikaCanvasSamplePoint;
|
||||
typedef struct _PikaCanvasSamplePointClass PikaCanvasSamplePointClass;
|
||||
|
||||
struct _PikaCanvasSamplePoint
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasSamplePointClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_sample_point_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_sample_point_new (PikaDisplayShell *shell,
|
||||
gint x,
|
||||
gint y,
|
||||
gint index,
|
||||
gboolean sample_point_style);
|
||||
|
||||
void pika_canvas_sample_point_set (PikaCanvasItem *sample_point,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_SAMPLE_POINT_H__ */
|
||||
274
app/display/pikacanvastext.c
Normal file
274
app/display/pikacanvastext.c
Normal file
@ -0,0 +1,274 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvastext.c
|
||||
* Copyright (C) 2023 mr.fantastic <mrfantastic@firemail.cc>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvastext.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_FONT_SIZE,
|
||||
PROP_TEXT
|
||||
};
|
||||
|
||||
typedef struct _PikaCanvasTextPrivate PikaCanvasTextPrivate;
|
||||
|
||||
struct _PikaCanvasTextPrivate
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble font_size;
|
||||
gchar *text;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(text_item) \
|
||||
((PikaCanvasTextPrivate *) pika_canvas_text_get_instance_private ((PikaCanvasText *) (text_item)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_text_finalize (GObject *object);
|
||||
static void pika_canvas_text_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_text_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_text_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_text_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasText, pika_canvas_text,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_text_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_text_class_init (PikaCanvasTextClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_canvas_text_finalize;
|
||||
object_class->set_property = pika_canvas_text_set_property;
|
||||
object_class->get_property = pika_canvas_text_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_text_draw;
|
||||
item_class->get_extents = pika_canvas_text_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_double ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_double ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FONT_SIZE,
|
||||
g_param_spec_double ("font-size", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TEXT,
|
||||
g_param_spec_string ("text", NULL, NULL,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_init (PikaCanvasText *text)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTextPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_FONT_SIZE:
|
||||
private->font_size = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
private->text = (gchar *) g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTextPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_double (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_double (value, private->y);
|
||||
break;
|
||||
case PROP_FONT_SIZE:
|
||||
g_value_set_double (value, private->font_size);
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, private->text);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_transform (PikaCanvasItem *item,
|
||||
gdouble *x1,
|
||||
gdouble *y1,
|
||||
gdouble *x2,
|
||||
gdouble *y2)
|
||||
{
|
||||
PikaCanvasTextPrivate *private = GET_PRIVATE (item);
|
||||
cairo_text_extents_t extents;
|
||||
cairo_surface_t *dummy_surface;
|
||||
cairo_t *cr;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
private->x, private->y,
|
||||
x1, y1);
|
||||
|
||||
dummy_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 0, 0);
|
||||
cr = cairo_create (dummy_surface);
|
||||
|
||||
cairo_set_font_size (cr, private->font_size);
|
||||
cairo_text_extents (cr, private->text, &extents);
|
||||
|
||||
cairo_surface_destroy (dummy_surface);
|
||||
cairo_destroy (cr);
|
||||
|
||||
*x1 = floor (*x1) + 0.5;
|
||||
*y1 = floor (*y1) + 0.5;
|
||||
*x2 = extents.width;
|
||||
*y2 = extents.height;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gdouble x, y, ignore_x2, ignore_y2;
|
||||
|
||||
PikaCanvasTextPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_text_transform (item, &x, &y, &ignore_x2, &ignore_y2);
|
||||
|
||||
cairo_set_font_size (cr, private->font_size);
|
||||
cairo_move_to (cr, x,y);
|
||||
cairo_text_path (cr, private->text);
|
||||
|
||||
_pika_canvas_item_fill (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_text_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x1, y1, x2, y2;
|
||||
|
||||
pika_canvas_text_transform (item, &x1, &y1, &x2, &y2);
|
||||
|
||||
rectangle.x = (gint) x1-1;
|
||||
rectangle.y = (gint) (y1-y2-1);
|
||||
rectangle.width = (gint) x2+3;
|
||||
rectangle.height = (gint) y2+3;
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_text_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble font_size,
|
||||
gchar *text)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_TEXT,
|
||||
"shell", shell,
|
||||
"x", x,
|
||||
"y", y,
|
||||
"font-size", font_size,
|
||||
"text", text,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_finalize (GObject *object)
|
||||
{
|
||||
PikaCanvasTextPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_free (private->text);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
62
app/display/pikacanvastext.h
Normal file
62
app/display/pikacanvastext.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvastext.h
|
||||
* Copyright (C) 2023 mr.fantastic <mrfantastic@firemail.cc>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKACANVASTEXT_H__
|
||||
#define __PIKACANVASTEXT_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_TEXT (pika_canvas_text_get_type ())
|
||||
#define PIKA_CANVAS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_TEXT, PikaCanvasText))
|
||||
#define PIKA_CANVAS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_TEXT, PikaCanvasTextClass))
|
||||
#define PIKA_IS_CANVAS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((klass), PIKA_TYPE_CANVAS_TEXT))
|
||||
#define PIKA_IS_CANVAS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_TEXT))
|
||||
#define PIKA_CANVAS_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_TEXT, PikaCanvasTextClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasText PikaCanvasText;
|
||||
typedef struct _PikaCanvasTextClass PikaCanvasTextClass;
|
||||
|
||||
struct _PikaCanvasText
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasTextClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_text_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_text_new (PikaDisplayShell *shell,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble font_size,
|
||||
gchar *text);
|
||||
|
||||
#endif
|
||||
390
app/display/pikacanvastextcursor.c
Normal file
390
app/display/pikacanvastextcursor.c
Normal file
@ -0,0 +1,390 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvastextcursor.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvastextcursor.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_X,
|
||||
PROP_Y,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_OVERWRITE,
|
||||
PROP_DIRECTION
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasTextCursorPrivate PikaCanvasTextCursorPrivate;
|
||||
|
||||
struct _PikaCanvasTextCursorPrivate
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
gint width;
|
||||
gint height;
|
||||
gboolean overwrite;
|
||||
PikaTextDirection direction;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(text_cursor) \
|
||||
((PikaCanvasTextCursorPrivate *) pika_canvas_text_cursor_get_instance_private ((PikaCanvasTextCursor *) (text_cursor)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_text_cursor_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_text_cursor_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_text_cursor_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_text_cursor_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasTextCursor, pika_canvas_text_cursor,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_text_cursor_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_text_cursor_class_init (PikaCanvasTextCursorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_text_cursor_set_property;
|
||||
object_class->get_property = pika_canvas_text_cursor_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_text_cursor_draw;
|
||||
item_class->get_extents = pika_canvas_text_cursor_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X,
|
||||
g_param_spec_int ("x", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y,
|
||||
g_param_spec_int ("y", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WIDTH,
|
||||
g_param_spec_int ("width", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HEIGHT,
|
||||
g_param_spec_int ("height", NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE, 0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OVERWRITE,
|
||||
g_param_spec_boolean ("overwrite", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_DIRECTION,
|
||||
g_param_spec_enum ("direction", NULL, NULL,
|
||||
pika_text_direction_get_type(),
|
||||
PIKA_TEXT_DIRECTION_LTR,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_cursor_init (PikaCanvasTextCursor *text_cursor)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_cursor_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTextCursorPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
private->x = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_Y:
|
||||
private->y = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
private->width = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
private->height = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_OVERWRITE:
|
||||
private->overwrite = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_DIRECTION:
|
||||
private->direction = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_cursor_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTextCursorPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_X:
|
||||
g_value_set_int (value, private->x);
|
||||
break;
|
||||
case PROP_Y:
|
||||
g_value_set_int (value, private->y);
|
||||
break;
|
||||
case PROP_WIDTH:
|
||||
g_value_set_int (value, private->width);
|
||||
break;
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_int (value, private->height);
|
||||
break;
|
||||
case PROP_OVERWRITE:
|
||||
g_value_set_boolean (value, private->overwrite);
|
||||
break;
|
||||
case PROP_DIRECTION:
|
||||
g_value_set_enum (value, private->direction);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_cursor_transform (PikaCanvasItem *item,
|
||||
gdouble *x,
|
||||
gdouble *y,
|
||||
gdouble *w,
|
||||
gdouble *h)
|
||||
{
|
||||
PikaCanvasTextCursorPrivate *private = GET_PRIVATE (item);
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MIN (private->x,
|
||||
private->x + private->width),
|
||||
MIN (private->y,
|
||||
private->y + private->height),
|
||||
x, y);
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
MAX (private->x,
|
||||
private->x + private->width),
|
||||
MAX (private->y,
|
||||
private->y + private->height),
|
||||
w, h);
|
||||
|
||||
*w -= *x;
|
||||
*h -= *y;
|
||||
|
||||
*x = floor (*x) + 0.5;
|
||||
*y = floor (*y) + 0.5;
|
||||
switch (private->direction)
|
||||
{
|
||||
case PIKA_TEXT_DIRECTION_LTR:
|
||||
case PIKA_TEXT_DIRECTION_RTL:
|
||||
break;
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL:
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
||||
*x = *x - *w;
|
||||
break;
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR:
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
||||
*y = *y + *h;
|
||||
break;
|
||||
}
|
||||
|
||||
if (private->overwrite)
|
||||
{
|
||||
*w = ceil (*w) - 1.0;
|
||||
*h = ceil (*h) - 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (private->direction)
|
||||
{
|
||||
case PIKA_TEXT_DIRECTION_LTR:
|
||||
case PIKA_TEXT_DIRECTION_RTL:
|
||||
*w = 0;
|
||||
*h = ceil (*h) - 1.0;
|
||||
break;
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL:
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
||||
*w = ceil (*w) - 1.0;
|
||||
*h = 0;
|
||||
break;
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR:
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
||||
*w = ceil (*w) - 1.0;
|
||||
*h = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_text_cursor_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasTextCursorPrivate *private = GET_PRIVATE (item);
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_text_cursor_transform (item, &x, &y, &w, &h);
|
||||
|
||||
if (private->overwrite)
|
||||
{
|
||||
cairo_rectangle (cr, x, y, w, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (private->direction)
|
||||
{
|
||||
case PIKA_TEXT_DIRECTION_LTR:
|
||||
case PIKA_TEXT_DIRECTION_RTL:
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_line_to (cr, x, y + h);
|
||||
|
||||
cairo_move_to (cr, x - 3.0, y);
|
||||
cairo_line_to (cr, x + 3.0, y);
|
||||
|
||||
cairo_move_to (cr, x - 3.0, y + h);
|
||||
cairo_line_to (cr, x + 3.0, y + h);
|
||||
break;
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL:
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR:
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_line_to (cr, x + w, y);
|
||||
|
||||
cairo_move_to (cr, x, y - 3.0);
|
||||
cairo_line_to (cr, x, y + 3.0);
|
||||
|
||||
cairo_move_to (cr, x + w, y - 3.0);
|
||||
cairo_line_to (cr, x + w, y + 3.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_text_cursor_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaCanvasTextCursorPrivate *private = GET_PRIVATE (item);
|
||||
cairo_rectangle_int_t rectangle;
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
pika_canvas_text_cursor_transform (item, &x, &y, &w, &h);
|
||||
|
||||
if (private->overwrite)
|
||||
{
|
||||
rectangle.x = floor (x - 1.5);
|
||||
rectangle.y = floor (y - 1.5);
|
||||
rectangle.width = ceil (w + 3.0);
|
||||
rectangle.height = ceil (h + 3.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (private->direction)
|
||||
{
|
||||
case PIKA_TEXT_DIRECTION_LTR:
|
||||
case PIKA_TEXT_DIRECTION_RTL:
|
||||
rectangle.x = floor (x - 4.5);
|
||||
rectangle.y = floor (y - 1.5);
|
||||
rectangle.width = ceil (9.0);
|
||||
rectangle.height = ceil (h + 3.0);
|
||||
break;
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL:
|
||||
case PIKA_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR:
|
||||
case PIKA_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
||||
rectangle.x = floor (x - 1.5);
|
||||
rectangle.y = floor (y - 4.5);
|
||||
rectangle.width = ceil (w + 3.0);
|
||||
rectangle.height = ceil (9.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_text_cursor_new (PikaDisplayShell *shell,
|
||||
PangoRectangle *cursor,
|
||||
gboolean overwrite,
|
||||
PikaTextDirection direction)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (cursor != NULL, NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_TEXT_CURSOR,
|
||||
"shell", shell,
|
||||
"x", cursor->x,
|
||||
"y", cursor->y,
|
||||
"width", cursor->width,
|
||||
"height", cursor->height,
|
||||
"overwrite", overwrite,
|
||||
"direction", direction,
|
||||
NULL);
|
||||
}
|
||||
62
app/display/pikacanvastextcursor.h
Normal file
62
app/display/pikacanvastextcursor.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvastextcursor.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_TEXT_CURSOR_H__
|
||||
#define __PIKA_CANVAS_TEXT_CURSOR_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_TEXT_CURSOR (pika_canvas_text_cursor_get_type ())
|
||||
#define PIKA_CANVAS_TEXT_CURSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_TEXT_CURSOR, PikaCanvasTextCursor))
|
||||
#define PIKA_CANVAS_TEXT_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_TEXT_CURSOR, PikaCanvasTextCursorClass))
|
||||
#define PIKA_IS_CANVAS_TEXT_CURSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_TEXT_CURSOR))
|
||||
#define PIKA_IS_CANVAS_TEXT_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_TEXT_CURSOR))
|
||||
#define PIKA_CANVAS_TEXT_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_TEXT_CURSOR, PikaCanvasTextCursorClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasTextCursor PikaCanvasTextCursor;
|
||||
typedef struct _PikaCanvasTextCursorClass PikaCanvasTextCursorClass;
|
||||
|
||||
struct _PikaCanvasTextCursor
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasTextCursorClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_text_cursor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_text_cursor_new (PikaDisplayShell *shell,
|
||||
PangoRectangle *cursor,
|
||||
gboolean overwrite,
|
||||
PikaTextDirection direction);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_RECTANGLE_H__ */
|
||||
687
app/display/pikacanvastransformguides.c
Normal file
687
app/display/pikacanvastransformguides.c
Normal file
@ -0,0 +1,687 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvastransformguides.c
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-transform-utils.h"
|
||||
#include "core/pika-utils.h"
|
||||
|
||||
#include "pikacanvastransformguides.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
#define SQRT5 2.236067977
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TRANSFORM,
|
||||
PROP_X1,
|
||||
PROP_Y1,
|
||||
PROP_X2,
|
||||
PROP_Y2,
|
||||
PROP_TYPE,
|
||||
PROP_N_GUIDES,
|
||||
PROP_CLIP
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasTransformGuidesPrivate PikaCanvasTransformGuidesPrivate;
|
||||
|
||||
struct _PikaCanvasTransformGuidesPrivate
|
||||
{
|
||||
PikaMatrix3 transform;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
PikaGuidesType type;
|
||||
gint n_guides;
|
||||
gboolean clip;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(transform) \
|
||||
((PikaCanvasTransformGuidesPrivate *) pika_canvas_transform_guides_get_instance_private ((PikaCanvasTransformGuides *) (transform)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_transform_guides_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_transform_guides_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_transform_guides_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_transform_guides_get_extents (PikaCanvasItem *item);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasTransformGuides,
|
||||
pika_canvas_transform_guides, PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_transform_guides_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_transform_guides_class_init (PikaCanvasTransformGuidesClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_canvas_transform_guides_set_property;
|
||||
object_class->get_property = pika_canvas_transform_guides_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_transform_guides_draw;
|
||||
item_class->get_extents = pika_canvas_transform_guides_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TRANSFORM,
|
||||
pika_param_spec_matrix3 ("transform",
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X1,
|
||||
g_param_spec_double ("x1",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y1,
|
||||
g_param_spec_double ("y1",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X2,
|
||||
g_param_spec_double ("x2",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y2,
|
||||
g_param_spec_double ("y2",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TYPE,
|
||||
g_param_spec_enum ("type", NULL, NULL,
|
||||
PIKA_TYPE_GUIDES_TYPE,
|
||||
PIKA_GUIDES_NONE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_N_GUIDES,
|
||||
g_param_spec_int ("n-guides", NULL, NULL,
|
||||
1, 128, 4,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CLIP,
|
||||
g_param_spec_boolean ("clip", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_guides_init (PikaCanvasTransformGuides *transform)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_guides_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTransformGuidesPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TRANSFORM:
|
||||
{
|
||||
PikaMatrix3 *transform = g_value_get_boxed (value);
|
||||
|
||||
if (transform)
|
||||
private->transform = *transform;
|
||||
else
|
||||
pika_matrix3_identity (&private->transform);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_X1:
|
||||
private->x1 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_Y1:
|
||||
private->y1 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_X2:
|
||||
private->x2 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_Y2:
|
||||
private->y2 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_TYPE:
|
||||
private->type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_N_GUIDES:
|
||||
private->n_guides = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_CLIP:
|
||||
private->clip = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_guides_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTransformGuidesPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TRANSFORM:
|
||||
g_value_set_boxed (value, &private->transform);
|
||||
break;
|
||||
|
||||
case PROP_X1:
|
||||
g_value_set_double (value, private->x1);
|
||||
break;
|
||||
|
||||
case PROP_Y1:
|
||||
g_value_set_double (value, private->y1);
|
||||
break;
|
||||
|
||||
case PROP_X2:
|
||||
g_value_set_double (value, private->x2);
|
||||
break;
|
||||
|
||||
case PROP_Y2:
|
||||
g_value_set_double (value, private->y2);
|
||||
break;
|
||||
|
||||
case PROP_TYPE:
|
||||
g_value_set_enum (value, private->type);
|
||||
break;
|
||||
|
||||
case PROP_N_GUIDES:
|
||||
g_value_set_int (value, private->n_guides);
|
||||
break;
|
||||
|
||||
case PROP_CLIP:
|
||||
g_value_set_boolean (value, private->clip);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_transform_guides_transform (PikaCanvasItem *item,
|
||||
PikaVector2 *t_vertices,
|
||||
gint *n_t_vertices)
|
||||
{
|
||||
PikaCanvasTransformGuidesPrivate *private = GET_PRIVATE (item);
|
||||
PikaVector2 vertices[4];
|
||||
|
||||
vertices[0] = (PikaVector2) { private->x1, private->y1 };
|
||||
vertices[1] = (PikaVector2) { private->x2, private->y1 };
|
||||
vertices[2] = (PikaVector2) { private->x2, private->y2 };
|
||||
vertices[3] = (PikaVector2) { private->x1, private->y2 };
|
||||
|
||||
if (private->clip)
|
||||
{
|
||||
pika_transform_polygon (&private->transform, vertices, 4, TRUE,
|
||||
t_vertices, n_t_vertices);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
pika_matrix3_transform_point (&private->transform,
|
||||
vertices[i].x, vertices[i].y,
|
||||
&t_vertices[i].x, &t_vertices[i].y);
|
||||
}
|
||||
|
||||
*n_t_vertices = 4;
|
||||
|
||||
return pika_transform_polygon_is_convex (t_vertices[0].x, t_vertices[0].y,
|
||||
t_vertices[1].x, t_vertices[1].y,
|
||||
t_vertices[3].x, t_vertices[3].y,
|
||||
t_vertices[2].x, t_vertices[2].y);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_line (cairo_t *cr,
|
||||
PikaCanvasItem *item,
|
||||
PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2)
|
||||
{
|
||||
PikaCanvasTransformGuidesPrivate *private = GET_PRIVATE (item);
|
||||
PikaVector2 vertices[2];
|
||||
PikaVector2 t_vertices[2];
|
||||
gint n_t_vertices;
|
||||
|
||||
vertices[0] = (PikaVector2) { x1, y1 };
|
||||
vertices[1] = (PikaVector2) { x2, y2 };
|
||||
|
||||
if (private->clip)
|
||||
{
|
||||
pika_transform_polygon (transform, vertices, 2, FALSE,
|
||||
t_vertices, &n_t_vertices);
|
||||
}
|
||||
else
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
pika_matrix3_transform_point (transform,
|
||||
vertices[i].x, vertices[i].y,
|
||||
&t_vertices[i].x, &t_vertices[i].y);
|
||||
}
|
||||
|
||||
n_t_vertices = 2;
|
||||
}
|
||||
|
||||
if (n_t_vertices == 2)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
PikaVector2 v;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
t_vertices[i].x, t_vertices[i].y,
|
||||
&v.x, &v.y);
|
||||
|
||||
v.x = floor (v.x) + 0.5;
|
||||
v.y = floor (v.y) + 0.5;
|
||||
|
||||
if (i == 0)
|
||||
cairo_move_to (cr, v.x, v.y);
|
||||
else
|
||||
cairo_line_to (cr, v.x, v.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_hline (cairo_t *cr,
|
||||
PikaCanvasItem *item,
|
||||
PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble x2,
|
||||
gdouble y)
|
||||
{
|
||||
draw_line (cr, item, transform, x1, y, x2, y);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_vline (cairo_t *cr,
|
||||
PikaCanvasItem *item,
|
||||
PikaMatrix3 *transform,
|
||||
gdouble y1,
|
||||
gdouble y2,
|
||||
gdouble x)
|
||||
{
|
||||
draw_line (cr, item, transform, x, y1, x, y2);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_guides_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasTransformGuidesPrivate *private = GET_PRIVATE (item);
|
||||
PikaVector2 t_vertices[5];
|
||||
gint n_t_vertices;
|
||||
gboolean convex;
|
||||
gint i;
|
||||
|
||||
convex = pika_canvas_transform_guides_transform (item,
|
||||
t_vertices, &n_t_vertices);
|
||||
|
||||
if (n_t_vertices < 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < n_t_vertices; i++)
|
||||
{
|
||||
PikaVector2 v;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item, t_vertices[i].x, t_vertices[i].y,
|
||||
&v.x, &v.y);
|
||||
|
||||
v.x = floor (v.x) + 0.5;
|
||||
v.y = floor (v.y) + 0.5;
|
||||
|
||||
if (i == 0)
|
||||
cairo_move_to (cr, v.x, v.y);
|
||||
else
|
||||
cairo_line_to (cr, v.x, v.y);
|
||||
}
|
||||
|
||||
cairo_close_path (cr);
|
||||
|
||||
if (! convex || n_t_vertices < 3)
|
||||
{
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (private->type)
|
||||
{
|
||||
case PIKA_GUIDES_NONE:
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_CENTER_LINES:
|
||||
draw_hline (cr, item, &private->transform,
|
||||
private->x1, private->x2, (private->y1 + private->y2) / 2);
|
||||
draw_vline (cr, item, &private->transform,
|
||||
private->y1, private->y2, (private->x1 + private->x2) / 2);
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_THIRDS:
|
||||
draw_hline (cr, item, &private->transform,
|
||||
private->x1, private->x2, (2 * private->y1 + private->y2) / 3);
|
||||
draw_hline (cr, item, &private->transform,
|
||||
private->x1, private->x2, (private->y1 + 2 * private->y2) / 3);
|
||||
|
||||
draw_vline (cr, item, &private->transform,
|
||||
private->y1, private->y2, (2 * private->x1 + private->x2) / 3);
|
||||
draw_vline (cr, item, &private->transform,
|
||||
private->y1, private->y2, (private->x1 + 2 * private->x2) / 3);
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_FIFTHS:
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
draw_hline (cr, item, &private->transform,
|
||||
private->x1, private->x2,
|
||||
private->y1 + i * (private->y2 - private->y1) / 5);
|
||||
draw_vline (cr, item, &private->transform,
|
||||
private->y1, private->y2,
|
||||
private->x1 + i * (private->x2 - private->x1) / 5);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_GOLDEN:
|
||||
draw_hline (cr, item, &private->transform,
|
||||
private->x1, private->x2,
|
||||
(2 * private->y1 + (1 + SQRT5) * private->y2) / (3 + SQRT5));
|
||||
draw_hline (cr, item, &private->transform,
|
||||
private->x1, private->x2,
|
||||
((1 + SQRT5) * private->y1 + 2 * private->y2) / (3 + SQRT5));
|
||||
|
||||
draw_vline (cr, item, &private->transform,
|
||||
private->y1, private->y2,
|
||||
(2 * private->x1 + (1 + SQRT5) * private->x2) / (3 + SQRT5));
|
||||
draw_vline (cr, item, &private->transform,
|
||||
private->y1, private->y2,
|
||||
((1 + SQRT5) * private->x1 + 2 * private->x2) / (3 + SQRT5));
|
||||
break;
|
||||
|
||||
/* This code implements the method of diagonals discovered by
|
||||
* Edwin Westhoff - see http://www.diagonalmethod.info/
|
||||
*/
|
||||
case PIKA_GUIDES_DIAGONALS:
|
||||
{
|
||||
/* the side of the largest square that can be
|
||||
* fitted in whole into the rectangle (x1, y1), (x2, y2)
|
||||
*/
|
||||
const gdouble square_side = MIN (private->x2 - private->x1,
|
||||
private->y2 - private->y1);
|
||||
|
||||
/* diagonal from the top-left edge */
|
||||
draw_line (cr, item, &private->transform,
|
||||
private->x1, private->y1,
|
||||
private->x1 + square_side,
|
||||
private->y1 + square_side);
|
||||
|
||||
/* diagonal from the top-right edge */
|
||||
draw_line (cr, item, &private->transform,
|
||||
private->x2, private->y1,
|
||||
private->x2 - square_side,
|
||||
private->y1 + square_side);
|
||||
|
||||
/* diagonal from the bottom-left edge */
|
||||
draw_line (cr, item, &private->transform,
|
||||
private->x1, private->y2,
|
||||
private->x1 + square_side,
|
||||
private->y2 - square_side);
|
||||
|
||||
/* diagonal from the bottom-right edge */
|
||||
draw_line (cr, item, &private->transform,
|
||||
private->x2, private->y2,
|
||||
private->x2 - square_side,
|
||||
private->y2 - square_side);
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_GUIDES_N_LINES:
|
||||
case PIKA_GUIDES_SPACING:
|
||||
{
|
||||
gint width, height;
|
||||
gint ngx, ngy;
|
||||
|
||||
width = MAX (1, private->x2 - private->x1);
|
||||
height = MAX (1, private->y2 - private->y1);
|
||||
|
||||
/* the MIN() in the code below limits the grid to one line
|
||||
* every 5 image pixels, see bug 772667.
|
||||
*/
|
||||
|
||||
if (private->type == PIKA_GUIDES_N_LINES)
|
||||
{
|
||||
if (width <= height)
|
||||
{
|
||||
ngx = private->n_guides;
|
||||
ngx = MIN (ngx, width / 5);
|
||||
|
||||
ngy = ngx * MAX (1, height / width);
|
||||
ngy = MIN (ngy, height / 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
ngy = private->n_guides;
|
||||
ngy = MIN (ngy, height / 5);
|
||||
|
||||
ngx = ngy * MAX (1, width / height);
|
||||
ngx = MIN (ngx, width / 5);
|
||||
}
|
||||
}
|
||||
else /* PIKA_GUIDES_SPACING */
|
||||
{
|
||||
gint grid_size = MAX (2, private->n_guides);
|
||||
|
||||
ngx = width / grid_size;
|
||||
ngx = MIN (ngx, width / 5);
|
||||
|
||||
ngy = height / grid_size;
|
||||
ngy = MIN (ngy, height / 5);
|
||||
}
|
||||
|
||||
for (i = 1; i <= ngx; i++)
|
||||
{
|
||||
gdouble x = private->x1 + (((gdouble) i) / (ngx + 1) *
|
||||
(private->x2 - private->x1));
|
||||
|
||||
draw_line (cr, item, &private->transform,
|
||||
x, private->y1,
|
||||
x, private->y2);
|
||||
}
|
||||
|
||||
for (i = 1; i <= ngy; i++)
|
||||
{
|
||||
gdouble y = private->y1 + (((gdouble) i) / (ngy + 1) *
|
||||
(private->y2 - private->y1));
|
||||
|
||||
draw_line (cr, item, &private->transform,
|
||||
private->x1, y,
|
||||
private->x2, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pika_canvas_item_stroke (item, cr);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_transform_guides_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
PikaVector2 t_vertices[5];
|
||||
gint n_t_vertices;
|
||||
PikaVector2 top_left;
|
||||
PikaVector2 bottom_right;
|
||||
cairo_rectangle_int_t extents;
|
||||
gint i;
|
||||
|
||||
pika_canvas_transform_guides_transform (item, t_vertices, &n_t_vertices);
|
||||
|
||||
if (n_t_vertices < 2)
|
||||
return cairo_region_create ();
|
||||
|
||||
for (i = 0; i < n_t_vertices; i++)
|
||||
{
|
||||
PikaVector2 v;
|
||||
|
||||
pika_canvas_item_transform_xy_f (item,
|
||||
t_vertices[i].x, t_vertices[i].y,
|
||||
&v.x, &v.y);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
top_left = bottom_right = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
top_left.x = MIN (top_left.x, v.x);
|
||||
top_left.y = MIN (top_left.y, v.y);
|
||||
|
||||
bottom_right.x = MAX (bottom_right.x, v.x);
|
||||
bottom_right.y = MAX (bottom_right.y, v.y);
|
||||
}
|
||||
}
|
||||
|
||||
extents.x = (gint) floor (top_left.x - 1.5);
|
||||
extents.y = (gint) floor (top_left.y - 1.5);
|
||||
extents.width = (gint) ceil (bottom_right.x + 1.5) - extents.x;
|
||||
extents.height = (gint) ceil (bottom_right.y + 1.5) - extents.y;
|
||||
|
||||
return cairo_region_create_rectangle (&extents);
|
||||
}
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_transform_guides_new (PikaDisplayShell *shell,
|
||||
const PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
PikaGuidesType type,
|
||||
gint n_guides,
|
||||
gboolean clip)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_TRANSFORM_GUIDES,
|
||||
"shell", shell,
|
||||
"transform", transform,
|
||||
"x1", x1,
|
||||
"y1", y1,
|
||||
"x2", x2,
|
||||
"y2", y2,
|
||||
"type", type,
|
||||
"n-guides", n_guides,
|
||||
"clip", clip,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_canvas_transform_guides_set (PikaCanvasItem *guides,
|
||||
const PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
PikaGuidesType type,
|
||||
gint n_guides,
|
||||
gboolean clip)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CANVAS_TRANSFORM_GUIDES (guides));
|
||||
|
||||
pika_canvas_item_begin_change (guides);
|
||||
|
||||
g_object_set (guides,
|
||||
"transform", transform,
|
||||
"x1", x1,
|
||||
"y1", y1,
|
||||
"x2", x2,
|
||||
"y2", y2,
|
||||
"type", type,
|
||||
"n-guides", n_guides,
|
||||
"clip", clip,
|
||||
NULL);
|
||||
|
||||
pika_canvas_item_end_change (guides);
|
||||
}
|
||||
77
app/display/pikacanvastransformguides.h
Normal file
77
app/display/pikacanvastransformguides.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvastransformguides.h
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_TRANSFORM_GUIDES_H__
|
||||
#define __PIKA_CANVAS_TRANSFORM_GUIDES_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_TRANSFORM_GUIDES (pika_canvas_transform_guides_get_type ())
|
||||
#define PIKA_CANVAS_TRANSFORM_GUIDES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_TRANSFORM_GUIDES, PikaCanvasTransformGuides))
|
||||
#define PIKA_CANVAS_TRANSFORM_GUIDES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_TRANSFORM_GUIDES, PikaCanvasTransformGuidesClass))
|
||||
#define PIKA_IS_CANVAS_TRANSFORM_GUIDES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_TRANSFORM_GUIDES))
|
||||
#define PIKA_IS_CANVAS_TRANSFORM_GUIDES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_TRANSFORM_GUIDES))
|
||||
#define PIKA_CANVAS_TRANSFORM_GUIDES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_TRANSFORM_GUIDES, PikaCanvasTransformGuidesClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasTransformGuides PikaCanvasTransformGuides;
|
||||
typedef struct _PikaCanvasTransformGuidesClass PikaCanvasTransformGuidesClass;
|
||||
|
||||
struct _PikaCanvasTransformGuides
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasTransformGuidesClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_transform_guides_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_transform_guides_new (PikaDisplayShell *shell,
|
||||
const PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
PikaGuidesType type,
|
||||
gint n_guides,
|
||||
gboolean clip);
|
||||
|
||||
void pika_canvas_transform_guides_set (PikaCanvasItem *guides,
|
||||
const PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
PikaGuidesType type,
|
||||
gint n_guides,
|
||||
gboolean clip);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_TRANSFORM_GUIDES_H__ */
|
||||
795
app/display/pikacanvastransformpreview.c
Normal file
795
app/display/pikacanvastransformpreview.c
Normal file
@ -0,0 +1,795 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacanvastransformpreview.c
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display/display-types.h"
|
||||
|
||||
#include "gegl/pika-gegl-nodes.h"
|
||||
#include "gegl/pika-gegl-utils.h"
|
||||
#include "gegl/pikatilehandlervalidate.h"
|
||||
|
||||
#include "core/pika-transform-resize.h"
|
||||
#include "core/pika-transform-utils.h"
|
||||
#include "core/pika-utils.h"
|
||||
#include "core/pikachannel.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikapickable.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvastransformpreview.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PICKABLE,
|
||||
PROP_TRANSFORM,
|
||||
PROP_CLIP,
|
||||
PROP_X1,
|
||||
PROP_Y1,
|
||||
PROP_X2,
|
||||
PROP_Y2,
|
||||
PROP_OPACITY
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaCanvasTransformPreviewPrivate PikaCanvasTransformPreviewPrivate;
|
||||
|
||||
struct _PikaCanvasTransformPreviewPrivate
|
||||
{
|
||||
PikaPickable *pickable;
|
||||
PikaMatrix3 transform;
|
||||
PikaTransformResize clip;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
gdouble opacity;
|
||||
|
||||
GeglNode *node;
|
||||
GeglNode *source_node;
|
||||
GeglNode *convert_format_node;
|
||||
GeglNode *layer_mask_source_node;
|
||||
GeglNode *layer_mask_opacity_node;
|
||||
GeglNode *mask_source_node;
|
||||
GeglNode *mask_translate_node;
|
||||
GeglNode *mask_crop_node;
|
||||
GeglNode *opacity_node;
|
||||
GeglNode *cache_node;
|
||||
GeglNode *transform_node;
|
||||
|
||||
PikaPickable *node_pickable;
|
||||
PikaDrawable *node_layer_mask;
|
||||
PikaDrawable *node_mask;
|
||||
GeglRectangle node_rect;
|
||||
gdouble node_opacity;
|
||||
PikaMatrix3 node_matrix;
|
||||
GeglNode *node_output;
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(transform_preview) \
|
||||
((PikaCanvasTransformPreviewPrivate *) pika_canvas_transform_preview_get_instance_private ((PikaCanvasTransformPreview *) (transform_preview)))
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_canvas_transform_preview_dispose (GObject *object);
|
||||
static void pika_canvas_transform_preview_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_canvas_transform_preview_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_canvas_transform_preview_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr);
|
||||
static cairo_region_t * pika_canvas_transform_preview_get_extents (PikaCanvasItem *item);
|
||||
|
||||
static void pika_canvas_transform_preview_layer_changed (PikaLayer *layer,
|
||||
PikaCanvasTransformPreview *transform_preview);
|
||||
|
||||
static void pika_canvas_transform_preview_set_pickable (PikaCanvasTransformPreview *transform_preview,
|
||||
PikaPickable *pickable);
|
||||
static void pika_canvas_transform_preview_sync_node (PikaCanvasTransformPreview *transform_preview);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaCanvasTransformPreview,
|
||||
pika_canvas_transform_preview,
|
||||
PIKA_TYPE_CANVAS_ITEM)
|
||||
|
||||
#define parent_class pika_canvas_transform_preview_parent_class
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_class_init (PikaCanvasTransformPreviewClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaCanvasItemClass *item_class = PIKA_CANVAS_ITEM_CLASS (klass);
|
||||
|
||||
object_class->dispose = pika_canvas_transform_preview_dispose;
|
||||
object_class->set_property = pika_canvas_transform_preview_set_property;
|
||||
object_class->get_property = pika_canvas_transform_preview_get_property;
|
||||
|
||||
item_class->draw = pika_canvas_transform_preview_draw;
|
||||
item_class->get_extents = pika_canvas_transform_preview_get_extents;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PICKABLE,
|
||||
g_param_spec_object ("pickable",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_PICKABLE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TRANSFORM,
|
||||
pika_param_spec_matrix3 ("transform",
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CLIP,
|
||||
g_param_spec_enum ("clip",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_TRANSFORM_RESIZE,
|
||||
PIKA_TRANSFORM_RESIZE_ADJUST,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X1,
|
||||
g_param_spec_double ("x1",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y1,
|
||||
g_param_spec_double ("y1",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_X2,
|
||||
g_param_spec_double ("x2",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_Y2,
|
||||
g_param_spec_double ("y2",
|
||||
NULL, NULL,
|
||||
-PIKA_MAX_IMAGE_SIZE,
|
||||
PIKA_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OPACITY,
|
||||
g_param_spec_double ("opacity",
|
||||
NULL, NULL,
|
||||
0.0, 1.0, 1.0,
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_init (PikaCanvasTransformPreview *transform_preview)
|
||||
{
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (transform_preview);
|
||||
|
||||
private->clip = PIKA_TRANSFORM_RESIZE_ADJUST;
|
||||
private->opacity = 1.0;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_dispose (GObject *object)
|
||||
{
|
||||
PikaCanvasTransformPreview *transform_preview = PIKA_CANVAS_TRANSFORM_PREVIEW (object);
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
g_clear_object (&private->node);
|
||||
|
||||
pika_canvas_transform_preview_set_pickable (transform_preview, NULL);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTransformPreview *transform_preview = PIKA_CANVAS_TRANSFORM_PREVIEW (object);
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PICKABLE:
|
||||
pika_canvas_transform_preview_set_pickable (transform_preview,
|
||||
g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_TRANSFORM:
|
||||
{
|
||||
PikaMatrix3 *transform = g_value_get_boxed (value);
|
||||
|
||||
if (transform)
|
||||
private->transform = *transform;
|
||||
else
|
||||
pika_matrix3_identity (&private->transform);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_CLIP:
|
||||
private->clip = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_X1:
|
||||
private->x1 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_Y1:
|
||||
private->y1 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_X2:
|
||||
private->x2 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_Y2:
|
||||
private->y2 = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
private->opacity = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PICKABLE:
|
||||
g_value_set_object (value, private->pickable);
|
||||
break;
|
||||
|
||||
case PROP_TRANSFORM:
|
||||
g_value_set_boxed (value, &private->transform);
|
||||
break;
|
||||
|
||||
case PROP_CLIP:
|
||||
g_value_set_enum (value, private->clip);
|
||||
break;
|
||||
|
||||
case PROP_X1:
|
||||
g_value_set_double (value, private->x1);
|
||||
break;
|
||||
|
||||
case PROP_Y1:
|
||||
g_value_set_double (value, private->y1);
|
||||
break;
|
||||
|
||||
case PROP_X2:
|
||||
g_value_set_double (value, private->x2);
|
||||
break;
|
||||
|
||||
case PROP_Y2:
|
||||
g_value_set_double (value, private->y2);
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
g_value_set_double (value, private->opacity);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_canvas_transform_preview_transform (PikaCanvasItem *item,
|
||||
cairo_rectangle_int_t *extents)
|
||||
{
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (item);
|
||||
gint x1, y1;
|
||||
gint x2, y2;
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
|
||||
if (! pika_transform_resize_boundary (&private->transform,
|
||||
private->clip,
|
||||
private->x1, private->y1,
|
||||
private->x2, private->y2,
|
||||
&x1, &y1,
|
||||
&x2, &y2))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pika_canvas_item_transform_xy_f (item, x1, y1, &tx1, &ty1);
|
||||
pika_canvas_item_transform_xy_f (item, x2, y2, &tx2, &ty2);
|
||||
|
||||
extents->x = (gint) floor (tx1);
|
||||
extents->y = (gint) floor (ty1);
|
||||
extents->width = (gint) ceil (tx2) - extents->x;
|
||||
extents->height = (gint) ceil (ty2) - extents->y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_draw (PikaCanvasItem *item,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvasTransformPreview *transform_preview = PIKA_CANVAS_TRANSFORM_PREVIEW (item);
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (item);
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
cairo_rectangle_int_t extents;
|
||||
gdouble clip_x1, clip_y1;
|
||||
gdouble clip_x2, clip_y2;
|
||||
GeglRectangle bounds;
|
||||
cairo_surface_t *surface;
|
||||
guchar *surface_data;
|
||||
gint surface_stride;
|
||||
|
||||
if (! pika_canvas_transform_preview_transform (item, &extents))
|
||||
return;
|
||||
|
||||
cairo_clip_extents (cr, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
|
||||
|
||||
clip_x1 = floor (clip_x1);
|
||||
clip_y1 = floor (clip_y1);
|
||||
clip_x2 = ceil (clip_x2);
|
||||
clip_y2 = ceil (clip_y2);
|
||||
|
||||
if (! gegl_rectangle_intersect (&bounds,
|
||||
GEGL_RECTANGLE (extents.x,
|
||||
extents.y,
|
||||
extents.width,
|
||||
extents.height),
|
||||
GEGL_RECTANGLE (clip_x1,
|
||||
clip_y1,
|
||||
clip_x2 - clip_x1,
|
||||
clip_y2 - clip_y1)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
bounds.width, bounds.height);
|
||||
|
||||
g_return_if_fail (surface != NULL);
|
||||
|
||||
surface_data = cairo_image_surface_get_data (surface);
|
||||
surface_stride = cairo_image_surface_get_stride (surface);
|
||||
|
||||
pika_canvas_transform_preview_sync_node (transform_preview);
|
||||
|
||||
gegl_node_blit (private->node_output, 1.0,
|
||||
GEGL_RECTANGLE (bounds.x + shell->offset_x,
|
||||
bounds.y + shell->offset_y,
|
||||
bounds.width,
|
||||
bounds.height),
|
||||
babl_format ("cairo-ARGB32"), surface_data, surface_stride,
|
||||
GEGL_BLIT_CACHE);
|
||||
|
||||
cairo_surface_mark_dirty (surface);
|
||||
|
||||
cairo_set_source_surface (cr, surface, bounds.x, bounds.y);
|
||||
cairo_rectangle (cr, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
pika_canvas_transform_preview_get_extents (PikaCanvasItem *item)
|
||||
{
|
||||
cairo_rectangle_int_t rectangle;
|
||||
|
||||
if (pika_canvas_transform_preview_transform (item, &rectangle))
|
||||
return cairo_region_create_rectangle (&rectangle);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_layer_changed (PikaLayer *layer,
|
||||
PikaCanvasTransformPreview *transform_preview)
|
||||
{
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (transform_preview);
|
||||
|
||||
pika_canvas_item_begin_change (item);
|
||||
pika_canvas_item_end_change (item);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_set_pickable (PikaCanvasTransformPreview *transform_preview,
|
||||
PikaPickable *pickable)
|
||||
{
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (transform_preview);
|
||||
|
||||
if (private->pickable && PIKA_IS_LAYER (private->pickable))
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
private->pickable,
|
||||
pika_canvas_transform_preview_layer_changed,
|
||||
transform_preview);
|
||||
}
|
||||
|
||||
g_set_object (&private->pickable, pickable);
|
||||
|
||||
if (pickable && PIKA_IS_LAYER (pickable))
|
||||
{
|
||||
g_signal_connect (pickable, "opacity-changed",
|
||||
G_CALLBACK (pika_canvas_transform_preview_layer_changed),
|
||||
transform_preview);
|
||||
g_signal_connect (pickable, "mask-changed",
|
||||
G_CALLBACK (pika_canvas_transform_preview_layer_changed),
|
||||
transform_preview);
|
||||
g_signal_connect (pickable, "apply-mask-changed",
|
||||
G_CALLBACK (pika_canvas_transform_preview_layer_changed),
|
||||
transform_preview);
|
||||
g_signal_connect (pickable, "show-mask-changed",
|
||||
G_CALLBACK (pika_canvas_transform_preview_layer_changed),
|
||||
transform_preview);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_canvas_transform_preview_sync_node (PikaCanvasTransformPreview *transform_preview)
|
||||
{
|
||||
PikaCanvasTransformPreviewPrivate *private = GET_PRIVATE (transform_preview);
|
||||
PikaCanvasItem *item = PIKA_CANVAS_ITEM (transform_preview);
|
||||
PikaDisplayShell *shell = pika_canvas_item_get_shell (item);
|
||||
PikaImage *image = pika_canvas_item_get_image (item);
|
||||
PikaPickable *pickable = private->pickable;
|
||||
PikaDrawable *layer_mask = NULL;
|
||||
PikaDrawable *mask = NULL;
|
||||
gdouble opacity = private->opacity;
|
||||
gint offset_x = 0;
|
||||
gint offset_y = 0;
|
||||
PikaMatrix3 matrix;
|
||||
|
||||
if (! private->node)
|
||||
{
|
||||
private->node = gegl_node_new ();
|
||||
|
||||
private->source_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "pika:buffer-source-validate",
|
||||
NULL);
|
||||
|
||||
private->convert_format_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:convert-format",
|
||||
NULL);
|
||||
|
||||
private->layer_mask_source_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "pika:buffer-source-validate",
|
||||
NULL);
|
||||
|
||||
private->layer_mask_opacity_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:opacity",
|
||||
NULL);
|
||||
|
||||
private->mask_source_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "pika:buffer-source-validate",
|
||||
NULL);
|
||||
|
||||
private->mask_translate_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:translate",
|
||||
NULL);
|
||||
|
||||
private->mask_crop_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:crop",
|
||||
"width", 0.0,
|
||||
"height", 0.0,
|
||||
NULL);
|
||||
|
||||
private->opacity_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:opacity",
|
||||
NULL);
|
||||
|
||||
private->cache_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:cache",
|
||||
NULL);
|
||||
|
||||
private->transform_node =
|
||||
gegl_node_new_child (private->node,
|
||||
"operation", "gegl:transform",
|
||||
"near-z", PIKA_TRANSFORM_NEAR_Z,
|
||||
"sampler", PIKA_INTERPOLATION_NONE,
|
||||
NULL);
|
||||
|
||||
gegl_node_link_many (private->source_node,
|
||||
private->convert_format_node,
|
||||
private->transform_node,
|
||||
NULL);
|
||||
|
||||
gegl_node_connect (private->layer_mask_source_node, "output",
|
||||
private->layer_mask_opacity_node, "aux");
|
||||
|
||||
gegl_node_link_many (private->mask_source_node,
|
||||
private->mask_translate_node,
|
||||
private->mask_crop_node,
|
||||
NULL);
|
||||
|
||||
private->node_pickable = NULL;
|
||||
private->node_layer_mask = NULL;
|
||||
private->node_mask = NULL;
|
||||
private->node_rect = *GEGL_RECTANGLE (0, 0, 0, 0);
|
||||
private->node_opacity = 1.0;
|
||||
pika_matrix3_identity (&private->node_matrix);
|
||||
private->node_output = private->transform_node;
|
||||
}
|
||||
|
||||
if (PIKA_IS_ITEM (pickable))
|
||||
{
|
||||
pika_item_get_offset (PIKA_ITEM (private->pickable),
|
||||
&offset_x, &offset_y);
|
||||
|
||||
if (pika_item_mask_bounds (PIKA_ITEM (pickable),
|
||||
NULL, NULL, NULL, NULL))
|
||||
{
|
||||
mask = PIKA_DRAWABLE (pika_image_get_mask (image));
|
||||
}
|
||||
|
||||
if (PIKA_IS_LAYER (pickable))
|
||||
{
|
||||
PikaLayer *layer = PIKA_LAYER (pickable);
|
||||
|
||||
opacity *= pika_layer_get_opacity (layer);
|
||||
|
||||
layer_mask = PIKA_DRAWABLE (pika_layer_get_mask (layer));
|
||||
|
||||
if (layer_mask)
|
||||
{
|
||||
if (pika_layer_get_show_mask (layer) && ! mask)
|
||||
{
|
||||
pickable = PIKA_PICKABLE (layer_mask);
|
||||
layer_mask = NULL;
|
||||
}
|
||||
else if (! pika_layer_get_apply_mask (layer))
|
||||
{
|
||||
layer_mask = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pika_matrix3_identity (&matrix);
|
||||
pika_matrix3_translate (&matrix, offset_x, offset_y);
|
||||
pika_matrix3_mult (&private->transform, &matrix);
|
||||
pika_matrix3_scale (&matrix, shell->scale_x, shell->scale_y);
|
||||
|
||||
if (pickable != private->node_pickable)
|
||||
{
|
||||
GeglBuffer *buffer;
|
||||
|
||||
pika_pickable_flush (pickable);
|
||||
|
||||
buffer = pika_pickable_get_buffer (pickable);
|
||||
|
||||
if (pika_tile_handler_validate_get_assigned (buffer))
|
||||
buffer = pika_gegl_buffer_dup (buffer);
|
||||
else
|
||||
buffer = g_object_ref (buffer);
|
||||
|
||||
gegl_node_set (private->source_node,
|
||||
"buffer", buffer,
|
||||
NULL);
|
||||
gegl_node_set (private->convert_format_node,
|
||||
"format", pika_pickable_get_format_with_alpha (pickable),
|
||||
NULL);
|
||||
|
||||
g_object_unref (buffer);
|
||||
}
|
||||
|
||||
if (layer_mask != private->node_layer_mask)
|
||||
{
|
||||
gegl_node_set (private->layer_mask_source_node,
|
||||
"buffer", layer_mask ?
|
||||
pika_drawable_get_buffer (layer_mask) :
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
{
|
||||
GeglRectangle rect;
|
||||
|
||||
rect.x = offset_x;
|
||||
rect.y = offset_y;
|
||||
rect.width = pika_item_get_width (PIKA_ITEM (private->pickable));
|
||||
rect.height = pika_item_get_height (PIKA_ITEM (private->pickable));
|
||||
|
||||
if (mask != private->node_mask)
|
||||
{
|
||||
gegl_node_set (private->mask_source_node,
|
||||
"buffer", pika_drawable_get_buffer (mask),
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (! gegl_rectangle_equal (&rect, &private->node_rect))
|
||||
{
|
||||
private->node_rect = rect;
|
||||
|
||||
gegl_node_set (private->mask_translate_node,
|
||||
"x", (gdouble) -rect.x,
|
||||
"y", (gdouble) -rect.y,
|
||||
NULL);
|
||||
|
||||
gegl_node_set (private->mask_crop_node,
|
||||
"width", (gdouble) rect.width,
|
||||
"height", (gdouble) rect.height,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (! private->node_mask)
|
||||
{
|
||||
gegl_node_connect (private->mask_crop_node, "output",
|
||||
private->opacity_node, "aux");
|
||||
}
|
||||
}
|
||||
else if (private->node_mask)
|
||||
{
|
||||
gegl_node_disconnect (private->opacity_node, "aux");
|
||||
}
|
||||
|
||||
if (opacity != private->node_opacity)
|
||||
{
|
||||
gegl_node_set (private->opacity_node,
|
||||
"value", opacity,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (layer_mask != private->node_layer_mask ||
|
||||
mask != private->node_mask ||
|
||||
(opacity != 1.0) != (private->node_opacity != 1.0))
|
||||
{
|
||||
GeglNode *output = private->source_node;
|
||||
|
||||
if (layer_mask && ! mask)
|
||||
{
|
||||
gegl_node_link (output, private->layer_mask_opacity_node);
|
||||
output = private->layer_mask_opacity_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
gegl_node_disconnect (private->layer_mask_opacity_node, "input");
|
||||
}
|
||||
|
||||
if (mask || (opacity != 1.0))
|
||||
{
|
||||
gegl_node_link (output, private->opacity_node);
|
||||
output = private->opacity_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
gegl_node_disconnect (private->opacity_node, "input");
|
||||
}
|
||||
|
||||
if (output == private->source_node)
|
||||
{
|
||||
gegl_node_disconnect (private->cache_node, "input");
|
||||
|
||||
gegl_node_link (output, private->convert_format_node);
|
||||
output = private->convert_format_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
gegl_node_disconnect (private->convert_format_node, "input");
|
||||
|
||||
gegl_node_link (output, private->cache_node);
|
||||
output = private->cache_node;
|
||||
}
|
||||
|
||||
gegl_node_link (output, private->transform_node);
|
||||
output = private->transform_node;
|
||||
|
||||
if (layer_mask && mask)
|
||||
{
|
||||
gegl_node_link (output, private->layer_mask_opacity_node);
|
||||
output = private->layer_mask_opacity_node;
|
||||
}
|
||||
|
||||
private->node_output = output;
|
||||
}
|
||||
|
||||
if (memcmp (&matrix, &private->node_matrix, sizeof (matrix)))
|
||||
{
|
||||
private->node_matrix = matrix;
|
||||
|
||||
pika_gegl_node_set_matrix (private->transform_node, &matrix);
|
||||
}
|
||||
|
||||
private->node_pickable = pickable;
|
||||
private->node_layer_mask = layer_mask;
|
||||
private->node_mask = mask;
|
||||
private->node_opacity = opacity;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
PikaCanvasItem *
|
||||
pika_canvas_transform_preview_new (PikaDisplayShell *shell,
|
||||
PikaPickable *pickable,
|
||||
const PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_PICKABLE (pickable), NULL);
|
||||
g_return_val_if_fail (transform != NULL, NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW,
|
||||
"shell", shell,
|
||||
"pickable", pickable,
|
||||
"transform", transform,
|
||||
"x1", x1,
|
||||
"y1", y1,
|
||||
"x2", x2,
|
||||
"y2", y2,
|
||||
NULL);
|
||||
}
|
||||
65
app/display/pikacanvastransformpreview.h
Normal file
65
app/display/pikacanvastransformpreview.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacanvastransformpreview.h
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CANVAS_TRANSFORM_PREVIEW_H__
|
||||
#define __PIKA_CANVAS_TRANSFORM_PREVIEW_H__
|
||||
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW (pika_canvas_transform_preview_get_type ())
|
||||
#define PIKA_CANVAS_TRANSFORM_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW, PikaCanvasTransformPreview))
|
||||
#define PIKA_CANVAS_TRANSFORM_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW, PikaCanvasTransformPreviewClass))
|
||||
#define PIKA_IS_CANVAS_TRANSFORM_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW))
|
||||
#define PIKA_IS_CANVAS_TRANSFORM_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW))
|
||||
#define PIKA_CANVAS_TRANSFORM_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CANVAS_TRANSFORM_PREVIEW, PikaCanvasTransformPreviewClass))
|
||||
|
||||
|
||||
typedef struct _PikaCanvasTransformPreview PikaCanvasTransformPreview;
|
||||
typedef struct _PikaCanvasTransformPreviewClass PikaCanvasTransformPreviewClass;
|
||||
|
||||
struct _PikaCanvasTransformPreview
|
||||
{
|
||||
PikaCanvasItem parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaCanvasTransformPreviewClass
|
||||
{
|
||||
PikaCanvasItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_canvas_transform_preview_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaCanvasItem * pika_canvas_transform_preview_new (PikaDisplayShell *shell,
|
||||
PikaPickable *pickable,
|
||||
const PikaMatrix3 *transform,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2);
|
||||
|
||||
|
||||
#endif /* __PIKA_CANVAS_TRANSFORM_PREVIEW_H__ */
|
||||
923
app/display/pikacursorview.c
Normal file
923
app/display/pikacursorview.c
Normal file
@ -0,0 +1,923 @@
|
||||
/* 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
|
||||
*
|
||||
* pikacursorview.c
|
||||
* Copyright (C) 2005-2016 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "config/pikacoreconfig.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimage-pick-color.h"
|
||||
#include "core/pikaitem.h"
|
||||
|
||||
#include "widgets/pikacolorframe.h"
|
||||
#include "widgets/pikadocked.h"
|
||||
#include "widgets/pikamenufactory.h"
|
||||
#include "widgets/pikasessioninfo-aux.h"
|
||||
|
||||
#include "pikacursorview.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PIKA,
|
||||
PROP_SAMPLE_MERGED
|
||||
};
|
||||
|
||||
|
||||
struct _PikaCursorViewPrivate
|
||||
{
|
||||
PikaEditor parent_instance;
|
||||
|
||||
Pika *pika;
|
||||
|
||||
GtkWidget *coord_hbox;
|
||||
GtkWidget *selection_hbox;
|
||||
GtkWidget *color_hbox;
|
||||
|
||||
GtkWidget *pixel_x_label;
|
||||
GtkWidget *pixel_y_label;
|
||||
GtkWidget *unit_x_label;
|
||||
GtkWidget *unit_y_label;
|
||||
GtkWidget *selection_x_label;
|
||||
GtkWidget *selection_y_label;
|
||||
GtkWidget *selection_width_label;
|
||||
GtkWidget *selection_height_label;
|
||||
GtkWidget *color_frame_1;
|
||||
GtkWidget *color_frame_2;
|
||||
|
||||
gboolean sample_merged;
|
||||
|
||||
PikaContext *context;
|
||||
PikaDisplayShell *shell;
|
||||
PikaImage *image;
|
||||
|
||||
PikaUnit unit;
|
||||
guint cursor_idle_id;
|
||||
PikaImage *cursor_image;
|
||||
PikaUnit cursor_unit;
|
||||
gdouble cursor_x;
|
||||
gdouble cursor_y;
|
||||
};
|
||||
|
||||
|
||||
static void pika_cursor_view_docked_iface_init (PikaDockedInterface *iface);
|
||||
|
||||
static void pika_cursor_view_dispose (GObject *object);
|
||||
static void pika_cursor_view_constructed (GObject *object);
|
||||
static void pika_cursor_view_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_cursor_view_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_cursor_view_style_updated (GtkWidget *widget);
|
||||
|
||||
static void pika_cursor_view_set_aux_info (PikaDocked *docked,
|
||||
GList *aux_info);
|
||||
static GList * pika_cursor_view_get_aux_info (PikaDocked *docked);
|
||||
|
||||
static void pika_cursor_view_set_context (PikaDocked *docked,
|
||||
PikaContext *context);
|
||||
static void pika_cursor_view_image_changed (PikaCursorView *view,
|
||||
PikaImage *image,
|
||||
PikaContext *context);
|
||||
static void pika_cursor_view_mask_changed (PikaCursorView *view,
|
||||
PikaImage *image);
|
||||
static void pika_cursor_view_diplay_changed (PikaCursorView *view,
|
||||
PikaDisplay *display,
|
||||
PikaContext *context);
|
||||
static void pika_cursor_view_shell_unit_changed (PikaCursorView *view,
|
||||
GParamSpec *pspec,
|
||||
PikaDisplayShell *shell);
|
||||
static void pika_cursor_view_format_as_unit (PikaUnit unit,
|
||||
gchar *output_buf,
|
||||
gint output_buf_size,
|
||||
gdouble pixel_value,
|
||||
gdouble image_res);
|
||||
static void pika_cursor_view_set_label_italic (GtkWidget *label,
|
||||
gboolean italic);
|
||||
static void pika_cursor_view_update_selection_info (PikaCursorView *view,
|
||||
PikaImage *image,
|
||||
PikaUnit unit);
|
||||
static gboolean pika_cursor_view_cursor_idle (PikaCursorView *view);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaCursorView, pika_cursor_view, PIKA_TYPE_EDITOR,
|
||||
G_ADD_PRIVATE (PikaCursorView)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_DOCKED,
|
||||
pika_cursor_view_docked_iface_init))
|
||||
|
||||
#define parent_class pika_cursor_view_parent_class
|
||||
|
||||
static PikaDockedInterface *parent_docked_iface = NULL;
|
||||
|
||||
|
||||
static void
|
||||
pika_cursor_view_class_init (PikaCursorViewClass* klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_cursor_view_constructed;
|
||||
object_class->dispose = pika_cursor_view_dispose;
|
||||
object_class->get_property = pika_cursor_view_get_property;
|
||||
object_class->set_property = pika_cursor_view_set_property;
|
||||
|
||||
widget_class->style_updated = pika_cursor_view_style_updated;
|
||||
|
||||
g_object_class_install_property (object_class, 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, PROP_SAMPLE_MERGED,
|
||||
g_param_spec_boolean ("sample-merged",
|
||||
NULL, NULL,
|
||||
TRUE,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_init (PikaCursorView *view)
|
||||
{
|
||||
GtkWidget *frame;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *toggle;
|
||||
gint content_spacing;
|
||||
|
||||
view->priv = pika_cursor_view_get_instance_private (view);
|
||||
|
||||
view->priv->sample_merged = TRUE;
|
||||
view->priv->context = NULL;
|
||||
view->priv->shell = NULL;
|
||||
view->priv->image = NULL;
|
||||
view->priv->unit = PIKA_UNIT_PIXEL;
|
||||
view->priv->cursor_idle_id = 0;
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (view),
|
||||
"content-spacing", &content_spacing,
|
||||
NULL);
|
||||
|
||||
|
||||
/* cursor information */
|
||||
|
||||
view->priv->coord_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
|
||||
content_spacing);
|
||||
gtk_box_set_homogeneous (GTK_BOX (view->priv->coord_hbox), TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (view), view->priv->coord_hbox,
|
||||
FALSE, FALSE, 0);
|
||||
gtk_widget_show (view->priv->coord_hbox);
|
||||
|
||||
view->priv->selection_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
|
||||
content_spacing);
|
||||
gtk_box_set_homogeneous (GTK_BOX (view->priv->selection_hbox), TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (view), view->priv->selection_hbox,
|
||||
FALSE, FALSE, 0);
|
||||
gtk_widget_show (view->priv->selection_hbox);
|
||||
|
||||
|
||||
/* Pixels */
|
||||
|
||||
frame = pika_frame_new (_("Pixels"));
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->coord_hbox), frame, TRUE, TRUE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
view->priv->pixel_x_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->pixel_x_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 0,
|
||||
_("X"), 0.5, 0.5,
|
||||
view->priv->pixel_x_label, 1);
|
||||
|
||||
view->priv->pixel_y_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->pixel_y_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 1,
|
||||
_("Y"), 0.5, 0.5,
|
||||
view->priv->pixel_y_label, 1);
|
||||
|
||||
|
||||
/* Units */
|
||||
|
||||
frame = pika_frame_new (_("Units"));
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->coord_hbox), frame, TRUE, TRUE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
view->priv->unit_x_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->unit_x_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 0,
|
||||
_("X"), 0.5, 0.5,
|
||||
view->priv->unit_x_label, 1);
|
||||
|
||||
view->priv->unit_y_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->unit_y_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 1,
|
||||
_("Y"), 0.5, 0.5,
|
||||
view->priv->unit_y_label, 1);
|
||||
|
||||
|
||||
/* Selection Bounding Box */
|
||||
|
||||
frame = pika_frame_new (_("Selection"));
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->selection_hbox), frame, TRUE, TRUE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
pika_help_set_help_data (frame, _("The selection's bounding box"), NULL);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
view->priv->selection_x_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->selection_x_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 0,
|
||||
_("X"), 0.5, 0.5,
|
||||
view->priv->selection_x_label, 1);
|
||||
|
||||
view->priv->selection_y_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->selection_y_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 1,
|
||||
_("Y"), 0.5, 0.5,
|
||||
view->priv->selection_y_label, 1);
|
||||
|
||||
frame = pika_frame_new ("");
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->selection_hbox), frame, TRUE, TRUE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
view->priv->selection_width_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->selection_width_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 0,
|
||||
/* Width */
|
||||
_("W"), 0.5, 0.5,
|
||||
view->priv->selection_width_label, 1);
|
||||
|
||||
view->priv->selection_height_label = gtk_label_new (_("n/a"));
|
||||
gtk_label_set_xalign (GTK_LABEL (view->priv->selection_height_label), 1.0);
|
||||
pika_grid_attach_aligned (GTK_GRID (grid), 0, 1,
|
||||
/* Height */
|
||||
_("H"), 0.5, 0.5,
|
||||
view->priv->selection_height_label, 1);
|
||||
|
||||
/* sample merged toggle */
|
||||
|
||||
toggle = pika_prop_check_button_new (G_OBJECT (view), "sample-merged",
|
||||
_("_Sample Merged"));
|
||||
gtk_box_pack_start (GTK_BOX (view), toggle, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_docked_iface_init (PikaDockedInterface *iface)
|
||||
{
|
||||
parent_docked_iface = g_type_interface_peek_parent (iface);
|
||||
|
||||
if (! parent_docked_iface)
|
||||
parent_docked_iface = g_type_default_interface_peek (PIKA_TYPE_DOCKED);
|
||||
|
||||
iface->set_aux_info = pika_cursor_view_set_aux_info;
|
||||
iface->get_aux_info = pika_cursor_view_get_aux_info;
|
||||
iface->set_context = pika_cursor_view_set_context;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_constructed (GObject *object)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (object);
|
||||
gint content_spacing;
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (view),
|
||||
"content-spacing", &content_spacing,
|
||||
NULL);
|
||||
|
||||
/* color information */
|
||||
view->priv->color_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
|
||||
content_spacing);
|
||||
gtk_box_set_homogeneous (GTK_BOX (view->priv->color_hbox), TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (view), view->priv->color_hbox, FALSE, FALSE, 0);
|
||||
gtk_widget_show (view->priv->color_hbox);
|
||||
|
||||
view->priv->color_frame_1 = pika_color_frame_new (view->priv->pika);
|
||||
pika_color_frame_set_mode (PIKA_COLOR_FRAME (view->priv->color_frame_1),
|
||||
PIKA_COLOR_PICK_MODE_PIXEL);
|
||||
pika_color_frame_set_ellipsize (PIKA_COLOR_FRAME (view->priv->color_frame_1),
|
||||
PANGO_ELLIPSIZE_END);
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->color_hbox), view->priv->color_frame_1,
|
||||
TRUE, TRUE, 0);
|
||||
gtk_widget_show (view->priv->color_frame_1);
|
||||
|
||||
view->priv->color_frame_2 = pika_color_frame_new (view->priv->pika);
|
||||
pika_color_frame_set_mode (PIKA_COLOR_FRAME (view->priv->color_frame_2),
|
||||
PIKA_COLOR_PICK_MODE_RGB_PERCENT);
|
||||
gtk_box_pack_start (GTK_BOX (view->priv->color_hbox), view->priv->color_frame_2,
|
||||
TRUE, TRUE, 0);
|
||||
gtk_widget_show (view->priv->color_frame_2);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_dispose (GObject *object)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (object);
|
||||
|
||||
if (view->priv->context)
|
||||
pika_docked_set_context (PIKA_DOCKED (view), NULL);
|
||||
|
||||
if (view->priv->cursor_idle_id)
|
||||
{
|
||||
g_source_remove (view->priv->cursor_idle_id);
|
||||
view->priv->cursor_idle_id = 0;
|
||||
}
|
||||
|
||||
view->priv->color_frame_1 = NULL;
|
||||
view->priv->color_frame_2 = NULL;
|
||||
|
||||
g_clear_object (&view->priv->cursor_image);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PIKA:
|
||||
view->priv->pika = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_MERGED:
|
||||
view->priv->sample_merged = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PIKA:
|
||||
g_value_set_object (value, view->priv->pika);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_MERGED:
|
||||
g_value_set_boolean (value, view->priv->sample_merged);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define AUX_INFO_FRAME_1_MODE "frame-1-mode"
|
||||
#define AUX_INFO_FRAME_2_MODE "frame-2-mode"
|
||||
|
||||
static void
|
||||
pika_cursor_view_set_aux_info (PikaDocked *docked,
|
||||
GList *aux_info)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (docked);
|
||||
GList *list;
|
||||
|
||||
parent_docked_iface->set_aux_info (docked, aux_info);
|
||||
|
||||
for (list = aux_info; list; list = g_list_next (list))
|
||||
{
|
||||
PikaSessionInfoAux *aux = list->data;
|
||||
GtkWidget *frame = NULL;
|
||||
|
||||
if (! strcmp (aux->name, AUX_INFO_FRAME_1_MODE))
|
||||
frame = view->priv->color_frame_1;
|
||||
else if (! strcmp (aux->name, AUX_INFO_FRAME_2_MODE))
|
||||
frame = view->priv->color_frame_2;
|
||||
|
||||
if (frame)
|
||||
{
|
||||
GEnumClass *enum_class;
|
||||
GEnumValue *enum_value;
|
||||
|
||||
enum_class = g_type_class_peek (PIKA_TYPE_COLOR_PICK_MODE);
|
||||
enum_value = g_enum_get_value_by_nick (enum_class, aux->value);
|
||||
|
||||
if (enum_value)
|
||||
pika_color_frame_set_mode (PIKA_COLOR_FRAME (frame),
|
||||
enum_value->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GList *
|
||||
pika_cursor_view_get_aux_info (PikaDocked *docked)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (docked);
|
||||
GList *aux_info;
|
||||
const gchar *nick;
|
||||
PikaSessionInfoAux *aux;
|
||||
|
||||
aux_info = parent_docked_iface->get_aux_info (docked);
|
||||
|
||||
if (pika_enum_get_value (PIKA_TYPE_COLOR_PICK_MODE,
|
||||
PIKA_COLOR_FRAME (view->priv->color_frame_1)->pick_mode,
|
||||
NULL, &nick, NULL, NULL))
|
||||
{
|
||||
aux = pika_session_info_aux_new (AUX_INFO_FRAME_1_MODE, nick);
|
||||
aux_info = g_list_append (aux_info, aux);
|
||||
}
|
||||
|
||||
if (pika_enum_get_value (PIKA_TYPE_COLOR_PICK_MODE,
|
||||
PIKA_COLOR_FRAME (view->priv->color_frame_2)->pick_mode,
|
||||
NULL, &nick, NULL, NULL))
|
||||
{
|
||||
aux = pika_session_info_aux_new (AUX_INFO_FRAME_2_MODE, nick);
|
||||
aux_info = g_list_append (aux_info, aux);
|
||||
}
|
||||
|
||||
return aux_info;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_format_as_unit (PikaUnit unit,
|
||||
gchar *output_buf,
|
||||
gint output_buf_size,
|
||||
gdouble pixel_value,
|
||||
gdouble image_res)
|
||||
{
|
||||
gchar format_buf[32];
|
||||
gdouble value;
|
||||
gint unit_digits = 0;
|
||||
const gchar *unit_str = "";
|
||||
|
||||
value = pika_pixels_to_units (pixel_value, unit, image_res);
|
||||
|
||||
if (unit != PIKA_UNIT_PIXEL)
|
||||
{
|
||||
unit_digits = pika_unit_get_scaled_digits (unit, image_res);
|
||||
unit_str = pika_unit_get_abbreviation (unit);
|
||||
}
|
||||
|
||||
g_snprintf (format_buf, sizeof (format_buf),
|
||||
"%%.%df %s", unit_digits, unit_str);
|
||||
|
||||
g_snprintf (output_buf, output_buf_size, format_buf, value);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_set_label_italic (GtkWidget *label,
|
||||
gboolean italic)
|
||||
{
|
||||
PangoStyle attribute = italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
|
||||
|
||||
pika_label_set_attributes (GTK_LABEL (label),
|
||||
PANGO_ATTR_STYLE, attribute,
|
||||
-1);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_style_updated (GtkWidget *widget)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (widget);
|
||||
gint content_spacing;
|
||||
|
||||
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (view),
|
||||
"content-spacing", &content_spacing,
|
||||
NULL);
|
||||
|
||||
gtk_box_set_spacing (GTK_BOX (view->priv->coord_hbox), content_spacing);
|
||||
gtk_box_set_spacing (GTK_BOX (view->priv->selection_hbox), content_spacing);
|
||||
gtk_box_set_spacing (GTK_BOX (view->priv->color_hbox), content_spacing);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_set_context (PikaDocked *docked,
|
||||
PikaContext *context)
|
||||
{
|
||||
PikaCursorView *view = PIKA_CURSOR_VIEW (docked);
|
||||
PikaColorConfig *config = NULL;
|
||||
PikaDisplay *display = NULL;
|
||||
PikaImage *image = NULL;
|
||||
|
||||
if (context == view->priv->context)
|
||||
return;
|
||||
|
||||
if (view->priv->context)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (view->priv->context,
|
||||
pika_cursor_view_diplay_changed,
|
||||
view);
|
||||
g_signal_handlers_disconnect_by_func (view->priv->context,
|
||||
pika_cursor_view_image_changed,
|
||||
view);
|
||||
|
||||
g_object_unref (view->priv->context);
|
||||
}
|
||||
|
||||
view->priv->context = context;
|
||||
|
||||
if (view->priv->context)
|
||||
{
|
||||
g_object_ref (view->priv->context);
|
||||
|
||||
g_signal_connect_swapped (view->priv->context, "display-changed",
|
||||
G_CALLBACK (pika_cursor_view_diplay_changed),
|
||||
view);
|
||||
|
||||
g_signal_connect_swapped (view->priv->context, "image-changed",
|
||||
G_CALLBACK (pika_cursor_view_image_changed),
|
||||
view);
|
||||
|
||||
config = context->pika->config->color_management;
|
||||
display = pika_context_get_display (context);
|
||||
image = pika_context_get_image (context);
|
||||
}
|
||||
|
||||
pika_color_frame_set_color_config (PIKA_COLOR_FRAME (view->priv->color_frame_1),
|
||||
config);
|
||||
pika_color_frame_set_color_config (PIKA_COLOR_FRAME (view->priv->color_frame_2),
|
||||
config);
|
||||
|
||||
pika_cursor_view_diplay_changed (view, display, view->priv->context);
|
||||
pika_cursor_view_image_changed (view, image, view->priv->context);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_image_changed (PikaCursorView *view,
|
||||
PikaImage *image,
|
||||
PikaContext *context)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CURSOR_VIEW (view));
|
||||
|
||||
if (image == view->priv->image)
|
||||
return;
|
||||
|
||||
if (view->priv->image)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (view->priv->image,
|
||||
pika_cursor_view_mask_changed,
|
||||
view);
|
||||
}
|
||||
|
||||
view->priv->image = image;
|
||||
|
||||
if (view->priv->image)
|
||||
{
|
||||
g_signal_connect_swapped (view->priv->image, "mask-changed",
|
||||
G_CALLBACK (pika_cursor_view_mask_changed),
|
||||
view);
|
||||
}
|
||||
|
||||
pika_cursor_view_mask_changed (view, view->priv->image);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_mask_changed (PikaCursorView *view,
|
||||
PikaImage *image)
|
||||
{
|
||||
pika_cursor_view_update_selection_info (view,
|
||||
view->priv->image,
|
||||
view->priv->unit);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_diplay_changed (PikaCursorView *view,
|
||||
PikaDisplay *display,
|
||||
PikaContext *context)
|
||||
{
|
||||
PikaDisplayShell *shell = NULL;
|
||||
|
||||
if (display)
|
||||
shell = pika_display_get_shell (display);
|
||||
|
||||
if (view->priv->shell)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (view->priv->shell,
|
||||
pika_cursor_view_shell_unit_changed,
|
||||
view);
|
||||
}
|
||||
|
||||
view->priv->shell = shell;
|
||||
|
||||
if (view->priv->shell)
|
||||
{
|
||||
g_signal_connect_swapped (view->priv->shell, "notify::unit",
|
||||
G_CALLBACK (pika_cursor_view_shell_unit_changed),
|
||||
view);
|
||||
}
|
||||
|
||||
pika_cursor_view_shell_unit_changed (view,
|
||||
NULL,
|
||||
view->priv->shell);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_shell_unit_changed (PikaCursorView *view,
|
||||
GParamSpec *pspec,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
PikaUnit new_unit = PIKA_UNIT_PIXEL;
|
||||
|
||||
if (shell)
|
||||
{
|
||||
new_unit = pika_display_shell_get_unit (shell);
|
||||
}
|
||||
|
||||
if (view->priv->unit != new_unit)
|
||||
{
|
||||
pika_cursor_view_update_selection_info (view, view->priv->image, new_unit);
|
||||
view->priv->unit = new_unit;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cursor_view_update_selection_info (PikaCursorView *view,
|
||||
PikaImage *image,
|
||||
PikaUnit unit)
|
||||
{
|
||||
gint x, y, width, height;
|
||||
|
||||
if (image &&
|
||||
pika_item_bounds (PIKA_ITEM (pika_image_get_mask (image)),
|
||||
&x, &y, &width, &height))
|
||||
{
|
||||
gdouble xres, yres;
|
||||
gchar buf[32];
|
||||
|
||||
pika_image_get_resolution (image, &xres, &yres);
|
||||
|
||||
pika_cursor_view_format_as_unit (unit, buf, sizeof (buf), x, xres);
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_x_label), buf);
|
||||
|
||||
pika_cursor_view_format_as_unit (unit, buf, sizeof (buf), y, yres);
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_y_label), buf);
|
||||
|
||||
pika_cursor_view_format_as_unit (unit, buf, sizeof (buf), width, xres);
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_width_label), buf);
|
||||
|
||||
pika_cursor_view_format_as_unit (unit, buf, sizeof (buf), height, yres);
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_height_label), buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_x_label),
|
||||
_("n/a"));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_y_label),
|
||||
_("n/a"));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_width_label),
|
||||
_("n/a"));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->selection_height_label),
|
||||
_("n/a"));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_cursor_view_cursor_idle (PikaCursorView *view)
|
||||
{
|
||||
|
||||
if (view->priv->cursor_image)
|
||||
{
|
||||
PikaImage *image = view->priv->cursor_image;
|
||||
PikaUnit unit = view->priv->cursor_unit;
|
||||
gdouble x = view->priv->cursor_x;
|
||||
gdouble y = view->priv->cursor_y;
|
||||
gboolean in_image;
|
||||
gchar buf[32];
|
||||
const Babl *sample_format;
|
||||
gdouble pixel[4];
|
||||
PikaRGB color;
|
||||
gdouble xres;
|
||||
gdouble yres;
|
||||
gint int_x;
|
||||
gint int_y;
|
||||
|
||||
if (unit == PIKA_UNIT_PIXEL)
|
||||
unit = pika_image_get_unit (image);
|
||||
|
||||
pika_image_get_resolution (image, &xres, &yres);
|
||||
|
||||
in_image = (x >= 0.0 && x < pika_image_get_width (image) &&
|
||||
y >= 0.0 && y < pika_image_get_height (image));
|
||||
|
||||
g_snprintf (buf, sizeof (buf), "%d", (gint) floor (x));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->pixel_x_label), buf);
|
||||
pika_cursor_view_set_label_italic (view->priv->pixel_x_label, ! in_image);
|
||||
|
||||
g_snprintf (buf, sizeof (buf), "%d", (gint) floor (y));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->pixel_y_label), buf);
|
||||
pika_cursor_view_set_label_italic (view->priv->pixel_y_label, ! in_image);
|
||||
|
||||
pika_cursor_view_format_as_unit (unit, buf, sizeof (buf), x, xres);
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->unit_x_label), buf);
|
||||
pika_cursor_view_set_label_italic (view->priv->unit_x_label, ! in_image);
|
||||
|
||||
pika_cursor_view_format_as_unit (unit, buf, sizeof (buf), y, yres);
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->unit_y_label), buf);
|
||||
pika_cursor_view_set_label_italic (view->priv->unit_y_label, ! in_image);
|
||||
|
||||
int_x = (gint) floor (x);
|
||||
int_y = (gint) floor (y);
|
||||
|
||||
if (pika_image_pick_color (image, NULL,
|
||||
int_x, int_y,
|
||||
view->priv->shell->show_all,
|
||||
view->priv->sample_merged,
|
||||
FALSE, 0.0,
|
||||
&sample_format, pixel, &color))
|
||||
{
|
||||
pika_color_frame_set_color (PIKA_COLOR_FRAME (view->priv->color_frame_1),
|
||||
FALSE, sample_format, pixel, &color,
|
||||
int_x, int_y);
|
||||
pika_color_frame_set_color (PIKA_COLOR_FRAME (view->priv->color_frame_2),
|
||||
FALSE, sample_format, pixel, &color,
|
||||
int_x, int_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_color_frame_set_invalid (PIKA_COLOR_FRAME (view->priv->color_frame_1));
|
||||
pika_color_frame_set_invalid (PIKA_COLOR_FRAME (view->priv->color_frame_2));
|
||||
}
|
||||
|
||||
/* Show the selection info from the image under the cursor if any */
|
||||
pika_cursor_view_update_selection_info (view,
|
||||
image,
|
||||
view->priv->cursor_unit);
|
||||
|
||||
g_clear_object (&view->priv->cursor_image);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->pixel_x_label), _("n/a"));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->pixel_y_label), _("n/a"));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->unit_x_label), _("n/a"));
|
||||
gtk_label_set_text (GTK_LABEL (view->priv->unit_y_label), _("n/a"));
|
||||
|
||||
pika_color_frame_set_invalid (PIKA_COLOR_FRAME (view->priv->color_frame_1));
|
||||
pika_color_frame_set_invalid (PIKA_COLOR_FRAME (view->priv->color_frame_2));
|
||||
|
||||
/* Start showing selection info from the active image again */
|
||||
pika_cursor_view_update_selection_info (view,
|
||||
view->priv->image,
|
||||
view->priv->unit);
|
||||
}
|
||||
|
||||
view->priv->cursor_idle_id = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
GtkWidget *
|
||||
pika_cursor_view_new (Pika *pika,
|
||||
PikaMenuFactory *menu_factory)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_MENU_FACTORY (menu_factory), NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_CURSOR_VIEW,
|
||||
"pika", pika,
|
||||
"menu-factory", menu_factory,
|
||||
"menu-identifier", "<CursorInfo>",
|
||||
"ui-path", "/cursor-info-popup",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_cursor_view_set_sample_merged (PikaCursorView *view,
|
||||
gboolean sample_merged)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CURSOR_VIEW (view));
|
||||
|
||||
sample_merged = sample_merged ? TRUE : FALSE;
|
||||
|
||||
if (view->priv->sample_merged != sample_merged)
|
||||
{
|
||||
view->priv->sample_merged = sample_merged;
|
||||
|
||||
g_object_notify (G_OBJECT (view), "sample-merged");
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_cursor_view_get_sample_merged (PikaCursorView *view)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CURSOR_VIEW (view), FALSE);
|
||||
|
||||
return view->priv->sample_merged;
|
||||
}
|
||||
|
||||
void
|
||||
pika_cursor_view_update_cursor (PikaCursorView *view,
|
||||
PikaImage *image,
|
||||
PikaUnit shell_unit,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CURSOR_VIEW (view));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
|
||||
g_clear_object (&view->priv->cursor_image);
|
||||
|
||||
view->priv->cursor_image = g_object_ref (image);
|
||||
view->priv->cursor_unit = shell_unit;
|
||||
view->priv->cursor_x = x;
|
||||
view->priv->cursor_y = y;
|
||||
|
||||
if (view->priv->cursor_idle_id == 0)
|
||||
{
|
||||
view->priv->cursor_idle_id =
|
||||
g_idle_add ((GSourceFunc) pika_cursor_view_cursor_idle, view);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_cursor_view_clear_cursor (PikaCursorView *view)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CURSOR_VIEW (view));
|
||||
|
||||
g_clear_object (&view->priv->cursor_image);
|
||||
|
||||
if (view->priv->cursor_idle_id == 0)
|
||||
{
|
||||
view->priv->cursor_idle_id =
|
||||
g_idle_add ((GSourceFunc) pika_cursor_view_cursor_idle, view);
|
||||
}
|
||||
}
|
||||
73
app/display/pikacursorview.h
Normal file
73
app/display/pikacursorview.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacursorview.h
|
||||
* Copyright (C) 2005-2016 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CURSOR_VIEW_H__
|
||||
#define __PIKA_CURSOR_VIEW_H__
|
||||
|
||||
|
||||
#include "widgets/pikaeditor.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CURSOR_VIEW (pika_cursor_view_get_type ())
|
||||
#define PIKA_CURSOR_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CURSOR_VIEW, PikaCursorView))
|
||||
#define PIKA_CURSOR_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CURSOR_VIEW, PikaCursorViewClass))
|
||||
#define PIKA_IS_CURSOR_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CURSOR_VIEW))
|
||||
#define PIKA_IS_CURSOR_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CURSOR_VIEW))
|
||||
#define PIKA_CURSOR_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CURSOR_VIEW, PikaCursorViewClass))
|
||||
|
||||
|
||||
typedef struct _PikaCursorViewClass PikaCursorViewClass;
|
||||
typedef struct _PikaCursorViewPrivate PikaCursorViewPrivate;
|
||||
|
||||
struct _PikaCursorView
|
||||
{
|
||||
PikaEditor parent_instance;
|
||||
|
||||
PikaCursorViewPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PikaCursorViewClass
|
||||
{
|
||||
PikaEditorClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_cursor_view_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * pika_cursor_view_new (Pika *pika,
|
||||
PikaMenuFactory *menu_factory);
|
||||
|
||||
void pika_cursor_view_set_sample_merged (PikaCursorView *view,
|
||||
gboolean sample_merged);
|
||||
gboolean pika_cursor_view_get_sample_merged (PikaCursorView *view);
|
||||
|
||||
void pika_cursor_view_update_cursor (PikaCursorView *view,
|
||||
PikaImage *image,
|
||||
PikaUnit shell_unit,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
void pika_cursor_view_clear_cursor (PikaCursorView *view);
|
||||
|
||||
|
||||
#endif /* __PIKA_CURSOR_VIEW_H__ */
|
||||
312
app/display/pikadisplay-foreach.c
Normal file
312
app/display/pikadisplay-foreach.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikalist.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplay-foreach.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-cursor.h"
|
||||
|
||||
|
||||
gboolean
|
||||
pika_displays_dirty (Pika *pika)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
|
||||
for (list = pika_get_display_iter (pika);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
PikaDisplay *display = list->data;
|
||||
PikaImage *image = pika_display_get_image (display);
|
||||
|
||||
if (image && pika_image_is_dirty (image))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_displays_image_dirty_callback (PikaImage *image,
|
||||
PikaDirtyMask dirty_mask,
|
||||
PikaContainer *container)
|
||||
{
|
||||
if (pika_image_is_dirty (image) &&
|
||||
pika_image_get_display_count (image) > 0 &&
|
||||
! pika_container_have (container, PIKA_OBJECT (image)))
|
||||
pika_container_add (container, PIKA_OBJECT (image));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_displays_dirty_images_disconnect (PikaContainer *dirty_container,
|
||||
PikaContainer *global_container)
|
||||
{
|
||||
GQuark handler;
|
||||
|
||||
handler = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dirty_container),
|
||||
"clean-handler"));
|
||||
pika_container_remove_handler (global_container, handler);
|
||||
|
||||
handler = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dirty_container),
|
||||
"dirty-handler"));
|
||||
pika_container_remove_handler (global_container, handler);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_displays_image_clean_callback (PikaImage *image,
|
||||
PikaDirtyMask dirty_mask,
|
||||
PikaContainer *container)
|
||||
{
|
||||
if (! pika_image_is_dirty (image))
|
||||
pika_container_remove (container, PIKA_OBJECT (image));
|
||||
}
|
||||
|
||||
PikaContainer *
|
||||
pika_displays_get_dirty_images (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (pika_displays_dirty (pika))
|
||||
{
|
||||
PikaContainer *container = pika_list_new_weak (PIKA_TYPE_IMAGE, FALSE);
|
||||
GList *list;
|
||||
GQuark handler;
|
||||
|
||||
handler =
|
||||
pika_container_add_handler (pika->images, "clean",
|
||||
G_CALLBACK (pika_displays_image_dirty_callback),
|
||||
container);
|
||||
g_object_set_data (G_OBJECT (container), "clean-handler",
|
||||
GINT_TO_POINTER (handler));
|
||||
|
||||
handler =
|
||||
pika_container_add_handler (pika->images, "dirty",
|
||||
G_CALLBACK (pika_displays_image_dirty_callback),
|
||||
container);
|
||||
g_object_set_data (G_OBJECT (container), "dirty-handler",
|
||||
GINT_TO_POINTER (handler));
|
||||
|
||||
g_signal_connect_object (container, "disconnect",
|
||||
G_CALLBACK (pika_displays_dirty_images_disconnect),
|
||||
G_OBJECT (pika->images), 0);
|
||||
|
||||
pika_container_add_handler (container, "clean",
|
||||
G_CALLBACK (pika_displays_image_clean_callback),
|
||||
container);
|
||||
pika_container_add_handler (container, "dirty",
|
||||
G_CALLBACK (pika_displays_image_clean_callback),
|
||||
container);
|
||||
|
||||
for (list = pika_get_image_iter (pika);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
PikaImage *image = list->data;
|
||||
|
||||
if (pika_image_is_dirty (image) &&
|
||||
pika_image_get_display_count (image) > 0)
|
||||
pika_container_add (container, PIKA_OBJECT (image));
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_displays_delete:
|
||||
* @pika:
|
||||
*
|
||||
* Calls pika_display_delete() an all displays in the display list.
|
||||
* This closes all displays, including the first one which is usually
|
||||
* kept open.
|
||||
*/
|
||||
void
|
||||
pika_displays_delete (Pika *pika)
|
||||
{
|
||||
/* this removes the PikaDisplay from the list, so do a while loop
|
||||
* "around" the first element to get them all
|
||||
*/
|
||||
while (! pika_container_is_empty (pika->displays))
|
||||
{
|
||||
PikaDisplay *display = pika_get_display_iter (pika)->data;
|
||||
|
||||
pika_display_delete (display);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_displays_close:
|
||||
* @pika:
|
||||
*
|
||||
* Calls pika_display_close() an all displays in the display list. The
|
||||
* first display will remain open without an image.
|
||||
*/
|
||||
void
|
||||
pika_displays_close (Pika *pika)
|
||||
{
|
||||
GList *list;
|
||||
GList *iter;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
list = g_list_copy (pika_get_display_iter (pika));
|
||||
|
||||
for (iter = list; iter; iter = g_list_next (iter))
|
||||
{
|
||||
PikaDisplay *display = iter->data;
|
||||
|
||||
pika_display_close (display);
|
||||
}
|
||||
|
||||
g_list_free (list);
|
||||
}
|
||||
|
||||
void
|
||||
pika_displays_reconnect (Pika *pika,
|
||||
PikaImage *old,
|
||||
PikaImage *new)
|
||||
{
|
||||
GList *contexts = NULL;
|
||||
GList *list;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (old));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (new));
|
||||
|
||||
/* check which contexts refer to old_image */
|
||||
for (list = pika->context_list; list; list = g_list_next (list))
|
||||
{
|
||||
PikaContext *context = list->data;
|
||||
|
||||
if (pika_context_get_image (context) == old)
|
||||
contexts = g_list_prepend (contexts, list->data);
|
||||
}
|
||||
|
||||
/* set the new_image on the remembered contexts (in reverse order,
|
||||
* since older contexts are usually the parents of newer
|
||||
* ones). Also, update the contexts before the displays, or we
|
||||
* might run into menu update functions that would see an
|
||||
* inconsistent state (display = new, context = old), and thus
|
||||
* inadvertently call actions as if the user had selected a menu
|
||||
* item.
|
||||
*/
|
||||
g_list_foreach (contexts, (GFunc) pika_context_set_image, new);
|
||||
g_list_free (contexts);
|
||||
|
||||
for (list = pika_get_display_iter (pika);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
PikaDisplay *display = list->data;
|
||||
|
||||
if (pika_display_get_image (display) == old)
|
||||
pika_display_set_image (display, new);
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
pika_displays_get_num_visible (Pika *pika)
|
||||
{
|
||||
GList *list;
|
||||
gint visible = 0;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), 0);
|
||||
|
||||
for (list = pika_get_display_iter (pika);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
PikaDisplay *display = list->data;
|
||||
PikaDisplayShell *shell = pika_display_get_shell (display);
|
||||
|
||||
if (gtk_widget_is_drawable (GTK_WIDGET (shell)))
|
||||
{
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
|
||||
|
||||
if (GTK_IS_WINDOW (toplevel))
|
||||
{
|
||||
GdkWindow *window = gtk_widget_get_window (toplevel);
|
||||
GdkWindowState state = gdk_window_get_state (window);
|
||||
|
||||
if ((state & (GDK_WINDOW_STATE_WITHDRAWN |
|
||||
GDK_WINDOW_STATE_ICONIFIED)) == 0)
|
||||
{
|
||||
visible++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return visible;
|
||||
}
|
||||
|
||||
void
|
||||
pika_displays_set_busy (Pika *pika)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
for (list = pika_get_display_iter (pika);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
PikaDisplayShell *shell =
|
||||
pika_display_get_shell (PIKA_DISPLAY (list->data));
|
||||
|
||||
pika_display_shell_set_override_cursor (shell, (PikaCursorType) GDK_WATCH);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_displays_unset_busy (Pika *pika)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
for (list = pika_get_display_iter (pika);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
PikaDisplayShell *shell =
|
||||
pika_display_get_shell (PIKA_DISPLAY (list->data));
|
||||
|
||||
pika_display_shell_unset_override_cursor (shell);
|
||||
}
|
||||
}
|
||||
40
app/display/pikadisplay-foreach.h
Normal file
40
app/display/pikadisplay-foreach.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_FOREACH_H__
|
||||
#define __PIKA_DISPLAY_FOREACH_H__
|
||||
|
||||
|
||||
gboolean pika_displays_dirty (Pika *pika);
|
||||
PikaContainer * pika_displays_get_dirty_images (Pika *pika);
|
||||
void pika_displays_delete (Pika *pika);
|
||||
void pika_displays_close (Pika *pika);
|
||||
void pika_displays_reconnect (Pika *pika,
|
||||
PikaImage *old,
|
||||
PikaImage *new);
|
||||
|
||||
gint pika_displays_get_num_visible (Pika *pika);
|
||||
|
||||
void pika_displays_set_busy (Pika *pika);
|
||||
void pika_displays_unset_busy (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_FOREACH_H__ */
|
||||
124
app/display/pikadisplay-handlers.c
Normal file
124
app/display/pikadisplay-handlers.c
Normal file
@ -0,0 +1,124 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplay-handlers.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_update_handler (PikaProjection *projection,
|
||||
gboolean now,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h,
|
||||
PikaDisplay *display);
|
||||
|
||||
static void pika_display_bounds_changed_handler (PikaImage *image,
|
||||
gint old_x,
|
||||
gint old_y,
|
||||
PikaDisplay *display);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_connect (PikaDisplay *display)
|
||||
{
|
||||
PikaImage *image;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
image = pika_display_get_image (display);
|
||||
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
|
||||
g_signal_connect (pika_image_get_projection (image), "update",
|
||||
G_CALLBACK (pika_display_update_handler),
|
||||
display);
|
||||
|
||||
g_signal_connect (image, "bounds-changed",
|
||||
G_CALLBACK (pika_display_bounds_changed_handler),
|
||||
display);
|
||||
g_signal_connect_swapped (image, "flush",
|
||||
G_CALLBACK (pika_display_flush),
|
||||
display);
|
||||
g_signal_connect_swapped (image, "selected-layers-changed",
|
||||
G_CALLBACK (pika_display_flush),
|
||||
display);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_disconnect (PikaDisplay *display)
|
||||
{
|
||||
PikaImage *image;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
image = pika_display_get_image (display);
|
||||
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
|
||||
g_signal_handlers_disconnect_by_func (image,
|
||||
pika_display_flush,
|
||||
display);
|
||||
g_signal_handlers_disconnect_by_func (image,
|
||||
pika_display_bounds_changed_handler,
|
||||
display);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (pika_image_get_projection (image),
|
||||
pika_display_update_handler,
|
||||
display);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_display_update_handler (PikaProjection *projection,
|
||||
gboolean now,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
pika_display_update_area (display, now, x, y, w, h);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_bounds_changed_handler (PikaImage *image,
|
||||
gint old_x,
|
||||
gint old_y,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
pika_display_update_bounding_box (display);
|
||||
}
|
||||
30
app/display/pikadisplay-handlers.h
Normal file
30
app/display/pikadisplay-handlers.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_HANDLERS_H__
|
||||
#define __PIKA_DISPLAY_HANDLERS_H__
|
||||
|
||||
|
||||
void pika_display_connect (PikaDisplay *display);
|
||||
void pika_display_disconnect (PikaDisplay *display);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_HANDLERS_H__ */
|
||||
897
app/display/pikadisplay.c
Normal file
897
app/display/pikadisplay.c
Normal file
@ -0,0 +1,897 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
#include "tools/tools-types.h"
|
||||
|
||||
#include "config/pikaguiconfig.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "widgets/pikadialogfactory.h"
|
||||
|
||||
#include "tools/pikatool.h"
|
||||
#include "tools/tool_manager.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplay-handlers.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-expose.h"
|
||||
#include "pikadisplayshell-handlers.h"
|
||||
#include "pikadisplayshell-render.h"
|
||||
#include "pikadisplayshell-scroll.h"
|
||||
#include "pikadisplayshell-scrollbars.h"
|
||||
#include "pikadisplayshell-title.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
#include "pikaimagewindow.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define PAINT_AREA_CHUNK_WIDTH 32
|
||||
#define PAINT_AREA_CHUNK_HEIGHT 32
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_IMAGE,
|
||||
PROP_SHELL
|
||||
};
|
||||
|
||||
|
||||
struct _PikaDisplayImplPrivate
|
||||
{
|
||||
PikaImage *image; /* pointer to the associated image */
|
||||
gint instance; /* the instance # of this display as
|
||||
* taken from the image at creation */
|
||||
|
||||
GeglRectangle bounding_box;
|
||||
|
||||
GtkWidget *shell;
|
||||
cairo_region_t *update_region;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_progress_iface_init (PikaProgressInterface *iface);
|
||||
|
||||
static void pika_display_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_display_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_display_impl_present (PikaDisplay *display);
|
||||
static gboolean pika_display_impl_grab_focus (PikaDisplay *display);
|
||||
|
||||
static PikaProgress * pika_display_progress_start (PikaProgress *progress,
|
||||
gboolean cancellable,
|
||||
const gchar *message);
|
||||
static void pika_display_progress_end (PikaProgress *progress);
|
||||
static gboolean pika_display_progress_is_active (PikaProgress *progress);
|
||||
static void pika_display_progress_set_text (PikaProgress *progress,
|
||||
const gchar *message);
|
||||
static void pika_display_progress_set_value (PikaProgress *progress,
|
||||
gdouble percentage);
|
||||
static gdouble pika_display_progress_get_value (PikaProgress *progress);
|
||||
static void pika_display_progress_pulse (PikaProgress *progress);
|
||||
static guint32 pika_display_progress_get_window_id (PikaProgress *progress);
|
||||
static gboolean pika_display_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message);
|
||||
static void pika_display_progress_canceled (PikaProgress *progress,
|
||||
PikaDisplay *display);
|
||||
|
||||
static void pika_display_flush_update_region (PikaDisplay *display);
|
||||
static void pika_display_paint_area (PikaDisplay *display,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaDisplayImpl, pika_display_impl, PIKA_TYPE_DISPLAY,
|
||||
G_ADD_PRIVATE (PikaDisplayImpl)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_PROGRESS,
|
||||
pika_display_progress_iface_init))
|
||||
|
||||
#define parent_class pika_display_impl_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_display_impl_class_init (PikaDisplayImplClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaDisplayClass *display_class = PIKA_DISPLAY_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_display_set_property;
|
||||
object_class->get_property = pika_display_get_property;
|
||||
|
||||
display_class->present = pika_display_impl_present;
|
||||
display_class->grab_focus = pika_display_impl_grab_focus;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_IMAGE,
|
||||
g_param_spec_object ("image",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_IMAGE,
|
||||
PIKA_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SHELL,
|
||||
g_param_spec_object ("shell",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_DISPLAY_SHELL,
|
||||
PIKA_PARAM_READABLE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_impl_init (PikaDisplayImpl *display)
|
||||
{
|
||||
display->priv = pika_display_impl_get_instance_private (display);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_progress_iface_init (PikaProgressInterface *iface)
|
||||
{
|
||||
iface->start = pika_display_progress_start;
|
||||
iface->end = pika_display_progress_end;
|
||||
iface->is_active = pika_display_progress_is_active;
|
||||
iface->set_text = pika_display_progress_set_text;
|
||||
iface->set_value = pika_display_progress_set_value;
|
||||
iface->get_value = pika_display_progress_get_value;
|
||||
iface->pulse = pika_display_progress_pulse;
|
||||
iface->get_window_id = pika_display_progress_get_window_id;
|
||||
iface->message = pika_display_progress_message;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_IMAGE:
|
||||
g_value_set_object (value, display->priv->image);
|
||||
break;
|
||||
|
||||
case PROP_SHELL:
|
||||
g_value_set_object (value, display->priv->shell);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_impl_present (PikaDisplay *display)
|
||||
{
|
||||
pika_display_shell_present (pika_display_get_shell (display));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_impl_grab_focus (PikaDisplay *display)
|
||||
{
|
||||
PikaDisplayImpl *display_impl = PIKA_DISPLAY_IMPL (display);
|
||||
|
||||
if (display_impl->priv->shell && pika_display_get_image (display))
|
||||
{
|
||||
PikaImageWindow *image_window;
|
||||
|
||||
image_window = pika_display_shell_get_window (pika_display_get_shell (display));
|
||||
|
||||
pika_display_present (display);
|
||||
gtk_widget_grab_focus (pika_window_get_primary_focus_widget (PIKA_WINDOW (image_window)));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static PikaProgress *
|
||||
pika_display_progress_start (PikaProgress *progress,
|
||||
gboolean cancellable,
|
||||
const gchar *message)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
return pika_progress_start (PIKA_PROGRESS (display->priv->shell),
|
||||
cancellable,
|
||||
"%s", message);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_progress_end (PikaProgress *progress)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
pika_progress_end (PIKA_PROGRESS (display->priv->shell));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_progress_is_active (PikaProgress *progress)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
return pika_progress_is_active (PIKA_PROGRESS (display->priv->shell));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_progress_set_text (PikaProgress *progress,
|
||||
const gchar *message)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
pika_progress_set_text_literal (PIKA_PROGRESS (display->priv->shell),
|
||||
message);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_progress_set_value (PikaProgress *progress,
|
||||
gdouble percentage)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
pika_progress_set_value (PIKA_PROGRESS (display->priv->shell),
|
||||
percentage);
|
||||
}
|
||||
|
||||
static gdouble
|
||||
pika_display_progress_get_value (PikaProgress *progress)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
return pika_progress_get_value (PIKA_PROGRESS (display->priv->shell));
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_progress_pulse (PikaProgress *progress)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
pika_progress_pulse (PIKA_PROGRESS (display->priv->shell));
|
||||
}
|
||||
|
||||
static guint32
|
||||
pika_display_progress_get_window_id (PikaProgress *progress)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
return pika_progress_get_window_id (PIKA_PROGRESS (display->priv->shell));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_progress_message (PikaProgress *progress,
|
||||
Pika *pika,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message)
|
||||
{
|
||||
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
|
||||
|
||||
if (display->priv->shell)
|
||||
return pika_progress_message (PIKA_PROGRESS (display->priv->shell), pika,
|
||||
severity, domain, message);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_progress_canceled (PikaProgress *progress,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
pika_progress_cancel (PIKA_PROGRESS (display));
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaDisplay *
|
||||
pika_display_new (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale,
|
||||
PikaUIManager *popup_manager,
|
||||
PikaDialogFactory *dialog_factory,
|
||||
GdkMonitor *monitor)
|
||||
{
|
||||
PikaDisplay *display;
|
||||
PikaDisplayImplPrivate *private;
|
||||
PikaImageWindow *window = NULL;
|
||||
PikaDisplayShell *shell;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (image == NULL || PIKA_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GDK_IS_MONITOR (monitor), NULL);
|
||||
|
||||
/* If there isn't an interface, never create a display */
|
||||
if (pika->no_interface)
|
||||
return NULL;
|
||||
|
||||
display = g_object_new (PIKA_TYPE_DISPLAY_IMPL,
|
||||
"pika", pika,
|
||||
NULL);
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
/* refs the image */
|
||||
if (image)
|
||||
pika_display_set_image (display, image);
|
||||
|
||||
/* get an image window */
|
||||
if (PIKA_GUI_CONFIG (display->config)->single_window_mode)
|
||||
{
|
||||
PikaDisplay *active_display;
|
||||
|
||||
active_display = pika_context_get_display (pika_get_user_context (pika));
|
||||
|
||||
if (! active_display)
|
||||
{
|
||||
active_display =
|
||||
PIKA_DISPLAY (pika_container_get_first_child (pika->displays));
|
||||
}
|
||||
|
||||
if (active_display)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_display_get_shell (active_display);
|
||||
|
||||
window = pika_display_shell_get_window (shell);
|
||||
}
|
||||
}
|
||||
|
||||
if (! window)
|
||||
{
|
||||
window = pika_image_window_new (pika,
|
||||
private->image,
|
||||
dialog_factory,
|
||||
monitor);
|
||||
}
|
||||
|
||||
/* create the shell for the image */
|
||||
private->shell = pika_display_shell_new (display, unit, scale,
|
||||
popup_manager,
|
||||
monitor);
|
||||
|
||||
shell = pika_display_get_shell (display);
|
||||
|
||||
pika_display_update_bounding_box (display);
|
||||
|
||||
pika_image_window_add_shell (window, shell);
|
||||
pika_display_shell_present (shell);
|
||||
|
||||
/* make sure the docks are visible, in case all other image windows
|
||||
* are iconified, see bug #686544.
|
||||
*/
|
||||
pika_dialog_factory_show_with_display (dialog_factory);
|
||||
|
||||
g_signal_connect (pika_display_shell_get_statusbar (shell), "cancel",
|
||||
G_CALLBACK (pika_display_progress_canceled),
|
||||
display);
|
||||
|
||||
/* add the display to the list */
|
||||
pika_container_add (pika->displays, PIKA_OBJECT (display));
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_display_delete:
|
||||
* @display:
|
||||
*
|
||||
* Closes the display and removes it from the display list. You should
|
||||
* not call this function directly, use pika_display_close() instead.
|
||||
*/
|
||||
void
|
||||
pika_display_delete (PikaDisplay *display)
|
||||
{
|
||||
PikaDisplayImplPrivate *private;
|
||||
PikaTool *active_tool;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
/* remove the display from the list */
|
||||
pika_container_remove (display->pika->displays, PIKA_OBJECT (display));
|
||||
|
||||
/* unrefs the image */
|
||||
pika_display_set_image (display, NULL);
|
||||
|
||||
active_tool = tool_manager_get_active (display->pika);
|
||||
|
||||
if (active_tool && active_tool->focus_display == display)
|
||||
tool_manager_focus_display_active (display->pika, NULL);
|
||||
|
||||
if (private->shell)
|
||||
{
|
||||
PikaDisplayShell *shell = pika_display_get_shell (display);
|
||||
PikaImageWindow *window = pika_display_shell_get_window (shell);
|
||||
|
||||
/* set private->shell to NULL *before* destroying the shell.
|
||||
* all callbacks in pikadisplayshell-callbacks.c will check
|
||||
* this pointer and do nothing if the shell is in destruction.
|
||||
*/
|
||||
private->shell = NULL;
|
||||
|
||||
if (window)
|
||||
{
|
||||
if (pika_image_window_get_n_shells (window) > 1)
|
||||
{
|
||||
g_object_ref (shell);
|
||||
|
||||
pika_image_window_remove_shell (window, shell);
|
||||
gtk_widget_destroy (GTK_WIDGET (shell));
|
||||
|
||||
g_object_unref (shell);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_image_window_destroy (window);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_object_unref (shell);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (display);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_display_close:
|
||||
* @display:
|
||||
*
|
||||
* Closes the display. If this is the last display, it will remain
|
||||
* open, but without an image.
|
||||
*/
|
||||
void
|
||||
pika_display_close (PikaDisplay *display)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
if (pika_container_get_n_children (display->pika->displays) > 1)
|
||||
{
|
||||
pika_display_delete (display);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_display_empty (display);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_display_get_action_name:
|
||||
* @display:
|
||||
*
|
||||
* Returns: The action name for the given display. The action name
|
||||
* depends on the display ID. The result must be freed with g_free().
|
||||
**/
|
||||
gchar *
|
||||
pika_display_get_action_name (PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
|
||||
|
||||
return g_strdup_printf ("windows-display-%04d",
|
||||
pika_display_get_id (display));
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
pika_display_get_image (PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
|
||||
|
||||
return PIKA_DISPLAY_IMPL (display)->priv->image;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_set_image (PikaDisplay *display,
|
||||
PikaImage *image)
|
||||
{
|
||||
PikaDisplayImplPrivate *private;
|
||||
PikaImage *old_image = NULL;
|
||||
PikaDisplayShell *shell;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
g_return_if_fail (image == NULL || PIKA_IS_IMAGE (image));
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
shell = pika_display_get_shell (display);
|
||||
|
||||
if (private->image)
|
||||
{
|
||||
/* stop any active tool */
|
||||
tool_manager_control_active (display->pika, PIKA_TOOL_ACTION_HALT,
|
||||
display);
|
||||
|
||||
pika_display_shell_disconnect (shell);
|
||||
|
||||
pika_display_disconnect (display);
|
||||
|
||||
g_clear_pointer (&private->update_region, cairo_region_destroy);
|
||||
|
||||
pika_image_dec_display_count (private->image);
|
||||
|
||||
/* set private->image before unrefing because there may be code
|
||||
* that listens for image removals and then iterates the
|
||||
* display list to find a valid display.
|
||||
*/
|
||||
old_image = private->image;
|
||||
|
||||
#if 0
|
||||
g_print ("%s: image->ref_count before unrefing: %d\n",
|
||||
G_STRFUNC, G_OBJECT (old_image)->ref_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
private->image = image;
|
||||
|
||||
if (image)
|
||||
{
|
||||
#if 0
|
||||
g_print ("%s: image->ref_count before refing: %d\n",
|
||||
G_STRFUNC, G_OBJECT (image)->ref_count);
|
||||
#endif
|
||||
|
||||
g_object_ref (image);
|
||||
|
||||
private->instance = pika_image_get_instance_count (image);
|
||||
pika_image_inc_instance_count (image);
|
||||
|
||||
pika_image_inc_display_count (image);
|
||||
|
||||
pika_display_connect (display);
|
||||
|
||||
if (shell)
|
||||
pika_display_shell_connect (shell);
|
||||
}
|
||||
|
||||
if (old_image)
|
||||
g_object_unref (old_image);
|
||||
|
||||
pika_display_update_bounding_box (display);
|
||||
|
||||
if (shell)
|
||||
{
|
||||
if (image)
|
||||
{
|
||||
pika_display_shell_reconnect (shell);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_display_shell_title_update (shell);
|
||||
}
|
||||
}
|
||||
|
||||
if (old_image != image)
|
||||
g_object_notify (G_OBJECT (display), "image");
|
||||
}
|
||||
|
||||
gint
|
||||
pika_display_get_instance (PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), 0);
|
||||
|
||||
return PIKA_DISPLAY_IMPL (display)->priv->instance;
|
||||
}
|
||||
|
||||
PikaDisplayShell *
|
||||
pika_display_get_shell (PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
|
||||
|
||||
return PIKA_DISPLAY_SHELL (PIKA_DISPLAY_IMPL (display)->priv->shell);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_empty (PikaDisplay *display)
|
||||
{
|
||||
PikaDisplayImplPrivate *private;
|
||||
GList *iter;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
g_return_if_fail (PIKA_IS_IMAGE (private->image));
|
||||
|
||||
for (iter = display->pika->context_list; iter; iter = g_list_next (iter))
|
||||
{
|
||||
PikaContext *context = iter->data;
|
||||
|
||||
if (pika_context_get_display (context) == display)
|
||||
pika_context_set_image (context, NULL);
|
||||
}
|
||||
|
||||
pika_display_set_image (display, NULL);
|
||||
|
||||
pika_display_shell_empty (pika_display_get_shell (display));
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_fill (PikaDisplay *display,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale)
|
||||
{
|
||||
PikaDisplayImplPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
g_return_if_fail (private->image == NULL);
|
||||
|
||||
pika_display_set_image (display, image);
|
||||
|
||||
pika_display_shell_fill (pika_display_get_shell (display),
|
||||
image, unit, scale);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_update_bounding_box (PikaDisplay *display)
|
||||
{
|
||||
PikaDisplayImplPrivate *private;
|
||||
PikaDisplayShell *shell;
|
||||
GeglRectangle bounding_box = {};
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
shell = pika_display_get_shell (display);
|
||||
|
||||
if (shell)
|
||||
{
|
||||
bounding_box = pika_display_shell_get_bounding_box (shell);
|
||||
|
||||
if (! gegl_rectangle_equal (&bounding_box, &private->bounding_box))
|
||||
{
|
||||
GeglRectangle diff_rects[4];
|
||||
gint n_diff_rects;
|
||||
gint i;
|
||||
|
||||
n_diff_rects = gegl_rectangle_subtract (diff_rects,
|
||||
&private->bounding_box,
|
||||
&bounding_box);
|
||||
|
||||
for (i = 0; i < n_diff_rects; i++)
|
||||
{
|
||||
pika_display_paint_area (display,
|
||||
diff_rects[i].x, diff_rects[i].y,
|
||||
diff_rects[i].width, diff_rects[i].height);
|
||||
}
|
||||
|
||||
private->bounding_box = bounding_box;
|
||||
|
||||
pika_display_shell_scroll_clamp_and_update (shell);
|
||||
pika_display_shell_scrollbars_update (shell);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
private->bounding_box = bounding_box;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_update_area (PikaDisplay *display,
|
||||
gboolean now,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h)
|
||||
{
|
||||
PikaDisplayImplPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
if (now)
|
||||
{
|
||||
pika_display_paint_area (display, x, y, w, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
gint image_width;
|
||||
gint image_height;
|
||||
|
||||
image_width = pika_image_get_width (private->image);
|
||||
image_height = pika_image_get_height (private->image);
|
||||
|
||||
rect.x = CLAMP (x, 0, image_width);
|
||||
rect.y = CLAMP (y, 0, image_height);
|
||||
rect.width = CLAMP (x + w, 0, image_width) - rect.x;
|
||||
rect.height = CLAMP (y + h, 0, image_height) - rect.y;
|
||||
|
||||
if (private->update_region)
|
||||
cairo_region_union_rectangle (private->update_region, &rect);
|
||||
else
|
||||
private->update_region = cairo_region_create_rectangle (&rect);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_flush (PikaDisplay *display)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
/* FIXME: we can end up being called during shell construction if "show all"
|
||||
* is enabled by default, in which case the shell's display pointer is still
|
||||
* NULL
|
||||
*/
|
||||
if (pika_display_get_shell (display))
|
||||
{
|
||||
pika_display_flush_update_region (display);
|
||||
|
||||
pika_display_shell_flush (pika_display_get_shell (display));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_flush_now (PikaDisplay *display)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
pika_display_flush_update_region (display);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_display_flush_update_region (PikaDisplay *display)
|
||||
{
|
||||
PikaDisplayImplPrivate *private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
|
||||
if (private->update_region)
|
||||
{
|
||||
gint n_rects = cairo_region_num_rectangles (private->update_region);
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
cairo_region_get_rectangle (private->update_region,
|
||||
i, &rect);
|
||||
|
||||
pika_display_paint_area (display,
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height);
|
||||
}
|
||||
|
||||
g_clear_pointer (&private->update_region, cairo_region_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_paint_area (PikaDisplay *display,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h)
|
||||
{
|
||||
PikaDisplayImplPrivate *private = PIKA_DISPLAY_IMPL (display)->priv;
|
||||
PikaDisplayShell *shell = pika_display_get_shell (display);
|
||||
GeglRectangle rect;
|
||||
gint x1, y1, x2, y2;
|
||||
gdouble x1_f, y1_f, x2_f, y2_f;
|
||||
|
||||
if (! gegl_rectangle_intersect (&rect,
|
||||
&private->bounding_box,
|
||||
GEGL_RECTANGLE (x, y, w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* display the area */
|
||||
pika_display_shell_transform_bounds (shell,
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.x + rect.width,
|
||||
rect.y + rect.height,
|
||||
&x1_f, &y1_f, &x2_f, &y2_f);
|
||||
|
||||
/* make sure to expose a superset of the transformed sub-pixel expose
|
||||
* area, not a subset. bug #126942. --mitch
|
||||
*
|
||||
* also accommodate for spill introduced by potential box filtering.
|
||||
* (bug #474509). --simon
|
||||
*/
|
||||
x1 = floor (x1_f - 0.5);
|
||||
y1 = floor (y1_f - 0.5);
|
||||
x2 = ceil (x2_f + 0.5);
|
||||
y2 = ceil (y2_f + 0.5);
|
||||
|
||||
/* align transformed area to a coarse grid, to simplify the
|
||||
* invalidated area
|
||||
*/
|
||||
x1 = floor ((gdouble) x1 / PAINT_AREA_CHUNK_WIDTH) * PAINT_AREA_CHUNK_WIDTH;
|
||||
y1 = floor ((gdouble) y1 / PAINT_AREA_CHUNK_HEIGHT) * PAINT_AREA_CHUNK_HEIGHT;
|
||||
x2 = ceil ((gdouble) x2 / PAINT_AREA_CHUNK_WIDTH) * PAINT_AREA_CHUNK_WIDTH;
|
||||
y2 = ceil ((gdouble) y2 / PAINT_AREA_CHUNK_HEIGHT) * PAINT_AREA_CHUNK_HEIGHT;
|
||||
|
||||
pika_display_shell_expose_area (shell, x1, y1, x2 - x1, y2 - y1);
|
||||
|
||||
pika_display_shell_render_invalidate_area (shell, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
98
app/display/pikadisplay.h
Normal file
98
app/display/pikadisplay.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_IMPL_H__
|
||||
#define __PIKA_DISPLAY_IMPL_H__
|
||||
|
||||
|
||||
#include "core/pikadisplay.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_DISPLAY_IMPL (pika_display_impl_get_type ())
|
||||
#define PIKA_DISPLAY_IMPL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_DISPLAY_IMPL, PikaDisplayImpl))
|
||||
#define PIKA_DISPLAY_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_DISPLAY_IMPL, PikaDisplayImplClass))
|
||||
#define PIKA_IS_DISPLAY_IMPL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_DISPLAY_IMPL))
|
||||
#define PIKA_IS_DISPLAY_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_DISPLAY_IMPL))
|
||||
#define PIKA_DISPLAY_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_DISPLAY_IMPL, PikaDisplayImplClass))
|
||||
|
||||
|
||||
typedef struct _PikaDisplayImpl PikaDisplayImpl;
|
||||
typedef struct _PikaDisplayImplClass PikaDisplayImplClass;
|
||||
typedef struct _PikaDisplayImplPrivate PikaDisplayImplPrivate;
|
||||
|
||||
|
||||
struct _PikaDisplayImpl
|
||||
{
|
||||
PikaDisplay parent_instance;
|
||||
|
||||
PikaDisplayImplPrivate *priv;
|
||||
|
||||
};
|
||||
|
||||
struct _PikaDisplayImplClass
|
||||
{
|
||||
PikaDisplayClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_display_impl_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaDisplay * pika_display_new (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale,
|
||||
PikaUIManager *popup_manager,
|
||||
PikaDialogFactory *dialog_factory,
|
||||
GdkMonitor *monitor);
|
||||
void pika_display_delete (PikaDisplay *display);
|
||||
void pika_display_close (PikaDisplay *display);
|
||||
|
||||
gchar * pika_display_get_action_name (PikaDisplay *display);
|
||||
|
||||
PikaImage * pika_display_get_image (PikaDisplay *display);
|
||||
void pika_display_set_image (PikaDisplay *display,
|
||||
PikaImage *image);
|
||||
|
||||
gint pika_display_get_instance (PikaDisplay *display);
|
||||
|
||||
PikaDisplayShell * pika_display_get_shell (PikaDisplay *display);
|
||||
|
||||
void pika_display_empty (PikaDisplay *display);
|
||||
void pika_display_fill (PikaDisplay *display,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale);
|
||||
|
||||
void pika_display_update_bounding_box
|
||||
(PikaDisplay *display);
|
||||
|
||||
void pika_display_update_area (PikaDisplay *display,
|
||||
gboolean now,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h);
|
||||
|
||||
void pika_display_flush (PikaDisplay *display);
|
||||
void pika_display_flush_now (PikaDisplay *display);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_IMPL_H__ */
|
||||
155
app/display/pikadisplayshell-actions.c
Normal file
155
app/display/pikadisplayshell-actions.c
Normal file
@ -0,0 +1,155 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontext.h"
|
||||
|
||||
#include "menus/menus.h"
|
||||
|
||||
#include "widgets/pikaactiongroup.h"
|
||||
#include "widgets/pikauimanager.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-actions.h"
|
||||
#include "pikaimagewindow.h"
|
||||
|
||||
|
||||
void
|
||||
pika_display_shell_set_action_sensitive (PikaDisplayShell *shell,
|
||||
const gchar *action,
|
||||
gboolean sensitive)
|
||||
{
|
||||
PikaImageWindow *window;
|
||||
PikaContext *context;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (action != NULL);
|
||||
|
||||
window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window && pika_image_window_get_active_shell (window) == shell)
|
||||
{
|
||||
PikaUIManager *manager = menus_get_image_manager_singleton (shell->display->pika);
|
||||
PikaActionGroup *action_group;
|
||||
|
||||
action_group = pika_ui_manager_get_action_group (manager, "view");
|
||||
|
||||
if (action_group)
|
||||
pika_action_group_set_action_sensitive (action_group, action, sensitive, NULL);
|
||||
}
|
||||
|
||||
context = pika_get_user_context (shell->display->pika);
|
||||
|
||||
if (shell->display == pika_context_get_display (context))
|
||||
{
|
||||
PikaActionGroup *action_group;
|
||||
|
||||
action_group = pika_ui_manager_get_action_group (shell->popup_manager,
|
||||
"view");
|
||||
|
||||
if (action_group)
|
||||
pika_action_group_set_action_sensitive (action_group, action, sensitive, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_action_active (PikaDisplayShell *shell,
|
||||
const gchar *action,
|
||||
gboolean active)
|
||||
{
|
||||
PikaImageWindow *window;
|
||||
PikaContext *context;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (action != NULL);
|
||||
|
||||
window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window && pika_image_window_get_active_shell (window) == shell)
|
||||
{
|
||||
PikaUIManager *manager = menus_get_image_manager_singleton (shell->display->pika);
|
||||
PikaActionGroup *action_group;
|
||||
|
||||
action_group = pika_ui_manager_get_action_group (manager, "view");
|
||||
|
||||
if (action_group)
|
||||
pika_action_group_set_action_active (action_group, action, active);
|
||||
}
|
||||
|
||||
context = pika_get_user_context (shell->display->pika);
|
||||
|
||||
if (shell->display == pika_context_get_display (context))
|
||||
{
|
||||
PikaActionGroup *action_group;
|
||||
|
||||
action_group = pika_ui_manager_get_action_group (shell->popup_manager,
|
||||
"view");
|
||||
|
||||
if (action_group)
|
||||
pika_action_group_set_action_active (action_group, action, active);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_action_color (PikaDisplayShell *shell,
|
||||
const gchar *action,
|
||||
const PikaRGB *color)
|
||||
{
|
||||
PikaImageWindow *window;
|
||||
PikaContext *context;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (action != NULL);
|
||||
|
||||
window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window && pika_image_window_get_active_shell (window) == shell)
|
||||
{
|
||||
PikaUIManager *manager = menus_get_image_manager_singleton (shell->display->pika);
|
||||
PikaActionGroup *action_group;
|
||||
|
||||
action_group = pika_ui_manager_get_action_group (manager, "view");
|
||||
|
||||
if (action_group)
|
||||
pika_action_group_set_action_color (action_group, action, color, FALSE);
|
||||
}
|
||||
|
||||
context = pika_get_user_context (shell->display->pika);
|
||||
|
||||
if (shell->display == pika_context_get_display (context))
|
||||
{
|
||||
PikaActionGroup *action_group;
|
||||
|
||||
action_group = pika_ui_manager_get_action_group (shell->popup_manager,
|
||||
"view");
|
||||
|
||||
if (action_group)
|
||||
pika_action_group_set_action_color (action_group, action, color, FALSE);
|
||||
}
|
||||
}
|
||||
37
app/display/pikadisplayshell-actions.h
Normal file
37
app/display/pikadisplayshell-actions.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_ACTIONS_H__
|
||||
#define __PIKA_DISPLAY_SHELL_ACTIONS_H__
|
||||
|
||||
|
||||
void pika_display_shell_set_action_sensitive (PikaDisplayShell *shell,
|
||||
const gchar *action,
|
||||
gboolean sensitive);
|
||||
void pika_display_shell_set_action_active (PikaDisplayShell *shell,
|
||||
const gchar *action,
|
||||
gboolean active);
|
||||
void pika_display_shell_set_action_color (PikaDisplayShell *shell,
|
||||
const gchar *action,
|
||||
const PikaRGB *color);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_ACTIONS_H__ */
|
||||
639
app/display/pikadisplayshell-appearance.c
Normal file
639
app/display/pikadisplayshell-appearance.c
Normal file
@ -0,0 +1,639 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "config/pikadisplayoptions.h"
|
||||
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "widgets/pikadockcolumns.h"
|
||||
#include "widgets/pikamenumodel.h"
|
||||
#include "widgets/pikarender.h"
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvasitem.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-actions.h"
|
||||
#include "pikadisplayshell-appearance.h"
|
||||
#include "pikadisplayshell-expose.h"
|
||||
#include "pikadisplayshell-selection.h"
|
||||
#include "pikadisplayshell-scroll.h"
|
||||
#include "pikadisplayshell-scrollbars.h"
|
||||
#include "pikaimagewindow.h"
|
||||
#include "pikastatusbar.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static PikaDisplayOptions * appearance_get_options (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_appearance_update (PikaDisplayShell *shell)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
PikaImageWindow *window;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window)
|
||||
{
|
||||
gboolean fullscreen = pika_image_window_get_fullscreen (window);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-fullscreen",
|
||||
fullscreen);
|
||||
}
|
||||
|
||||
pika_display_shell_set_show_menubar (shell,
|
||||
options->show_menubar);
|
||||
pika_display_shell_set_show_statusbar (shell,
|
||||
options->show_statusbar);
|
||||
|
||||
pika_display_shell_set_show_rulers (shell,
|
||||
options->show_rulers);
|
||||
pika_display_shell_set_show_scrollbars (shell,
|
||||
options->show_scrollbars);
|
||||
pika_display_shell_set_show_selection (shell,
|
||||
options->show_selection);
|
||||
pika_display_shell_set_show_layer (shell,
|
||||
options->show_layer_boundary);
|
||||
pika_display_shell_set_show_canvas (shell,
|
||||
options->show_canvas_boundary);
|
||||
pika_display_shell_set_show_guides (shell,
|
||||
options->show_guides);
|
||||
pika_display_shell_set_show_grid (shell,
|
||||
options->show_grid);
|
||||
pika_display_shell_set_show_sample_points (shell,
|
||||
options->show_sample_points);
|
||||
pika_display_shell_set_padding (shell,
|
||||
options->padding_mode,
|
||||
&options->padding_color);
|
||||
pika_display_shell_set_padding_in_show_all (shell,
|
||||
options->padding_in_show_all);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_menubar (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
PikaImageWindow *window;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
window = pika_display_shell_get_window (shell);
|
||||
|
||||
g_object_set (options, "show-menubar", show, NULL);
|
||||
|
||||
if (window && pika_image_window_get_active_shell (window) == shell)
|
||||
{
|
||||
pika_image_window_keep_canvas_pos (pika_display_shell_get_window (shell));
|
||||
pika_image_window_set_show_menubar (window, show);
|
||||
}
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-menubar", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_menubar (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_menubar;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_statusbar (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-statusbar", show, NULL);
|
||||
|
||||
pika_image_window_keep_canvas_pos (pika_display_shell_get_window (shell));
|
||||
pika_statusbar_set_visible (PIKA_STATUSBAR (shell->statusbar), show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-statusbar", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_statusbar (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_statusbar;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_rulers (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-rulers", show, NULL);
|
||||
|
||||
pika_image_window_keep_canvas_pos (pika_display_shell_get_window (shell));
|
||||
gtk_widget_set_visible (shell->origin, show);
|
||||
gtk_widget_set_visible (shell->hrule, show);
|
||||
gtk_widget_set_visible (shell->vrule, show);
|
||||
gtk_widget_set_visible (shell->quick_mask_button, show);
|
||||
gtk_widget_set_visible (shell->zoom_button, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-rulers", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_rulers (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_rulers;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_scrollbars (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-scrollbars", show, NULL);
|
||||
|
||||
pika_image_window_keep_canvas_pos (pika_display_shell_get_window (shell));
|
||||
gtk_widget_set_visible (shell->nav_ebox, show);
|
||||
gtk_widget_set_visible (shell->hsb, show);
|
||||
gtk_widget_set_visible (shell->vsb, show);
|
||||
gtk_widget_set_visible (shell->quick_mask_button, show);
|
||||
gtk_widget_set_visible (shell->zoom_button, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-scrollbars", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_scrollbars (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_scrollbars;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_selection (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-selection", show, NULL);
|
||||
|
||||
pika_display_shell_selection_set_show (shell, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-selection", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_selection (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_selection;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_layer (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-layer-boundary", show, NULL);
|
||||
|
||||
pika_canvas_item_set_visible (shell->layer_boundary, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-layer-boundary", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_layer (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_layer_boundary;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_canvas (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-canvas-boundary", show, NULL);
|
||||
|
||||
pika_canvas_item_set_visible (shell->canvas_boundary,
|
||||
show && shell->show_all);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-canvas-boundary", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_canvas (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_canvas_boundary;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_update_show_canvas (PikaDisplayShell *shell)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
pika_canvas_item_set_visible (shell->canvas_boundary,
|
||||
options->show_canvas_boundary &&
|
||||
shell->show_all);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_guides (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-guides", show, NULL);
|
||||
|
||||
pika_canvas_item_set_visible (shell->guides, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-guides", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_guides (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_guides;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_grid (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-grid", show, NULL);
|
||||
|
||||
pika_canvas_item_set_visible (shell->grid, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-grid", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_grid (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_grid;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_show_sample_points (PikaDisplayShell *shell,
|
||||
gboolean show)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "show-sample-points", show, NULL);
|
||||
|
||||
pika_canvas_item_set_visible (shell->sample_points, show);
|
||||
|
||||
pika_display_shell_set_action_active (shell, "view-show-sample-points", show);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_show_sample_points (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->show_sample_points;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_snap_to_grid (PikaDisplayShell *shell,
|
||||
gboolean snap)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "snap-to-grid", snap, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_snap_to_grid (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->snap_to_grid;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_snap_to_guides (PikaDisplayShell *shell,
|
||||
gboolean snap)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "snap-to-guides", snap, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_snap_to_guides (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->snap_to_guides;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_snap_to_canvas (PikaDisplayShell *shell,
|
||||
gboolean snap)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "snap-to-canvas", snap, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_snap_to_canvas (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->snap_to_canvas;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_snap_to_vectors (PikaDisplayShell *shell,
|
||||
gboolean snap)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "snap-to-path", snap, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_snap_to_vectors (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->snap_to_path;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_snap_to_bbox (PikaDisplayShell *shell,
|
||||
gboolean snap)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "snap-to-bbox", snap, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_snap_to_bbox (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->snap_to_bbox;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_snap_to_equidistance (PikaDisplayShell *shell,
|
||||
gboolean snap)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
g_object_set (options, "snap-to-equidistance", snap, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_snap_to_equidistance (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->snap_to_equidistance;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_padding (PikaDisplayShell *shell,
|
||||
PikaCanvasPaddingMode padding_mode,
|
||||
const PikaRGB *padding_color)
|
||||
{
|
||||
PikaImageWindow *window;
|
||||
PikaMenuModel *model;
|
||||
PikaDisplayOptions *options;
|
||||
PikaRGB color;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (padding_color != NULL);
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
color = *padding_color;
|
||||
|
||||
switch (padding_mode)
|
||||
{
|
||||
case PIKA_CANVAS_PADDING_MODE_DEFAULT:
|
||||
break;
|
||||
|
||||
case PIKA_CANVAS_PADDING_MODE_LIGHT_CHECK:
|
||||
color = *pika_render_check_color1 ();
|
||||
break;
|
||||
|
||||
case PIKA_CANVAS_PADDING_MODE_DARK_CHECK:
|
||||
color = *pika_render_check_color2 ();
|
||||
break;
|
||||
|
||||
case PIKA_CANVAS_PADDING_MODE_CUSTOM:
|
||||
case PIKA_CANVAS_PADDING_MODE_RESET:
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_set (options,
|
||||
"padding-mode", padding_mode,
|
||||
"padding-color", &color,
|
||||
NULL);
|
||||
|
||||
pika_canvas_set_padding (PIKA_CANVAS (shell->canvas),
|
||||
padding_mode, &color);
|
||||
|
||||
window = pika_display_shell_get_window (shell);
|
||||
model = pika_image_window_get_menubar_model (window);
|
||||
if (padding_mode != PIKA_CANVAS_PADDING_MODE_DEFAULT)
|
||||
pika_menu_model_set_color (model, "/View/Padding color",
|
||||
&options->padding_color);
|
||||
else
|
||||
pika_menu_model_set_color (model, "/View/Padding color",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_get_padding (PikaDisplayShell *shell,
|
||||
PikaCanvasPaddingMode *padding_mode,
|
||||
PikaRGB *padding_color)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
if (padding_mode)
|
||||
*padding_mode = options->padding_mode;
|
||||
|
||||
if (padding_color)
|
||||
*padding_color = options->padding_color;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_padding_in_show_all (PikaDisplayShell *shell,
|
||||
gboolean keep)
|
||||
{
|
||||
PikaDisplayOptions *options;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
options = appearance_get_options (shell);
|
||||
|
||||
if (options->padding_in_show_all != keep)
|
||||
{
|
||||
g_object_set (options, "padding-in-show-all", keep, NULL);
|
||||
|
||||
if (shell->display)
|
||||
{
|
||||
pika_display_shell_scroll_clamp_and_update (shell);
|
||||
pika_display_shell_scrollbars_update (shell);
|
||||
|
||||
pika_display_shell_expose_full (shell);
|
||||
}
|
||||
|
||||
pika_display_shell_set_action_active (shell,
|
||||
"view-padding-color-in-show-all",
|
||||
keep);
|
||||
|
||||
g_object_notify (G_OBJECT (shell), "infinite-canvas");
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_get_padding_in_show_all (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
return appearance_get_options (shell)->padding_in_show_all;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static PikaDisplayOptions *
|
||||
appearance_get_options (PikaDisplayShell *shell)
|
||||
{
|
||||
if (pika_display_get_image (shell->display))
|
||||
{
|
||||
PikaImageWindow *window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window && pika_image_window_get_fullscreen (window))
|
||||
return shell->fullscreen_options;
|
||||
else
|
||||
return shell->options;
|
||||
}
|
||||
|
||||
return shell->no_image_options;
|
||||
}
|
||||
104
app/display/pikadisplayshell-appearance.h
Normal file
104
app/display/pikadisplayshell-appearance.h
Normal file
@ -0,0 +1,104 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_APPEARANCE_H__
|
||||
#define __PIKA_DISPLAY_SHELL_APPEARANCE_H__
|
||||
|
||||
|
||||
void pika_display_shell_appearance_update (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_menubar (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_menubar (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_statusbar (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_statusbar (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_rulers (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_rulers (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_scrollbars (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_scrollbars (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_selection (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_selection (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_layer (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_layer (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_canvas (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_canvas (PikaDisplayShell *shell);
|
||||
void pika_display_shell_update_show_canvas (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_grid (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_grid (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_guides (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_guides (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_snap_to_grid (PikaDisplayShell *shell,
|
||||
gboolean snap);
|
||||
gboolean pika_display_shell_get_snap_to_grid (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_show_sample_points (PikaDisplayShell *shell,
|
||||
gboolean show);
|
||||
gboolean pika_display_shell_get_show_sample_points (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_snap_to_guides (PikaDisplayShell *shell,
|
||||
gboolean snap);
|
||||
gboolean pika_display_shell_get_snap_to_guides (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_snap_to_canvas (PikaDisplayShell *shell,
|
||||
gboolean snap);
|
||||
gboolean pika_display_shell_get_snap_to_canvas (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_snap_to_vectors (PikaDisplayShell *shell,
|
||||
gboolean snap);
|
||||
gboolean pika_display_shell_get_snap_to_vectors (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_snap_to_bbox (PikaDisplayShell *shell,
|
||||
gboolean snap);
|
||||
gboolean pika_display_shell_get_snap_to_bbox (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_snap_to_equidistance (PikaDisplayShell *shell,
|
||||
gboolean snap);
|
||||
gboolean pika_display_shell_get_snap_to_equidistance (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_set_padding (PikaDisplayShell *shell,
|
||||
PikaCanvasPaddingMode mode,
|
||||
const PikaRGB *color);
|
||||
void pika_display_shell_get_padding (PikaDisplayShell *shell,
|
||||
PikaCanvasPaddingMode *mode,
|
||||
PikaRGB *color);
|
||||
void pika_display_shell_set_padding_in_show_all (PikaDisplayShell *shell,
|
||||
gboolean keep);
|
||||
gboolean pika_display_shell_get_padding_in_show_all (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_APPEARANCE_H__ */
|
||||
188
app/display/pikadisplayshell-autoscroll.c
Normal file
188
app/display/pikadisplayshell-autoscroll.c
Normal file
@ -0,0 +1,188 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "widgets/pikadeviceinfo.h"
|
||||
#include "widgets/pikadeviceinfo-coords.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-autoscroll.h"
|
||||
#include "pikadisplayshell-scroll.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
|
||||
#include "tools/tools-types.h"
|
||||
#include "tools/tool_manager.h"
|
||||
#include "tools/pikatool.h"
|
||||
#include "tools/pikatoolcontrol.h"
|
||||
|
||||
|
||||
#define AUTOSCROLL_DT 20
|
||||
#define AUTOSCROLL_DX 0.1
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdkEventMotion *mevent;
|
||||
PikaDeviceInfo *device;
|
||||
guint32 time;
|
||||
GdkModifierType state;
|
||||
guint timeout_id;
|
||||
} ScrollInfo;
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static gboolean pika_display_shell_autoscroll_timeout (gpointer data);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_autoscroll_start (PikaDisplayShell *shell,
|
||||
GdkModifierType state,
|
||||
GdkEventMotion *mevent)
|
||||
{
|
||||
ScrollInfo *info;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (shell->scroll_info)
|
||||
return;
|
||||
|
||||
info = g_slice_new0 (ScrollInfo);
|
||||
|
||||
info->mevent = mevent;
|
||||
info->device = pika_device_info_get_by_device (mevent->device);
|
||||
info->time = gdk_event_get_time ((GdkEvent *) mevent);
|
||||
info->state = state;
|
||||
info->timeout_id = g_timeout_add (AUTOSCROLL_DT,
|
||||
pika_display_shell_autoscroll_timeout,
|
||||
shell);
|
||||
|
||||
shell->scroll_info = info;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_autoscroll_stop (PikaDisplayShell *shell)
|
||||
{
|
||||
ScrollInfo *info;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (! shell->scroll_info)
|
||||
return;
|
||||
|
||||
info = shell->scroll_info;
|
||||
|
||||
if (info->timeout_id)
|
||||
{
|
||||
g_source_remove (info->timeout_id);
|
||||
info->timeout_id = 0;
|
||||
}
|
||||
|
||||
g_slice_free (ScrollInfo, info);
|
||||
shell->scroll_info = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static gboolean
|
||||
pika_display_shell_autoscroll_timeout (gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
ScrollInfo *info = shell->scroll_info;
|
||||
PikaCoords device_coords;
|
||||
PikaCoords image_coords;
|
||||
gint dx = 0;
|
||||
gint dy = 0;
|
||||
|
||||
pika_device_info_get_device_coords (info->device,
|
||||
gtk_widget_get_window (shell->canvas),
|
||||
&device_coords);
|
||||
|
||||
if (device_coords.x < 0)
|
||||
dx = device_coords.x;
|
||||
else if (device_coords.x > shell->disp_width)
|
||||
dx = device_coords.x - shell->disp_width;
|
||||
|
||||
if (device_coords.y < 0)
|
||||
dy = device_coords.y;
|
||||
else if (device_coords.y > shell->disp_height)
|
||||
dy = device_coords.y - shell->disp_height;
|
||||
|
||||
if (dx || dy)
|
||||
{
|
||||
PikaDisplay *display = shell->display;
|
||||
PikaTool *active_tool = tool_manager_get_active (display->pika);
|
||||
gint scroll_amount_x = AUTOSCROLL_DX * dx;
|
||||
gint scroll_amount_y = AUTOSCROLL_DX * dy;
|
||||
|
||||
info->time += AUTOSCROLL_DT;
|
||||
|
||||
pika_display_shell_scroll_unoverscrollify (shell,
|
||||
scroll_amount_x,
|
||||
scroll_amount_y,
|
||||
&scroll_amount_x,
|
||||
&scroll_amount_y);
|
||||
|
||||
pika_display_shell_scroll (shell,
|
||||
scroll_amount_x,
|
||||
scroll_amount_y);
|
||||
|
||||
pika_display_shell_untransform_coords (shell,
|
||||
&device_coords,
|
||||
&image_coords);
|
||||
|
||||
if (pika_tool_control_get_snap_to (active_tool->control))
|
||||
{
|
||||
gint x, y, width, height;
|
||||
|
||||
pika_tool_control_get_snap_offsets (active_tool->control,
|
||||
&x, &y, &width, &height);
|
||||
|
||||
pika_display_shell_snap_coords (shell,
|
||||
&image_coords,
|
||||
x, y, width, height);
|
||||
}
|
||||
|
||||
tool_manager_motion_active (display->pika,
|
||||
&image_coords,
|
||||
info->time, info->state,
|
||||
display);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_slice_free (ScrollInfo, info);
|
||||
shell->scroll_info = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
32
app/display/pikadisplayshell-autoscroll.h
Normal file
32
app/display/pikadisplayshell-autoscroll.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_AUTOSCROLL_H__
|
||||
#define __PIKA_DISPLAY_SHELL_AUTOSCROLL_H__
|
||||
|
||||
|
||||
void pika_display_shell_autoscroll_start (PikaDisplayShell *shell,
|
||||
GdkModifierType state,
|
||||
GdkEventMotion *mevent);
|
||||
void pika_display_shell_autoscroll_stop (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_AUTOSCROLL_H__ */
|
||||
692
app/display/pikadisplayshell-callbacks.c
Normal file
692
app/display/pikadisplayshell-callbacks.c
Normal file
@ -0,0 +1,692 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimage-quick-mask.h"
|
||||
|
||||
#include "menus/menus.h"
|
||||
|
||||
#include "widgets/pikacairo-mascot.h"
|
||||
#include "widgets/pikamenufactory.h"
|
||||
#include "widgets/pikauimanager.h"
|
||||
|
||||
#include "pikacanvasitem.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-appearance.h"
|
||||
#include "pikadisplayshell-callbacks.h"
|
||||
#include "pikadisplayshell-draw.h"
|
||||
#include "pikadisplayshell-render.h"
|
||||
#include "pikadisplayshell-scale.h"
|
||||
#include "pikadisplayshell-scroll.h"
|
||||
#include "pikadisplayshell-scrollbars.h"
|
||||
#include "pikadisplayshell-selection.h"
|
||||
#include "pikadisplayshell-title.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
#include "pikaimagewindow.h"
|
||||
#include "pikanavigationeditor.h"
|
||||
|
||||
#include "git-version.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_shell_vadjustment_changed (GtkAdjustment *adjustment,
|
||||
PikaDisplayShell *shell);
|
||||
static void pika_display_shell_hadjustment_changed (GtkAdjustment *adjustment,
|
||||
PikaDisplayShell *shell);
|
||||
static gboolean pika_display_shell_vscrollbar_change_value (GtkRange *range,
|
||||
GtkScrollType scroll,
|
||||
gdouble value,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
static gboolean pika_display_shell_hscrollbar_change_value (GtkRange *range,
|
||||
GtkScrollType scroll,
|
||||
gdouble value,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
static void pika_display_shell_canvas_draw_image (PikaDisplayShell *shell,
|
||||
cairo_t *cr);
|
||||
static void pika_display_shell_canvas_draw_drop_zone (PikaDisplayShell *shell,
|
||||
cairo_t *cr);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_canvas_realize (GtkWidget *canvas,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
PikaCanvasPaddingMode padding_mode;
|
||||
PikaRGB padding_color;
|
||||
GtkAllocation allocation;
|
||||
|
||||
gtk_widget_grab_focus (canvas);
|
||||
|
||||
pika_display_shell_get_padding (shell, &padding_mode, &padding_color);
|
||||
pika_display_shell_set_padding (shell, padding_mode, &padding_color);
|
||||
|
||||
gtk_widget_get_allocation (canvas, &allocation);
|
||||
|
||||
pika_display_shell_title_update (shell);
|
||||
|
||||
shell->disp_width = allocation.width;
|
||||
shell->disp_height = allocation.height;
|
||||
|
||||
pika_display_shell_render_set_scale (
|
||||
shell,
|
||||
gdk_window_get_scale_factor (
|
||||
gtk_widget_get_window (gtk_widget_get_toplevel (canvas))));
|
||||
|
||||
/* set up the scrollbar observers */
|
||||
g_signal_connect (shell->hsbdata, "value-changed",
|
||||
G_CALLBACK (pika_display_shell_hadjustment_changed),
|
||||
shell);
|
||||
g_signal_connect (shell->vsbdata, "value-changed",
|
||||
G_CALLBACK (pika_display_shell_vadjustment_changed),
|
||||
shell);
|
||||
|
||||
g_signal_connect (shell->hsb, "change-value",
|
||||
G_CALLBACK (pika_display_shell_hscrollbar_change_value),
|
||||
shell);
|
||||
|
||||
g_signal_connect (shell->vsb, "change-value",
|
||||
G_CALLBACK (pika_display_shell_vscrollbar_change_value),
|
||||
shell);
|
||||
|
||||
/* allow shrinking */
|
||||
gtk_widget_set_size_request (GTK_WIDGET (shell), 0, 0);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
gint prev_width;
|
||||
gint prev_height;
|
||||
} TickClosure;
|
||||
|
||||
static gboolean
|
||||
pika_display_shell_canvas_tick (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
TickClosure *tick)
|
||||
{
|
||||
PikaDisplayShell *shell = tick->shell;
|
||||
GtkAllocation allocation;
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
if ((tick->prev_width != allocation.width) ||
|
||||
(tick->prev_height != allocation.height))
|
||||
{
|
||||
if (shell->zoom_on_resize &&
|
||||
tick->prev_width > 64 &&
|
||||
tick->prev_height > 64 &&
|
||||
allocation.width > 64 &&
|
||||
allocation.height > 64)
|
||||
{
|
||||
gdouble scale = pika_zoom_model_get_factor (shell->zoom);
|
||||
gint offset_x;
|
||||
gint offset_y;
|
||||
|
||||
/* FIXME: The code is a bit of a mess */
|
||||
|
||||
/* multiply the zoom_factor with the ratio of the new and
|
||||
* old canvas diagonals
|
||||
*/
|
||||
scale *= (sqrt (SQR (allocation.width) +
|
||||
SQR (allocation.height)) /
|
||||
sqrt (SQR (tick->prev_width) +
|
||||
SQR (tick->prev_height)));
|
||||
|
||||
offset_x = UNSCALEX (shell, shell->offset_x);
|
||||
offset_y = UNSCALEX (shell, shell->offset_y);
|
||||
|
||||
pika_zoom_model_zoom (shell->zoom, PIKA_ZOOM_TO, scale);
|
||||
|
||||
shell->offset_x = SCALEX (shell, offset_x);
|
||||
shell->offset_y = SCALEY (shell, offset_y);
|
||||
}
|
||||
|
||||
/* When we size-allocate due to resize of the top level window,
|
||||
* we want some additional logic. Don't apply it on
|
||||
* zoom_on_resize though.
|
||||
*/
|
||||
if (shell->size_allocate_from_configure_event &&
|
||||
! shell->zoom_on_resize)
|
||||
{
|
||||
gboolean center_horizontally;
|
||||
gboolean center_vertically;
|
||||
gint target_offset_x;
|
||||
gint target_offset_y;
|
||||
gint sw;
|
||||
gint sh;
|
||||
|
||||
pika_display_shell_scale_get_image_size (shell, &sw, &sh);
|
||||
|
||||
center_horizontally = sw <= shell->disp_width;
|
||||
center_vertically = sh <= shell->disp_height;
|
||||
|
||||
if (! pika_display_shell_get_infinite_canvas (shell))
|
||||
{
|
||||
pika_display_shell_scroll_center_image (shell,
|
||||
center_horizontally,
|
||||
center_vertically);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_display_shell_scroll_center_content (shell,
|
||||
center_horizontally,
|
||||
center_vertically);
|
||||
}
|
||||
|
||||
/* This is basically the best we can do before we get an
|
||||
* API for storing the image offset at the start of an
|
||||
* image window resize using the mouse
|
||||
*/
|
||||
target_offset_x = shell->offset_x;
|
||||
target_offset_y = shell->offset_y;
|
||||
|
||||
if (! center_horizontally)
|
||||
{
|
||||
target_offset_x = MAX (shell->offset_x, 0);
|
||||
}
|
||||
|
||||
if (! center_vertically)
|
||||
{
|
||||
target_offset_y = MAX (shell->offset_y, 0);
|
||||
}
|
||||
|
||||
pika_display_shell_scroll_set_offset (shell,
|
||||
target_offset_x,
|
||||
target_offset_y);
|
||||
}
|
||||
|
||||
pika_display_shell_scroll_clamp_and_update (shell);
|
||||
pika_display_shell_scaled (shell);
|
||||
|
||||
shell->size_allocate_from_configure_event = FALSE;
|
||||
}
|
||||
|
||||
if (shell->size_allocate_center_image)
|
||||
{
|
||||
pika_display_shell_scroll_center_image (shell, TRUE, TRUE);
|
||||
|
||||
shell->size_allocate_center_image = FALSE;
|
||||
}
|
||||
|
||||
/* undo size request from pika_display_shell_constructed() */
|
||||
gtk_widget_set_size_request (widget, -1, -1);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_canvas_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
TickClosure *tick;
|
||||
|
||||
/* are we in destruction? */
|
||||
if (! shell->display || ! pika_display_get_shell (shell->display))
|
||||
return;
|
||||
|
||||
tick = g_new0 (TickClosure, 1);
|
||||
|
||||
tick->shell = shell;
|
||||
tick->prev_width = shell->disp_width;
|
||||
tick->prev_height = shell->disp_height;
|
||||
|
||||
if (shell->disp_width != allocation->width ||
|
||||
shell->disp_height != allocation->height)
|
||||
{
|
||||
g_clear_pointer (&shell->render_cache, cairo_surface_destroy);
|
||||
pika_display_shell_render_invalidate_full (shell);
|
||||
|
||||
shell->disp_width = allocation->width;
|
||||
shell->disp_height = allocation->height;
|
||||
}
|
||||
|
||||
gtk_widget_add_tick_callback (widget,
|
||||
(GtkTickCallback) pika_display_shell_canvas_tick,
|
||||
tick, (GDestroyNotify) g_free);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_canvas_draw (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
/* are we in destruction? */
|
||||
if (! shell->display || ! pika_display_get_shell (shell->display))
|
||||
return TRUE;
|
||||
|
||||
/* we will scroll around in the next tick anyway, so we just can as
|
||||
* well skip the drawing of this frame and wait for the next
|
||||
*/
|
||||
if (shell->size_allocate_center_image)
|
||||
return TRUE;
|
||||
|
||||
/* ignore events on overlays */
|
||||
if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
|
||||
{
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
|
||||
/* If we are currently converting the image, it might be in inconsistent
|
||||
* state and should not be redrawn.
|
||||
*/
|
||||
if (image != NULL && ! pika_image_get_converting (image))
|
||||
{
|
||||
pika_display_shell_canvas_draw_image (shell, cr);
|
||||
}
|
||||
else if (image == NULL)
|
||||
{
|
||||
pika_display_shell_canvas_draw_drop_zone (shell, cr);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_origin_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (! shell->display->pika->busy)
|
||||
{
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 1)
|
||||
{
|
||||
gboolean unused;
|
||||
|
||||
g_signal_emit_by_name (shell, "popup-menu", &unused);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return TRUE to stop signal emission so the button doesn't grab the
|
||||
* pointer away from us.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_quick_mask_button_press (GtkWidget *widget,
|
||||
GdkEventButton *bevent,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (! pika_display_get_image (shell->display))
|
||||
return TRUE;
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) bevent))
|
||||
{
|
||||
PikaImageWindow *window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window)
|
||||
{
|
||||
Pika *pika;
|
||||
PikaUIManager *manager;
|
||||
|
||||
pika = shell->display->pika;
|
||||
manager = pika_menu_factory_get_manager (menus_get_global_menu_factory (pika), "<QuickMask>", pika);
|
||||
pika_ui_manager_ui_popup_at_widget (manager,
|
||||
"/quick-mask-popup",
|
||||
NULL, NULL,
|
||||
widget,
|
||||
GDK_GRAVITY_EAST,
|
||||
GDK_GRAVITY_SOUTH_WEST,
|
||||
(GdkEvent *) bevent,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_quick_mask_toggled (GtkWidget *widget,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
|
||||
|
||||
if (active != pika_image_get_quick_mask_state (image))
|
||||
{
|
||||
PikaImageWindow *window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window)
|
||||
{
|
||||
PikaUIManager *manager = menus_get_image_manager_singleton (shell->display->pika);
|
||||
|
||||
pika_ui_manager_toggle_action (manager,
|
||||
"quick-mask", "quick-mask-toggle",
|
||||
active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_navigation_button_press (GtkWidget *widget,
|
||||
GdkEventButton *bevent,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (! pika_display_get_image (shell->display))
|
||||
return TRUE;
|
||||
|
||||
if (bevent->type == GDK_BUTTON_PRESS && bevent->button == 1)
|
||||
{
|
||||
pika_navigation_editor_popup (shell, widget,
|
||||
(GdkEvent *) bevent,
|
||||
bevent->x, bevent->y);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_display_shell_vadjustment_changed (GtkAdjustment *adjustment,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
/* If we are panning with mouse, scrollbars are to be ignored or
|
||||
* they will cause jitter in motion
|
||||
*/
|
||||
if (shell->mod_action == PIKA_MODIFIER_ACTION_NONE)
|
||||
pika_display_shell_scroll (shell,
|
||||
0,
|
||||
gtk_adjustment_get_value (adjustment) -
|
||||
shell->offset_y);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_hadjustment_changed (GtkAdjustment *adjustment,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
/* If we are panning with mouse, scrollbars are to be ignored or
|
||||
* they will cause jitter in motion
|
||||
*/
|
||||
if (shell->mod_action == PIKA_MODIFIER_ACTION_NONE)
|
||||
pika_display_shell_scroll (shell,
|
||||
gtk_adjustment_get_value (adjustment) -
|
||||
shell->offset_x,
|
||||
0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_shell_hscrollbar_change_value (GtkRange *range,
|
||||
GtkScrollType scroll,
|
||||
gdouble value,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (! shell->display)
|
||||
return TRUE;
|
||||
|
||||
if ((scroll == GTK_SCROLL_JUMP) ||
|
||||
(scroll == GTK_SCROLL_PAGE_BACKWARD) ||
|
||||
(scroll == GTK_SCROLL_PAGE_FORWARD))
|
||||
return FALSE;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (shell->hsbdata));
|
||||
|
||||
pika_display_shell_scrollbars_setup_horizontal (shell, value);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (shell->hsbdata)); /* emits "changed" */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_shell_vscrollbar_change_value (GtkRange *range,
|
||||
GtkScrollType scroll,
|
||||
gdouble value,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (! shell->display)
|
||||
return TRUE;
|
||||
|
||||
if ((scroll == GTK_SCROLL_JUMP) ||
|
||||
(scroll == GTK_SCROLL_PAGE_BACKWARD) ||
|
||||
(scroll == GTK_SCROLL_PAGE_FORWARD))
|
||||
return FALSE;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (shell->vsbdata));
|
||||
|
||||
pika_display_shell_scrollbars_setup_vertical (shell, value);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (shell->vsbdata)); /* emits "changed" */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_canvas_draw_image (PikaDisplayShell *shell,
|
||||
cairo_t *cr)
|
||||
{
|
||||
cairo_rectangle_list_t *clip_rectangles;
|
||||
GeglRectangle image_rect;
|
||||
GeglRectangle rotated_image_rect;
|
||||
GeglRectangle canvas_rect;
|
||||
cairo_matrix_t matrix;
|
||||
gdouble x1, y1;
|
||||
gdouble x2, y2;
|
||||
|
||||
pika_display_shell_scale_get_image_unrotated_bounding_box (
|
||||
shell,
|
||||
&image_rect.x,
|
||||
&image_rect.y,
|
||||
&image_rect.width,
|
||||
&image_rect.height);
|
||||
|
||||
pika_display_shell_scale_get_image_unrotated_bounds (
|
||||
shell,
|
||||
&canvas_rect.x,
|
||||
&canvas_rect.y,
|
||||
&canvas_rect.width,
|
||||
&canvas_rect.height);
|
||||
|
||||
/* first, draw the background
|
||||
*/
|
||||
|
||||
pika_display_shell_draw_background (shell, cr);
|
||||
|
||||
|
||||
/* then, draw the exposed part of the region that is inside the
|
||||
* image
|
||||
*/
|
||||
|
||||
cairo_save (cr);
|
||||
clip_rectangles = cairo_copy_clip_rectangle_list (cr);
|
||||
cairo_get_matrix (cr, &matrix);
|
||||
|
||||
if (shell->rotate_transform)
|
||||
cairo_transform (cr, shell->rotate_transform);
|
||||
|
||||
if (shell->show_all)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
if (pika_display_shell_get_padding_in_show_all (shell))
|
||||
{
|
||||
cairo_rectangle (cr,
|
||||
canvas_rect.x,
|
||||
canvas_rect.y,
|
||||
canvas_rect.width,
|
||||
canvas_rect.height);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
|
||||
pika_display_shell_draw_checkerboard (shell, cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
cairo_rectangle (cr,
|
||||
image_rect.x,
|
||||
image_rect.y,
|
||||
image_rect.width,
|
||||
image_rect.height);
|
||||
cairo_clip (cr);
|
||||
|
||||
pika_display_shell_rotate_bounds (shell,
|
||||
image_rect.x,
|
||||
image_rect.y,
|
||||
image_rect.x + image_rect.width,
|
||||
image_rect.y + image_rect.height,
|
||||
&x1, &y1, &x2, &y2);
|
||||
|
||||
rotated_image_rect.x = floor (x1);
|
||||
rotated_image_rect.y = floor (y1);
|
||||
rotated_image_rect.width = ceil (x2) - rotated_image_rect.x;
|
||||
rotated_image_rect.height = ceil (y2) - rotated_image_rect.y;
|
||||
|
||||
if (gdk_cairo_get_clip_rectangle (cr, NULL))
|
||||
{
|
||||
gint i;
|
||||
|
||||
if (! shell->show_all)
|
||||
{
|
||||
cairo_save (cr);
|
||||
pika_display_shell_draw_checkerboard (shell, cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
if (shell->show_image)
|
||||
{
|
||||
cairo_set_matrix (cr, &matrix);
|
||||
|
||||
for (i = 0; i < clip_rectangles->num_rectangles; i++)
|
||||
{
|
||||
cairo_rectangle_t clip_rect = clip_rectangles->rectangles[i];
|
||||
GeglRectangle rect;
|
||||
|
||||
rect.x = floor (clip_rect.x);
|
||||
rect.y = floor (clip_rect.y);
|
||||
rect.width = ceil (clip_rect.x + clip_rect.width) - rect.x;
|
||||
rect.height = ceil (clip_rect.y + clip_rect.height) - rect.y;
|
||||
|
||||
if (gegl_rectangle_intersect (&rect, &rect, &rotated_image_rect))
|
||||
{
|
||||
pika_display_shell_draw_image (shell, cr,
|
||||
rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cairo_rectangle_list_destroy (clip_rectangles);
|
||||
cairo_restore (cr);
|
||||
|
||||
|
||||
/* finally, draw all the remaining image window stuff on top
|
||||
*/
|
||||
|
||||
/* draw canvas items */
|
||||
cairo_save (cr);
|
||||
|
||||
if (shell->rotate_transform)
|
||||
cairo_transform (cr, shell->rotate_transform);
|
||||
|
||||
pika_canvas_item_draw (shell->canvas_item, cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
pika_canvas_item_draw (shell->unrotated_item, cr);
|
||||
|
||||
/* restart (and recalculate) the selection boundaries */
|
||||
pika_display_shell_selection_draw (shell, cr);
|
||||
pika_display_shell_selection_restart (shell);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_canvas_draw_drop_zone (PikaDisplayShell *shell,
|
||||
cairo_t *cr)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
pika_display_shell_draw_background (shell, cr);
|
||||
|
||||
pika_cairo_draw_drop_mascot (shell->canvas, cr, shell->blink);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
#ifdef PIKA_UNSTABLE
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (shell);
|
||||
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
||||
GtkStateFlags state = gtk_widget_get_state_flags (widget);
|
||||
PangoLayout *layout;
|
||||
gchar *msg;
|
||||
GtkAllocation allocation;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble scale;
|
||||
GdkRGBA color;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (shell->canvas, NULL);
|
||||
|
||||
msg = g_strdup_printf (_("<big>Unstable Development Version</big>\n\n"
|
||||
"<small>commit <tt>%s</tt></small>\n\n"
|
||||
"<small>Please test bugs against "
|
||||
"latest git master branch\n"
|
||||
"before reporting them.</small>"),
|
||||
PIKA_GIT_VERSION_ABBREV);
|
||||
pango_layout_set_markup (layout, msg, -1);
|
||||
g_free (msg);
|
||||
pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
|
||||
|
||||
pango_layout_get_pixel_size (layout, &width, &height);
|
||||
gtk_widget_get_allocation (shell->canvas, &allocation);
|
||||
|
||||
scale = MIN (((gdouble) allocation.width / 2.0) / (gdouble) width,
|
||||
((gdouble) allocation.height / 2.0) / (gdouble) height);
|
||||
|
||||
gtk_style_context_get_color (context, state, &color);
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
|
||||
cairo_move_to (cr,
|
||||
(allocation.width - (width * scale)) / 2,
|
||||
(allocation.height - (height * scale)) / 2);
|
||||
|
||||
cairo_scale (cr, scale, scale);
|
||||
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
#endif /* PIKA_UNSTABLE */
|
||||
}
|
||||
50
app/display/pikadisplayshell-callbacks.h
Normal file
50
app/display/pikadisplayshell-callbacks.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_CALLBACKS_H__
|
||||
#define __PIKA_DISPLAY_SHELL_CALLBACKS_H__
|
||||
|
||||
|
||||
void pika_display_shell_canvas_realize (GtkWidget *widget,
|
||||
PikaDisplayShell *shell);
|
||||
void pika_display_shell_canvas_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *alloc,
|
||||
PikaDisplayShell *shell);
|
||||
gboolean pika_display_shell_canvas_draw (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
gboolean pika_display_shell_origin_button_press (GtkWidget *widget,
|
||||
GdkEventButton *bevent,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
gboolean pika_display_shell_quick_mask_button_press (GtkWidget *widget,
|
||||
GdkEventButton *bevent,
|
||||
PikaDisplayShell *shell);
|
||||
void pika_display_shell_quick_mask_toggled (GtkWidget *widget,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
gboolean pika_display_shell_navigation_button_press (GtkWidget *widget,
|
||||
GdkEventButton *bevent,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_CALLBACKS_H__ */
|
||||
453
app/display/pikadisplayshell-close.c
Normal file
453
app/display/pikadisplayshell-close.c
Normal file
@ -0,0 +1,453 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "config/pikadisplayconfig.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontainer.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "menus/menus.h"
|
||||
|
||||
#include "widgets/pikahelp-ids.h"
|
||||
#include "widgets/pikamessagebox.h"
|
||||
#include "widgets/pikamessagedialog.h"
|
||||
#include "widgets/pikauimanager.h"
|
||||
#include "widgets/pikawidgets-utils.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-close.h"
|
||||
#include "pikaimagewindow.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_shell_close_dialog (PikaDisplayShell *shell,
|
||||
PikaImage *image);
|
||||
static void pika_display_shell_close_name_changed (PikaImage *image,
|
||||
PikaMessageBox *box);
|
||||
static void pika_display_shell_close_exported (PikaImage *image,
|
||||
GFile *file,
|
||||
PikaMessageBox *box);
|
||||
static gboolean pika_display_shell_close_time_changed (PikaMessageBox *box);
|
||||
static void pika_display_shell_close_response (GtkWidget *widget,
|
||||
gboolean close,
|
||||
PikaDisplayShell *shell);
|
||||
static void pika_display_shell_close_accel_marshal(GClosure *closure,
|
||||
GValue *return_value,
|
||||
guint n_param_values,
|
||||
const GValue *param_values,
|
||||
gpointer invocation_hint,
|
||||
gpointer marshal_data);
|
||||
static void pika_time_since (gint64 then,
|
||||
gint *hours,
|
||||
gint *minutes);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_close (PikaDisplayShell *shell,
|
||||
gboolean kill_it)
|
||||
{
|
||||
PikaImage *image;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
image = pika_display_get_image (shell->display);
|
||||
|
||||
/* FIXME: pika_busy HACK not really appropriate here because we only
|
||||
* want to prevent the busy image and display to be closed. --Mitch
|
||||
*/
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
/* If the image has been modified, give the user a chance to save
|
||||
* it before nuking it--this only applies if its the last view
|
||||
* to an image canvas. (a image with disp_count = 1)
|
||||
*/
|
||||
if (! kill_it &&
|
||||
image &&
|
||||
pika_image_get_display_count (image) == 1 &&
|
||||
pika_image_is_dirty (image))
|
||||
{
|
||||
/* If there's a save dialog active for this image, then raise it.
|
||||
* (see bug #511965)
|
||||
*/
|
||||
GtkWidget *dialog = g_object_get_data (G_OBJECT (image),
|
||||
"pika-file-save-dialog");
|
||||
if (dialog)
|
||||
{
|
||||
gtk_window_present (GTK_WINDOW (dialog));
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_display_shell_close_dialog (shell, image);
|
||||
}
|
||||
}
|
||||
else if (image)
|
||||
{
|
||||
pika_display_close (shell->display);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaImageWindow *window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window)
|
||||
{
|
||||
PikaUIManager *manager = menus_get_image_manager_singleton (shell->display->pika);
|
||||
|
||||
/* Activate the action instead of simply calling pika_exit(), so
|
||||
* the quit action's sensitivity is taken into account.
|
||||
*/
|
||||
pika_ui_manager_activate_action (manager, "file", "file-quit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
#define RESPONSE_SAVE 1
|
||||
|
||||
|
||||
static void
|
||||
pika_display_shell_close_dialog (PikaDisplayShell *shell,
|
||||
PikaImage *image)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
PikaMessageBox *box;
|
||||
GtkWidget *label;
|
||||
GtkAccelGroup *accel_group;
|
||||
GClosure *closure;
|
||||
GSource *source;
|
||||
guint accel_key;
|
||||
GdkModifierType accel_mods;
|
||||
gchar *title;
|
||||
gchar *accel_string;
|
||||
gchar *hint;
|
||||
gchar *markup;
|
||||
GFile *file;
|
||||
|
||||
if (shell->close_dialog)
|
||||
{
|
||||
gtk_window_present (GTK_WINDOW (shell->close_dialog));
|
||||
return;
|
||||
}
|
||||
|
||||
file = pika_image_get_file (image);
|
||||
|
||||
title = g_strdup_printf (_("Close %s"), pika_image_get_display_name (image));
|
||||
|
||||
shell->close_dialog =
|
||||
dialog = pika_message_dialog_new (title, PIKA_ICON_DOCUMENT_SAVE,
|
||||
GTK_WIDGET (shell),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
pika_standard_help_func, NULL,
|
||||
|
||||
file ?
|
||||
_("_Save") :
|
||||
_("Save _As"), RESPONSE_SAVE,
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_Discard Changes"), GTK_RESPONSE_CLOSE,
|
||||
NULL);
|
||||
|
||||
g_free (title);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
|
||||
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
|
||||
RESPONSE_SAVE,
|
||||
GTK_RESPONSE_CLOSE,
|
||||
GTK_RESPONSE_CANCEL,
|
||||
-1);
|
||||
|
||||
g_signal_connect (dialog, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed),
|
||||
&shell->close_dialog);
|
||||
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (pika_display_shell_close_response),
|
||||
shell);
|
||||
|
||||
/* connect <Primary>D to the quit/close button */
|
||||
accel_group = gtk_accel_group_new ();
|
||||
gtk_window_add_accel_group (GTK_WINDOW (shell->close_dialog), accel_group);
|
||||
g_object_unref (accel_group);
|
||||
|
||||
closure = g_closure_new_object (sizeof (GClosure),
|
||||
G_OBJECT (shell->close_dialog));
|
||||
g_closure_set_marshal (closure, pika_display_shell_close_accel_marshal);
|
||||
gtk_accelerator_parse ("<Primary>D", &accel_key, &accel_mods);
|
||||
gtk_accel_group_connect (accel_group, accel_key, accel_mods, 0, closure);
|
||||
|
||||
box = PIKA_MESSAGE_DIALOG (dialog)->box;
|
||||
|
||||
accel_string = gtk_accelerator_get_label (accel_key, accel_mods);
|
||||
hint = g_strdup_printf (_("Press %s to discard all changes and close the image."),
|
||||
accel_string);
|
||||
markup = g_strdup_printf ("<i><small>%s</small></i>", hint);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
gtk_label_set_markup (GTK_LABEL (label), markup);
|
||||
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
|
||||
gtk_widget_show (label);
|
||||
|
||||
g_free (markup);
|
||||
g_free (hint);
|
||||
g_free (accel_string);
|
||||
|
||||
g_signal_connect_object (image, "name-changed",
|
||||
G_CALLBACK (pika_display_shell_close_name_changed),
|
||||
box, 0);
|
||||
g_signal_connect_object (image, "exported",
|
||||
G_CALLBACK (pika_display_shell_close_exported),
|
||||
box, 0);
|
||||
|
||||
pika_display_shell_close_name_changed (image, box);
|
||||
|
||||
closure =
|
||||
g_cclosure_new_object (G_CALLBACK (pika_display_shell_close_time_changed),
|
||||
G_OBJECT (box));
|
||||
|
||||
/* update every 10 seconds */
|
||||
source = g_timeout_source_new_seconds (10);
|
||||
g_source_set_closure (source, closure);
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
|
||||
/* The dialog is destroyed with the shell, so it should be safe
|
||||
* to hold an image pointer for the lifetime of the dialog.
|
||||
*/
|
||||
g_object_set_data (G_OBJECT (box), "pika-image", image);
|
||||
|
||||
pika_display_shell_close_time_changed (box);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_close_name_changed (PikaImage *image,
|
||||
PikaMessageBox *box)
|
||||
{
|
||||
GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET (box));
|
||||
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
gchar *title = g_strdup_printf (_("Close %s"),
|
||||
pika_image_get_display_name (image));
|
||||
|
||||
gtk_window_set_title (GTK_WINDOW (window), title);
|
||||
g_free (title);
|
||||
}
|
||||
|
||||
pika_message_box_set_primary_text (box,
|
||||
_("Save the changes to image '%s' "
|
||||
"before closing?"),
|
||||
pika_image_get_display_name (image));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_close_exported (PikaImage *image,
|
||||
GFile *file,
|
||||
PikaMessageBox *box)
|
||||
{
|
||||
pika_display_shell_close_time_changed (box);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_display_shell_close_time_changed (PikaMessageBox *box)
|
||||
{
|
||||
PikaImage *image = g_object_get_data (G_OBJECT (box), "pika-image");
|
||||
gint64 dirty_time = pika_image_get_dirty_time (image);
|
||||
gchar *time_text = NULL;
|
||||
gchar *export_text = NULL;
|
||||
|
||||
if (dirty_time)
|
||||
{
|
||||
gint hours = 0;
|
||||
gint minutes = 0;
|
||||
|
||||
pika_time_since (dirty_time, &hours, &minutes);
|
||||
|
||||
if (hours > 0)
|
||||
{
|
||||
if (hours > 1 || minutes == 0)
|
||||
{
|
||||
time_text =
|
||||
g_strdup_printf (ngettext ("If you don't save the image, "
|
||||
"changes from the last hour "
|
||||
"will be lost.",
|
||||
"If you don't save the image, "
|
||||
"changes from the last %d "
|
||||
"hours will be lost.",
|
||||
hours), hours);
|
||||
}
|
||||
else
|
||||
{
|
||||
time_text =
|
||||
g_strdup_printf (ngettext ("If you don't save the image, "
|
||||
"changes from the last hour "
|
||||
"and %d minute will be lost.",
|
||||
"If you don't save the image, "
|
||||
"changes from the last hour "
|
||||
"and %d minutes will be lost.",
|
||||
minutes), minutes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
time_text =
|
||||
g_strdup_printf (ngettext ("If you don't save the image, "
|
||||
"changes from the last minute "
|
||||
"will be lost.",
|
||||
"If you don't save the image, "
|
||||
"changes from the last %d "
|
||||
"minutes will be lost.",
|
||||
minutes), minutes);
|
||||
}
|
||||
}
|
||||
|
||||
if (! pika_image_is_export_dirty (image))
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = pika_image_get_exported_file (image);
|
||||
if (! file)
|
||||
file = pika_image_get_imported_file (image);
|
||||
|
||||
export_text = g_strdup_printf (_("The image has been exported to '%s'."),
|
||||
pika_file_get_utf8_name (file));
|
||||
}
|
||||
|
||||
if (time_text && export_text)
|
||||
pika_message_box_set_text (box, "%s\n\n%s", time_text, export_text);
|
||||
else if (time_text || export_text)
|
||||
pika_message_box_set_text (box, "%s", time_text ? time_text : export_text);
|
||||
else
|
||||
pika_message_box_set_text (box, "%s", time_text);
|
||||
|
||||
g_free (time_text);
|
||||
g_free (export_text);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_close_response (GtkWidget *widget,
|
||||
gint response_id,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
gtk_widget_destroy (widget);
|
||||
|
||||
switch (response_id)
|
||||
{
|
||||
case GTK_RESPONSE_CLOSE:
|
||||
pika_display_close (shell->display);
|
||||
break;
|
||||
|
||||
case RESPONSE_SAVE:
|
||||
{
|
||||
PikaImageWindow *window = pika_display_shell_get_window (shell);
|
||||
|
||||
if (window)
|
||||
{
|
||||
PikaUIManager *manager = menus_get_image_manager_singleton (shell->display->pika);
|
||||
|
||||
pika_image_window_set_active_shell (window, shell);
|
||||
|
||||
pika_ui_manager_activate_action (manager,
|
||||
"file", "file-save-and-close");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_close_accel_marshal (GClosure *closure,
|
||||
GValue *return_value,
|
||||
guint n_param_values,
|
||||
const GValue *param_values,
|
||||
gpointer invocation_hint,
|
||||
gpointer marshal_data)
|
||||
{
|
||||
gtk_dialog_response (GTK_DIALOG (closure->data), GTK_RESPONSE_CLOSE);
|
||||
|
||||
/* we handled the accelerator */
|
||||
g_value_set_boolean (return_value, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_time_since (gint64 then,
|
||||
gint *hours,
|
||||
gint *minutes)
|
||||
{
|
||||
gint64 now = time (NULL);
|
||||
gint64 diff = 1 + now - then;
|
||||
|
||||
g_return_if_fail (now >= then);
|
||||
|
||||
/* first round up to the nearest minute */
|
||||
diff = (diff + 59) / 60;
|
||||
|
||||
/* then optionally round minutes to multiples of 5 or 10 */
|
||||
if (diff > 50)
|
||||
diff = ((diff + 8) / 10) * 10;
|
||||
else if (diff > 20)
|
||||
diff = ((diff + 3) / 5) * 5;
|
||||
|
||||
/* determine full hours */
|
||||
if (diff >= 60)
|
||||
{
|
||||
*hours = diff / 60;
|
||||
diff = (diff % 60);
|
||||
}
|
||||
|
||||
/* round up to full hours for 2 and more */
|
||||
if (*hours > 1 && diff > 0)
|
||||
{
|
||||
*hours += 1;
|
||||
diff = 0;
|
||||
}
|
||||
|
||||
*minutes = diff;
|
||||
}
|
||||
30
app/display/pikadisplayshell-close.h
Normal file
30
app/display/pikadisplayshell-close.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_CLOSE_H__
|
||||
#define __PIKA_DISPLAY_SHELL_CLOSE_H__
|
||||
|
||||
|
||||
void pika_display_shell_close (PikaDisplayShell *shell,
|
||||
gboolean kill_it);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_CLOSE_H__ */
|
||||
300
app/display/pikadisplayshell-cursor.c
Normal file
300
app/display/pikadisplayshell-cursor.c
Normal file
@ -0,0 +1,300 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "config/pikaguiconfig.h"
|
||||
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "widgets/pikacursor.h"
|
||||
#include "widgets/pikadialogfactory.h"
|
||||
#include "widgets/pikadockcontainer.h"
|
||||
#include "widgets/pikasessioninfo.h"
|
||||
|
||||
#include "pikacanvascursor.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikacursorview.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-cursor.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
#include "pikastatusbar.h"
|
||||
|
||||
|
||||
static void pika_display_shell_real_set_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorType cursor_type,
|
||||
PikaToolCursorType tool_cursor,
|
||||
PikaCursorModifier modifier,
|
||||
gboolean always_install);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_set_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorType cursor_type,
|
||||
PikaToolCursorType tool_cursor,
|
||||
PikaCursorModifier modifier)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (! shell->using_override_cursor)
|
||||
{
|
||||
pika_display_shell_real_set_cursor (shell,
|
||||
cursor_type,
|
||||
tool_cursor,
|
||||
modifier,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_unset_cursor (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (! shell->using_override_cursor)
|
||||
{
|
||||
pika_display_shell_real_set_cursor (shell,
|
||||
(PikaCursorType) -1, 0, 0, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_set_override_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorType cursor_type)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (! shell->using_override_cursor ||
|
||||
(shell->using_override_cursor &&
|
||||
shell->override_cursor != cursor_type))
|
||||
{
|
||||
shell->override_cursor = cursor_type;
|
||||
shell->using_override_cursor = TRUE;
|
||||
|
||||
pika_cursor_set (shell->canvas,
|
||||
shell->cursor_handedness,
|
||||
cursor_type,
|
||||
PIKA_TOOL_CURSOR_NONE,
|
||||
PIKA_CURSOR_MODIFIER_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_unset_override_cursor (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (shell->using_override_cursor)
|
||||
{
|
||||
shell->using_override_cursor = FALSE;
|
||||
|
||||
pika_display_shell_real_set_cursor (shell,
|
||||
shell->current_cursor,
|
||||
shell->tool_cursor,
|
||||
shell->cursor_modifier,
|
||||
TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_update_software_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorPrecision precision,
|
||||
gint display_x,
|
||||
gint display_y,
|
||||
gdouble image_x,
|
||||
gdouble image_y)
|
||||
{
|
||||
PikaImageWindow *image_window;
|
||||
PikaDialogFactory *factory;
|
||||
PikaStatusbar *statusbar;
|
||||
GtkWidget *widget;
|
||||
PikaImage *image;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
image = pika_display_get_image (shell->display);
|
||||
|
||||
if (shell->draw_cursor &&
|
||||
shell->proximity &&
|
||||
display_x >= 0 &&
|
||||
display_y >= 0)
|
||||
{
|
||||
pika_canvas_item_begin_change (shell->cursor);
|
||||
|
||||
pika_canvas_cursor_set (shell->cursor,
|
||||
display_x,
|
||||
display_y);
|
||||
pika_canvas_item_set_visible (shell->cursor, TRUE);
|
||||
|
||||
pika_canvas_item_end_change (shell->cursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_canvas_item_set_visible (shell->cursor, FALSE);
|
||||
}
|
||||
|
||||
/* use the passed image_coords for the statusbar because they are
|
||||
* possibly snapped...
|
||||
*/
|
||||
statusbar = pika_display_shell_get_statusbar (shell);
|
||||
|
||||
pika_statusbar_update_cursor (statusbar, precision, image_x, image_y);
|
||||
|
||||
image_window = pika_display_shell_get_window (shell);
|
||||
factory = pika_dock_container_get_dialog_factory (PIKA_DOCK_CONTAINER (image_window));
|
||||
|
||||
widget = pika_dialog_factory_find_widget (factory, "pika-cursor-view");
|
||||
|
||||
if (widget)
|
||||
{
|
||||
GtkWidget *cursor_view = gtk_bin_get_child (GTK_BIN (widget));
|
||||
|
||||
if (cursor_view)
|
||||
{
|
||||
gint t_x = -1;
|
||||
gint t_y = -1;
|
||||
|
||||
/* ...but use the unsnapped display_coords for the info window */
|
||||
if (display_x >= 0 && display_y >= 0)
|
||||
pika_display_shell_untransform_xy (shell, display_x, display_y,
|
||||
&t_x, &t_y, FALSE);
|
||||
|
||||
pika_cursor_view_update_cursor (PIKA_CURSOR_VIEW (cursor_view),
|
||||
image, shell->unit,
|
||||
t_x, t_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_clear_software_cursor (PikaDisplayShell *shell)
|
||||
{
|
||||
PikaImageWindow *image_window;
|
||||
PikaDialogFactory *factory;
|
||||
PikaStatusbar *statusbar;
|
||||
GtkWidget *widget;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
pika_canvas_item_set_visible (shell->cursor, FALSE);
|
||||
|
||||
statusbar = pika_display_shell_get_statusbar (shell);
|
||||
|
||||
pika_statusbar_clear_cursor (statusbar);
|
||||
|
||||
image_window = pika_display_shell_get_window (shell);
|
||||
factory = pika_dock_container_get_dialog_factory (PIKA_DOCK_CONTAINER (image_window));
|
||||
|
||||
widget = pika_dialog_factory_find_widget (factory, "pika-cursor-view");
|
||||
|
||||
if (widget)
|
||||
{
|
||||
GtkWidget *cursor_view = gtk_bin_get_child (GTK_BIN (widget));
|
||||
|
||||
if (cursor_view)
|
||||
pika_cursor_view_clear_cursor (PIKA_CURSOR_VIEW (cursor_view));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_display_shell_real_set_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorType cursor_type,
|
||||
PikaToolCursorType tool_cursor,
|
||||
PikaCursorModifier modifier,
|
||||
gboolean always_install)
|
||||
{
|
||||
PikaHandedness cursor_handedness;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (cursor_type == (PikaCursorType) -1)
|
||||
{
|
||||
shell->current_cursor = cursor_type;
|
||||
|
||||
if (gtk_widget_is_drawable (shell->canvas))
|
||||
gdk_window_set_cursor (gtk_widget_get_window (shell->canvas), NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursor_type != PIKA_CURSOR_NONE &&
|
||||
cursor_type != PIKA_CURSOR_BAD &&
|
||||
cursor_type != PIKA_CURSOR_SINGLE_DOT)
|
||||
{
|
||||
switch (shell->display->config->cursor_mode)
|
||||
{
|
||||
case PIKA_CURSOR_MODE_TOOL_ICON:
|
||||
break;
|
||||
|
||||
case PIKA_CURSOR_MODE_TOOL_CROSSHAIR:
|
||||
if (cursor_type < PIKA_CURSOR_CORNER_TOP ||
|
||||
cursor_type > PIKA_CURSOR_SIDE_TOP_LEFT)
|
||||
{
|
||||
/* the corner and side cursors count as crosshair, so leave
|
||||
* them and override everything else
|
||||
*/
|
||||
cursor_type = PIKA_CURSOR_CROSSHAIR_SMALL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_CURSOR_MODE_CROSSHAIR:
|
||||
cursor_type = PIKA_CURSOR_CROSSHAIR;
|
||||
tool_cursor = PIKA_TOOL_CURSOR_NONE;
|
||||
|
||||
if (modifier != PIKA_CURSOR_MODIFIER_BAD)
|
||||
{
|
||||
/* the bad modifier is always shown */
|
||||
modifier = PIKA_CURSOR_MODIFIER_NONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cursor_type = pika_cursor_rotate (cursor_type, shell->rotate_angle);
|
||||
|
||||
cursor_handedness = PIKA_GUI_CONFIG (shell->display->config)->cursor_handedness;
|
||||
|
||||
if (shell->cursor_handedness != cursor_handedness ||
|
||||
shell->current_cursor != cursor_type ||
|
||||
shell->tool_cursor != tool_cursor ||
|
||||
shell->cursor_modifier != modifier ||
|
||||
always_install)
|
||||
{
|
||||
shell->cursor_handedness = cursor_handedness;
|
||||
shell->current_cursor = cursor_type;
|
||||
shell->tool_cursor = tool_cursor;
|
||||
shell->cursor_modifier = modifier;
|
||||
|
||||
pika_cursor_set (shell->canvas,
|
||||
cursor_handedness,
|
||||
cursor_type, tool_cursor, modifier);
|
||||
}
|
||||
}
|
||||
51
app/display/pikadisplayshell-cursor.h
Normal file
51
app/display/pikadisplayshell-cursor.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_CURSOR_H__
|
||||
#define __PIKA_DISPLAY_SHELL_CURSOR_H__
|
||||
|
||||
|
||||
/* functions dealing with the normal windowing system cursor */
|
||||
|
||||
void pika_display_shell_set_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorType cursor_type,
|
||||
PikaToolCursorType tool_cursor,
|
||||
PikaCursorModifier modifier);
|
||||
void pika_display_shell_unset_cursor (PikaDisplayShell *shell);
|
||||
void pika_display_shell_set_override_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorType cursor_type);
|
||||
void pika_display_shell_unset_override_cursor (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
/* functions dealing with the software cursor that is drawn to the
|
||||
* canvas by PIKA
|
||||
*/
|
||||
|
||||
void pika_display_shell_update_software_cursor (PikaDisplayShell *shell,
|
||||
PikaCursorPrecision precision,
|
||||
gint display_x,
|
||||
gint display_y,
|
||||
gdouble image_x,
|
||||
gdouble image_y);
|
||||
void pika_display_shell_clear_software_cursor (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_CURSOR_H__ */
|
||||
764
app/display/pikadisplayshell-dnd.c
Normal file
764
app/display/pikadisplayshell-dnd.c
Normal file
@ -0,0 +1,764 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pika-edit.h"
|
||||
#include "core/pikabuffer.h"
|
||||
#include "core/pikadrawable-edit.h"
|
||||
#include "core/pikafilloptions.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimage-new.h"
|
||||
#include "core/pikaimage-undo.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikalayer-new.h"
|
||||
#include "core/pikalayermask.h"
|
||||
#include "core/pikapattern.h"
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "file/file-open.h"
|
||||
|
||||
#include "text/pikatext.h"
|
||||
#include "text/pikatextlayer.h"
|
||||
|
||||
#include "vectors/pikavectors.h"
|
||||
#include "vectors/pikavectors-import.h"
|
||||
|
||||
#include "widgets/pikadnd.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-dnd.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
|
||||
#include "pika-log.h"
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_shell_drop_drawable (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_vectors (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_svg (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
const guchar *svg_data,
|
||||
gsize svg_data_length,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_pattern (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_color (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
const PikaRGB *color,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_buffer (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_uri_list (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
GList *uri_list,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_component (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaImage *image,
|
||||
PikaChannelType component,
|
||||
gpointer data);
|
||||
static void pika_display_shell_drop_pixbuf (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
GdkPixbuf *pixbuf,
|
||||
gpointer data);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_dnd_init (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
pika_dnd_viewable_dest_add (shell->canvas, PIKA_TYPE_LAYER,
|
||||
pika_display_shell_drop_drawable,
|
||||
shell);
|
||||
pika_dnd_viewable_dest_add (shell->canvas, PIKA_TYPE_LAYER_MASK,
|
||||
pika_display_shell_drop_drawable,
|
||||
shell);
|
||||
pika_dnd_viewable_dest_add (shell->canvas, PIKA_TYPE_CHANNEL,
|
||||
pika_display_shell_drop_drawable,
|
||||
shell);
|
||||
pika_dnd_viewable_dest_add (shell->canvas, PIKA_TYPE_VECTORS,
|
||||
pika_display_shell_drop_vectors,
|
||||
shell);
|
||||
pika_dnd_viewable_dest_add (shell->canvas, PIKA_TYPE_PATTERN,
|
||||
pika_display_shell_drop_pattern,
|
||||
shell);
|
||||
pika_dnd_viewable_dest_add (shell->canvas, PIKA_TYPE_BUFFER,
|
||||
pika_display_shell_drop_buffer,
|
||||
shell);
|
||||
pika_dnd_color_dest_add (shell->canvas,
|
||||
pika_display_shell_drop_color,
|
||||
shell);
|
||||
pika_dnd_component_dest_add (shell->canvas,
|
||||
pika_display_shell_drop_component,
|
||||
shell);
|
||||
pika_dnd_uri_list_dest_add (shell->canvas,
|
||||
pika_display_shell_drop_uri_list,
|
||||
shell);
|
||||
pika_dnd_svg_dest_add (shell->canvas,
|
||||
pika_display_shell_drop_svg,
|
||||
shell);
|
||||
pika_dnd_pixbuf_dest_add (shell->canvas,
|
||||
pika_display_shell_drop_pixbuf,
|
||||
shell);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
/*
|
||||
* Position the dropped item in the middle of the viewport.
|
||||
*/
|
||||
static void
|
||||
pika_display_shell_dnd_position_item (PikaDisplayShell *shell,
|
||||
PikaImage *image,
|
||||
PikaItem *item)
|
||||
{
|
||||
gint item_width = pika_item_get_width (item);
|
||||
gint item_height = pika_item_get_height (item);
|
||||
gint off_x, off_y;
|
||||
|
||||
if (item_width >= pika_image_get_width (image) &&
|
||||
item_height >= pika_image_get_height (image))
|
||||
{
|
||||
off_x = (pika_image_get_width (image) - item_width) / 2;
|
||||
off_y = (pika_image_get_height (image) - item_height) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
gint x, y;
|
||||
gint width, height;
|
||||
|
||||
pika_display_shell_untransform_viewport (
|
||||
shell,
|
||||
! pika_display_shell_get_infinite_canvas (shell),
|
||||
&x, &y, &width, &height);
|
||||
|
||||
off_x = x + (width - item_width) / 2;
|
||||
off_y = y + (height - item_height) / 2;
|
||||
}
|
||||
|
||||
pika_item_translate (item,
|
||||
off_x - pika_item_get_offset_x (item),
|
||||
off_y - pika_item_get_offset_y (item),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_dnd_flush (PikaDisplayShell *shell,
|
||||
PikaImage *image)
|
||||
{
|
||||
pika_display_shell_present (shell);
|
||||
|
||||
pika_image_flush (image);
|
||||
|
||||
pika_context_set_display (pika_get_user_context (shell->display->pika),
|
||||
shell->display);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_drawable (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
GType new_type;
|
||||
PikaItem *new_item;
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! image)
|
||||
{
|
||||
image = pika_image_new_from_drawable (shell->display->pika,
|
||||
PIKA_DRAWABLE (viewable));
|
||||
pika_create_display (shell->display->pika, image, PIKA_UNIT_PIXEL, 1.0,
|
||||
G_OBJECT (pika_widget_get_monitor (widget)));
|
||||
g_object_unref (image);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (PIKA_IS_LAYER (viewable))
|
||||
new_type = G_TYPE_FROM_INSTANCE (viewable);
|
||||
else
|
||||
new_type = PIKA_TYPE_LAYER;
|
||||
|
||||
new_item = pika_item_convert (PIKA_ITEM (viewable), image, new_type);
|
||||
|
||||
if (new_item)
|
||||
{
|
||||
PikaLayer *new_layer = PIKA_LAYER (new_item);
|
||||
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_EDIT_PASTE,
|
||||
_("Drop New Layer"));
|
||||
|
||||
pika_display_shell_dnd_position_item (shell, image, new_item);
|
||||
|
||||
pika_item_set_visible (new_item, TRUE, FALSE);
|
||||
|
||||
pika_image_add_layer (image, new_layer,
|
||||
PIKA_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
||||
|
||||
pika_image_undo_group_end (image);
|
||||
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_vectors (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
PikaItem *new_item;
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! image)
|
||||
return;
|
||||
|
||||
new_item = pika_item_convert (PIKA_ITEM (viewable),
|
||||
image, G_TYPE_FROM_INSTANCE (viewable));
|
||||
|
||||
if (new_item)
|
||||
{
|
||||
PikaVectors *new_vectors = PIKA_VECTORS (new_item);
|
||||
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_EDIT_PASTE,
|
||||
_("Drop New Path"));
|
||||
|
||||
pika_image_add_vectors (image, new_vectors,
|
||||
PIKA_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
||||
|
||||
pika_image_undo_group_end (image);
|
||||
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_svg (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
const guchar *svg_data,
|
||||
gsize svg_data_len,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
GError *error = NULL;
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! image)
|
||||
return;
|
||||
|
||||
if (! pika_vectors_import_buffer (image,
|
||||
(const gchar *) svg_data, svg_data_len,
|
||||
TRUE, FALSE,
|
||||
PIKA_IMAGE_ACTIVE_PARENT, -1,
|
||||
NULL, &error))
|
||||
{
|
||||
pika_message_literal (shell->display->pika, G_OBJECT (shell->display),
|
||||
PIKA_MESSAGE_ERROR,
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_dnd_fill (PikaDisplayShell *shell,
|
||||
PikaFillOptions *options,
|
||||
const gchar *undo_desc)
|
||||
{
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
GList *drawables;
|
||||
GList *iter;
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! image)
|
||||
return;
|
||||
|
||||
drawables = pika_image_get_selected_drawables (image);
|
||||
|
||||
if (! drawables)
|
||||
return;
|
||||
|
||||
for (iter = drawables; iter; iter = iter->next)
|
||||
{
|
||||
if (pika_viewable_get_children (iter->data))
|
||||
{
|
||||
pika_message_literal (shell->display->pika, G_OBJECT (shell->display),
|
||||
PIKA_MESSAGE_ERROR,
|
||||
_("Cannot modify the pixels of layer groups."));
|
||||
g_list_free (drawables);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pika_item_is_content_locked (iter->data, NULL))
|
||||
{
|
||||
pika_message_literal (shell->display->pika, G_OBJECT (shell->display),
|
||||
PIKA_MESSAGE_ERROR,
|
||||
_("A selected layer's pixels are locked."));
|
||||
g_list_free (drawables);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_PAINT, undo_desc);
|
||||
|
||||
for (iter = drawables; iter; iter = iter->next)
|
||||
{
|
||||
/* FIXME: there should be a virtual method for this that the
|
||||
* PikaTextLayer can override.
|
||||
*/
|
||||
if (pika_item_is_text_layer (iter->data) &&
|
||||
(pika_fill_options_get_style (options) == PIKA_FILL_STYLE_FG_COLOR ||
|
||||
pika_fill_options_get_style (options) == PIKA_FILL_STYLE_BG_COLOR))
|
||||
{
|
||||
PikaRGB color;
|
||||
|
||||
if (pika_fill_options_get_style (options) == PIKA_FILL_STYLE_FG_COLOR)
|
||||
pika_context_get_foreground (PIKA_CONTEXT (options), &color);
|
||||
else
|
||||
pika_context_get_background (PIKA_CONTEXT (options), &color);
|
||||
|
||||
pika_text_layer_set (iter->data, NULL,
|
||||
"color", &color,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_drawable_edit_fill (iter->data, options, undo_desc);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (drawables);
|
||||
pika_image_undo_group_end (image);
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_pattern (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaFillOptions *options = pika_fill_options_new (shell->display->pika,
|
||||
NULL, FALSE);
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
pika_fill_options_set_style (options, PIKA_FILL_STYLE_PATTERN);
|
||||
pika_context_set_pattern (PIKA_CONTEXT (options), PIKA_PATTERN (viewable));
|
||||
|
||||
pika_display_shell_dnd_fill (shell, options,
|
||||
C_("undo-type", "Drop pattern to layer"));
|
||||
|
||||
g_object_unref (options);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_color (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
const PikaRGB *color,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaFillOptions *options = pika_fill_options_new (shell->display->pika,
|
||||
NULL, FALSE);
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
pika_fill_options_set_style (options, PIKA_FILL_STYLE_FG_COLOR);
|
||||
pika_context_set_foreground (PIKA_CONTEXT (options), color);
|
||||
|
||||
pika_display_shell_dnd_fill (shell, options,
|
||||
C_("undo-type", "Drop color to layer"));
|
||||
|
||||
g_object_unref (options);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_buffer (GtkWidget *widget,
|
||||
gint drop_x,
|
||||
gint drop_y,
|
||||
PikaViewable *viewable,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
PikaContext *context;
|
||||
GList *drawables;
|
||||
PikaBuffer *buffer;
|
||||
PikaPasteType paste_type;
|
||||
gint x, y, width, height;
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! image)
|
||||
{
|
||||
image = pika_image_new_from_buffer (shell->display->pika,
|
||||
PIKA_BUFFER (viewable));
|
||||
pika_create_display (image->pika, image, PIKA_UNIT_PIXEL, 1.0,
|
||||
G_OBJECT (pika_widget_get_monitor (widget)));
|
||||
g_object_unref (image);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
paste_type = PIKA_PASTE_TYPE_NEW_LAYER_OR_FLOATING;
|
||||
drawables = pika_image_get_selected_drawables (image);
|
||||
context = pika_get_user_context (shell->display->pika);
|
||||
buffer = PIKA_BUFFER (viewable);
|
||||
|
||||
pika_display_shell_untransform_viewport (
|
||||
shell,
|
||||
! pika_display_shell_get_infinite_canvas (shell),
|
||||
&x, &y, &width, &height);
|
||||
|
||||
/* FIXME: popup a menu for selecting "Paste Into" */
|
||||
|
||||
g_list_free (pika_edit_paste (image, drawables, PIKA_OBJECT (buffer),
|
||||
paste_type, context, FALSE,
|
||||
x, y, width, height));
|
||||
|
||||
g_list_free (drawables);
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_uri_list (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
GList *uri_list,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *image;
|
||||
PikaContext *context;
|
||||
GList *list;
|
||||
gboolean open_as_layers;
|
||||
|
||||
/* If the app is already being torn down, shell->display might be
|
||||
* NULL here. Play it safe.
|
||||
*/
|
||||
if (! shell->display)
|
||||
return;
|
||||
|
||||
image = pika_display_get_image (shell->display);
|
||||
context = pika_get_user_context (shell->display->pika);
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
open_as_layers = (image != NULL);
|
||||
|
||||
if (image)
|
||||
g_object_ref (image);
|
||||
|
||||
for (list = uri_list; list; list = g_list_next (list))
|
||||
{
|
||||
GFile *file = g_file_new_for_uri (list->data);
|
||||
PikaPDBStatusType status;
|
||||
GError *error = NULL;
|
||||
gboolean warn = FALSE;
|
||||
|
||||
if (! shell->display)
|
||||
{
|
||||
/* It seems as if PIKA is being torn down for quitting. Bail out. */
|
||||
g_object_unref (file);
|
||||
g_clear_object (&image);
|
||||
return;
|
||||
}
|
||||
|
||||
if (open_as_layers)
|
||||
{
|
||||
GList *new_layers;
|
||||
|
||||
new_layers = file_open_layers (shell->display->pika, context,
|
||||
PIKA_PROGRESS (shell->display),
|
||||
image, FALSE,
|
||||
file, PIKA_RUN_INTERACTIVE, NULL,
|
||||
&status, &error);
|
||||
|
||||
if (new_layers)
|
||||
{
|
||||
gint x = 0;
|
||||
gint y = 0;
|
||||
gint width = pika_image_get_width (image);
|
||||
gint height = pika_image_get_height (image);
|
||||
|
||||
if (pika_display_get_image (shell->display))
|
||||
{
|
||||
pika_display_shell_untransform_viewport (
|
||||
shell,
|
||||
! pika_display_shell_get_infinite_canvas (shell),
|
||||
&x, &y, &width, &height);
|
||||
}
|
||||
|
||||
pika_image_add_layers (image, new_layers,
|
||||
PIKA_IMAGE_ACTIVE_PARENT, -1,
|
||||
x, y, width, height,
|
||||
_("Drop layers"));
|
||||
|
||||
g_list_free (new_layers);
|
||||
}
|
||||
else if (status != PIKA_PDB_CANCEL && status != PIKA_PDB_SUCCESS)
|
||||
{
|
||||
warn = TRUE;
|
||||
}
|
||||
}
|
||||
else if (pika_display_get_image (shell->display))
|
||||
{
|
||||
/* open any subsequent images in a new display */
|
||||
PikaImage *new_image;
|
||||
|
||||
new_image = file_open_with_display (shell->display->pika, context,
|
||||
NULL,
|
||||
file, FALSE,
|
||||
G_OBJECT (pika_widget_get_monitor (widget)),
|
||||
&status, &error);
|
||||
|
||||
if (! new_image && status != PIKA_PDB_CANCEL && status != PIKA_PDB_SUCCESS)
|
||||
warn = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* open the first image in the empty display */
|
||||
image = file_open_with_display (shell->display->pika, context,
|
||||
PIKA_PROGRESS (shell->display),
|
||||
file, FALSE,
|
||||
G_OBJECT (pika_widget_get_monitor (widget)),
|
||||
&status, &error);
|
||||
|
||||
if (image)
|
||||
{
|
||||
g_object_ref (image);
|
||||
}
|
||||
else if (status != PIKA_PDB_CANCEL && status != PIKA_PDB_SUCCESS)
|
||||
{
|
||||
warn = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Something above might have run a few rounds of the main loop. Check
|
||||
* that shell->display is still there, otherwise ignore this as the app
|
||||
* is being torn down for quitting.
|
||||
*/
|
||||
if (warn && shell->display)
|
||||
{
|
||||
pika_message (shell->display->pika, G_OBJECT (shell->display),
|
||||
PIKA_MESSAGE_ERROR,
|
||||
_("Opening '%s' failed:\n\n%s"),
|
||||
pika_file_get_utf8_name (file), error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
if (image)
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
|
||||
g_clear_object (&image);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_component (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
PikaImage *image,
|
||||
PikaChannelType component,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *dest_image = pika_display_get_image (shell->display);
|
||||
PikaChannel *channel;
|
||||
PikaItem *new_item;
|
||||
const gchar *desc;
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! dest_image)
|
||||
{
|
||||
dest_image = pika_image_new_from_component (image->pika,
|
||||
image, component);
|
||||
pika_create_display (dest_image->pika, dest_image, PIKA_UNIT_PIXEL, 1.0,
|
||||
G_OBJECT (pika_widget_get_monitor (widget)));
|
||||
g_object_unref (dest_image);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
channel = pika_channel_new_from_component (image, component, NULL, NULL);
|
||||
|
||||
new_item = pika_item_convert (PIKA_ITEM (channel),
|
||||
dest_image, PIKA_TYPE_LAYER);
|
||||
g_object_unref (channel);
|
||||
|
||||
if (new_item)
|
||||
{
|
||||
PikaLayer *new_layer = PIKA_LAYER (new_item);
|
||||
|
||||
pika_enum_get_value (PIKA_TYPE_CHANNEL_TYPE, component,
|
||||
NULL, NULL, &desc, NULL);
|
||||
pika_object_take_name (PIKA_OBJECT (new_layer),
|
||||
g_strdup_printf (_("%s Channel Copy"), desc));
|
||||
|
||||
pika_image_undo_group_start (dest_image, PIKA_UNDO_GROUP_EDIT_PASTE,
|
||||
_("Drop New Layer"));
|
||||
|
||||
pika_display_shell_dnd_position_item (shell, image, new_item);
|
||||
|
||||
pika_image_add_layer (dest_image, new_layer,
|
||||
PIKA_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
||||
|
||||
pika_image_undo_group_end (dest_image);
|
||||
|
||||
pika_display_shell_dnd_flush (shell, dest_image);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_drop_pixbuf (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
GdkPixbuf *pixbuf,
|
||||
gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (data);
|
||||
PikaImage *image = pika_display_get_image (shell->display);
|
||||
PikaLayer *new_layer;
|
||||
gboolean has_alpha = FALSE;
|
||||
|
||||
PIKA_LOG (DND, NULL);
|
||||
|
||||
if (shell->display->pika->busy)
|
||||
return;
|
||||
|
||||
if (! image)
|
||||
{
|
||||
image = pika_image_new_from_pixbuf (shell->display->pika, pixbuf,
|
||||
_("Dropped Buffer"));
|
||||
pika_create_display (image->pika, image, PIKA_UNIT_PIXEL, 1.0,
|
||||
G_OBJECT (pika_widget_get_monitor (widget)));
|
||||
g_object_unref (image);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_pixbuf_get_n_channels (pixbuf) == 2 ||
|
||||
gdk_pixbuf_get_n_channels (pixbuf) == 4)
|
||||
{
|
||||
has_alpha = TRUE;
|
||||
}
|
||||
|
||||
new_layer =
|
||||
pika_layer_new_from_pixbuf (pixbuf, image,
|
||||
pika_image_get_layer_format (image, has_alpha),
|
||||
_("Dropped Buffer"),
|
||||
PIKA_OPACITY_OPAQUE,
|
||||
pika_image_get_default_new_layer_mode (image));
|
||||
|
||||
if (new_layer)
|
||||
{
|
||||
PikaItem *new_item = PIKA_ITEM (new_layer);
|
||||
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_EDIT_PASTE,
|
||||
_("Drop New Layer"));
|
||||
|
||||
pika_display_shell_dnd_position_item (shell, image, new_item);
|
||||
|
||||
pika_image_add_layer (image, new_layer,
|
||||
PIKA_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
||||
|
||||
pika_image_undo_group_end (image);
|
||||
|
||||
pika_display_shell_dnd_flush (shell, image);
|
||||
}
|
||||
}
|
||||
29
app/display/pikadisplayshell-dnd.h
Normal file
29
app/display/pikadisplayshell-dnd.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_DND_H__
|
||||
#define __PIKA_DISPLAY_SHELL_DND_H__
|
||||
|
||||
|
||||
void pika_display_shell_dnd_init (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_DND_H__ */
|
||||
248
app/display/pikadisplayshell-draw.c
Normal file
248
app/display/pikadisplayshell-draw.c
Normal file
@ -0,0 +1,248 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika-cairo.h"
|
||||
#include "core/pika-utils.h"
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "pikacanvas.h"
|
||||
#include "pikacanvas-style.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-draw.h"
|
||||
#include "pikadisplayshell-render.h"
|
||||
|
||||
#include "widgets/pikarender.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_draw_selection_out (PikaDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
PikaSegment *segs,
|
||||
gint n_segs)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (segs != NULL && n_segs > 0);
|
||||
|
||||
pika_canvas_set_selection_out_style (shell->canvas, cr,
|
||||
shell->offset_x, shell->offset_y);
|
||||
|
||||
pika_cairo_segments (cr, segs, n_segs);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_draw_selection_in (PikaDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
cairo_pattern_t *mask,
|
||||
gint index)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (mask != NULL);
|
||||
|
||||
pika_canvas_set_selection_in_style (shell->canvas, cr, index,
|
||||
shell->offset_x, shell->offset_y);
|
||||
|
||||
cairo_mask (cr, mask);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_draw_background (PikaDisplayShell *shell,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaCanvas *canvas;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
canvas = PIKA_CANVAS (shell->canvas);
|
||||
|
||||
if (canvas->padding_mode != PIKA_CANVAS_PADDING_MODE_DEFAULT)
|
||||
{
|
||||
pika_cairo_set_source_rgb (cr, &canvas->padding_color);
|
||||
cairo_paint (cr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_draw_checkerboard (PikaDisplayShell *shell,
|
||||
cairo_t *cr)
|
||||
{
|
||||
PikaImage *image;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
image = pika_display_get_image (shell->display);
|
||||
|
||||
if (G_UNLIKELY (! shell->checkerboard))
|
||||
{
|
||||
PikaCheckSize check_size;
|
||||
|
||||
g_object_get (shell->display->config,
|
||||
"transparency-size", &check_size,
|
||||
NULL);
|
||||
|
||||
shell->checkerboard =
|
||||
pika_cairo_checkerboard_create (cr,
|
||||
1 << (check_size + 2),
|
||||
pika_render_check_color1 (),
|
||||
pika_render_check_color2 ());
|
||||
}
|
||||
|
||||
cairo_translate (cr, - shell->offset_x, - shell->offset_y);
|
||||
|
||||
if (pika_image_get_component_visible (image, PIKA_CHANNEL_ALPHA))
|
||||
cairo_set_source (cr, shell->checkerboard);
|
||||
else
|
||||
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
||||
|
||||
cairo_paint (cr);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_draw_image (PikaDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h)
|
||||
{
|
||||
gdouble chunk_width;
|
||||
gdouble chunk_height;
|
||||
gdouble scale = 1.0;
|
||||
gint n_rows;
|
||||
gint n_cols;
|
||||
gint r, c;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (pika_display_get_image (shell->display));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
/* display the image in RENDER_BUF_WIDTH x RENDER_BUF_HEIGHT
|
||||
* maximally-sized image-space chunks. adjust the screen-space
|
||||
* chunk size as necessary, to accommodate for the display
|
||||
* transform and window scale factor.
|
||||
*/
|
||||
chunk_width = shell->render_buf_width;
|
||||
chunk_height = shell->render_buf_height;
|
||||
|
||||
/* multiply the image scale-factor by the window scale-factor, and divide
|
||||
* the cairo scale-factor by the same amount (further down), so that we make
|
||||
* full use of the screen resolution, even on hidpi displays.
|
||||
*/
|
||||
scale *= shell->render_scale;
|
||||
|
||||
scale *= MAX (shell->scale_x, shell->scale_y);
|
||||
|
||||
if (scale != shell->scale_x)
|
||||
chunk_width = (chunk_width - 1.0) * (shell->scale_x / scale);
|
||||
if (scale != shell->scale_y)
|
||||
chunk_height = (chunk_height - 1.0) * (shell->scale_y / scale);
|
||||
|
||||
if (shell->rotate_untransform)
|
||||
{
|
||||
gdouble a = shell->rotate_angle * G_PI / 180.0;
|
||||
|
||||
chunk_width = chunk_height = (MIN (chunk_width, chunk_height) - 1.0) /
|
||||
(fabs (sin (a)) + fabs (cos (a)));
|
||||
}
|
||||
|
||||
/* divide the painted area to evenly-sized chunks */
|
||||
n_rows = ceil (h / floor (chunk_height));
|
||||
n_cols = ceil (w / floor (chunk_width));
|
||||
|
||||
for (r = 0; r < n_rows; r++)
|
||||
{
|
||||
gint y1 = y + (2 * r * h + n_rows) / (2 * n_rows);
|
||||
gint y2 = y + (2 * (r + 1) * h + n_rows) / (2 * n_rows);
|
||||
|
||||
for (c = 0; c < n_cols; c++)
|
||||
{
|
||||
gint x1 = x + (2 * c * w + n_cols) / (2 * n_cols);
|
||||
gint x2 = x + (2 * (c + 1) * w + n_cols) / (2 * n_cols);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
/* clip to chunk bounds, in screen space */
|
||||
cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1);
|
||||
cairo_clip (cr);
|
||||
|
||||
if (! pika_display_shell_render_is_valid (shell,
|
||||
x1, y1, x2 - x1, y2 - y1))
|
||||
{
|
||||
/* render image to the render cache */
|
||||
pika_display_shell_render (shell, cr,
|
||||
x1, y1, x2 - x1, y2 - y1,
|
||||
scale);
|
||||
|
||||
pika_display_shell_render_validate_area (shell,
|
||||
x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
/* divide the cairo scale-factor by the window scale-factor, since
|
||||
* the render cache uses device pixels. see comment further up.
|
||||
*/
|
||||
cairo_scale (cr,
|
||||
1.0 / shell->render_scale,
|
||||
1.0 / shell->render_scale);
|
||||
|
||||
/* render from the render cache to screen */
|
||||
cairo_set_source_surface (cr, shell->render_cache, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
/* if the PIKA_BRICK_WALL environment variable is defined,
|
||||
* show chunk bounds
|
||||
*/
|
||||
{
|
||||
static gint brick_wall = -1;
|
||||
|
||||
if (brick_wall < 0)
|
||||
brick_wall = (g_getenv ("PIKA_BRICK_WALL") != NULL);
|
||||
|
||||
if (brick_wall)
|
||||
{
|
||||
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
||||
cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
app/display/pikadisplayshell-draw.h
Normal file
47
app/display/pikadisplayshell-draw.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_DRAW_H__
|
||||
#define __PIKA_DISPLAY_SHELL_DRAW_H__
|
||||
|
||||
|
||||
void pika_display_shell_draw_selection_out (PikaDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
PikaSegment *segs,
|
||||
gint n_segs);
|
||||
void pika_display_shell_draw_selection_in (PikaDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
cairo_pattern_t *mask,
|
||||
gint index);
|
||||
|
||||
void pika_display_shell_draw_background (PikaDisplayShell *shell,
|
||||
cairo_t *cr);
|
||||
void pika_display_shell_draw_checkerboard (PikaDisplayShell *shell,
|
||||
cairo_t *cr);
|
||||
void pika_display_shell_draw_image (PikaDisplayShell *shell,
|
||||
cairo_t *cr,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_DRAW_H__ */
|
||||
65
app/display/pikadisplayshell-expose.c
Normal file
65
app/display/pikadisplayshell-expose.c
Normal file
@ -0,0 +1,65 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-expose.h"
|
||||
|
||||
|
||||
void
|
||||
pika_display_shell_expose_area (PikaDisplayShell *shell,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
gtk_widget_queue_draw_area (shell->canvas, x, y, w, h);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_expose_region (PikaDisplayShell *shell,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (region != NULL);
|
||||
|
||||
if (! gtk_widget_get_realized (shell->canvas))
|
||||
return;
|
||||
|
||||
gdk_window_invalidate_region (gtk_widget_get_window (shell->canvas),
|
||||
region, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_expose_full (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
gtk_widget_queue_draw (shell->canvas);
|
||||
}
|
||||
36
app/display/pikadisplayshell-expose.h
Normal file
36
app/display/pikadisplayshell-expose.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_EXPOSE_H__
|
||||
#define __PIKA_DISPLAY_SHELL_EXPOSE_H__
|
||||
|
||||
|
||||
void pika_display_shell_expose_area (PikaDisplayShell *shell,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h);
|
||||
void pika_display_shell_expose_region (PikaDisplayShell *shell,
|
||||
cairo_region_t *region);
|
||||
void pika_display_shell_expose_full (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_EXPOSE_H__ */
|
||||
155
app/display/pikadisplayshell-filter-dialog.c
Normal file
155
app/display/pikadisplayshell-filter-dialog.c
Normal file
@ -0,0 +1,155 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1999 Manish Singh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikaviewable.h"
|
||||
|
||||
#include "widgets/pikacolordisplayeditor.h"
|
||||
#include "widgets/pikahelp-ids.h"
|
||||
#include "widgets/pikaviewabledialog.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-filter.h"
|
||||
#include "pikadisplayshell-filter-dialog.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaDisplayShell *shell;
|
||||
GtkWidget *dialog;
|
||||
|
||||
PikaColorDisplayStack *old_stack;
|
||||
} ColorDisplayDialog;
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_shell_filter_dialog_response (GtkWidget *widget,
|
||||
gint response_id,
|
||||
ColorDisplayDialog *cdd);
|
||||
|
||||
static void pika_display_shell_filter_dialog_free (ColorDisplayDialog *cdd);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
GtkWidget *
|
||||
pika_display_shell_filter_dialog_new (PikaDisplayShell *shell)
|
||||
{
|
||||
PikaImage *image;
|
||||
ColorDisplayDialog *cdd;
|
||||
GtkWidget *editor;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
|
||||
|
||||
image = pika_display_get_image (shell->display);
|
||||
|
||||
cdd = g_slice_new0 (ColorDisplayDialog);
|
||||
|
||||
cdd->shell = shell;
|
||||
cdd->dialog = pika_viewable_dialog_new (g_list_prepend (NULL, image),
|
||||
pika_get_user_context (shell->display->pika),
|
||||
_("Color Display Filters"),
|
||||
"pika-display-filters",
|
||||
PIKA_ICON_DISPLAY_FILTER,
|
||||
_("Configure Color Display Filters"),
|
||||
GTK_WIDGET (cdd->shell),
|
||||
pika_standard_help_func,
|
||||
PIKA_HELP_DISPLAY_FILTER_DIALOG,
|
||||
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_OK"), GTK_RESPONSE_OK,
|
||||
|
||||
NULL);
|
||||
|
||||
pika_dialog_set_alternative_button_order (GTK_DIALOG (cdd->dialog),
|
||||
GTK_RESPONSE_OK,
|
||||
GTK_RESPONSE_CANCEL,
|
||||
-1);
|
||||
|
||||
gtk_window_set_destroy_with_parent (GTK_WINDOW (cdd->dialog), TRUE);
|
||||
|
||||
g_object_weak_ref (G_OBJECT (cdd->dialog),
|
||||
(GWeakNotify) pika_display_shell_filter_dialog_free, cdd);
|
||||
|
||||
g_signal_connect (cdd->dialog, "response",
|
||||
G_CALLBACK (pika_display_shell_filter_dialog_response),
|
||||
cdd);
|
||||
|
||||
if (shell->filter_stack)
|
||||
{
|
||||
cdd->old_stack = pika_color_display_stack_clone (shell->filter_stack);
|
||||
|
||||
g_object_weak_ref (G_OBJECT (cdd->dialog),
|
||||
(GWeakNotify) g_object_unref, cdd->old_stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaColorDisplayStack *stack = pika_color_display_stack_new ();
|
||||
|
||||
pika_display_shell_filter_set (shell, stack);
|
||||
g_object_unref (stack);
|
||||
}
|
||||
|
||||
editor = pika_color_display_editor_new (shell->display->pika,
|
||||
shell->filter_stack,
|
||||
pika_display_shell_get_color_config (shell),
|
||||
PIKA_COLOR_MANAGED (shell));
|
||||
gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (cdd->dialog))),
|
||||
editor, TRUE, TRUE, 0);
|
||||
gtk_widget_show (editor);
|
||||
|
||||
return cdd->dialog;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_display_shell_filter_dialog_response (GtkWidget *widget,
|
||||
gint response_id,
|
||||
ColorDisplayDialog *cdd)
|
||||
{
|
||||
if (response_id != GTK_RESPONSE_OK)
|
||||
pika_display_shell_filter_set (cdd->shell, cdd->old_stack);
|
||||
|
||||
gtk_widget_destroy (GTK_WIDGET (cdd->dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_filter_dialog_free (ColorDisplayDialog *cdd)
|
||||
{
|
||||
g_slice_free (ColorDisplayDialog, cdd);
|
||||
}
|
||||
29
app/display/pikadisplayshell-filter-dialog.h
Normal file
29
app/display/pikadisplayshell-filter-dialog.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1999 Manish Singh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_FILTER_DIALOG_H__
|
||||
#define __PIKA_DISPLAY_SHELL_FILTER_DIALOG_H__
|
||||
|
||||
|
||||
GtkWidget * pika_display_shell_filter_dialog_new (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_FILTER_DIALOG_H__ */
|
||||
125
app/display/pikadisplayshell-filter.c
Normal file
125
app/display/pikadisplayshell-filter.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* 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) 1999 Manish Singh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikawidgets/pikawidgets.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-expose.h"
|
||||
#include "pikadisplayshell-filter.h"
|
||||
#include "pikadisplayshell-profile.h"
|
||||
#include "pikadisplayshell-render.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_shell_filter_changed (PikaColorDisplayStack *stack,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_filter_set (PikaDisplayShell *shell,
|
||||
PikaColorDisplayStack *stack)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (stack == NULL || PIKA_IS_COLOR_DISPLAY_STACK (stack));
|
||||
|
||||
if (stack == shell->filter_stack)
|
||||
return;
|
||||
|
||||
if (shell->filter_stack)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (shell->filter_stack,
|
||||
pika_display_shell_filter_changed,
|
||||
shell);
|
||||
}
|
||||
|
||||
g_set_object (&shell->filter_stack, stack);
|
||||
|
||||
if (shell->filter_stack)
|
||||
{
|
||||
g_signal_connect (shell->filter_stack, "changed",
|
||||
G_CALLBACK (pika_display_shell_filter_changed),
|
||||
shell);
|
||||
}
|
||||
|
||||
pika_display_shell_filter_changed (NULL, shell);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_has_filter (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
|
||||
if (shell->filter_stack)
|
||||
{
|
||||
GList *filters;
|
||||
GList *iter;
|
||||
|
||||
filters = pika_color_display_stack_get_filters (shell->filter_stack);
|
||||
|
||||
for (iter = filters; iter; iter = g_list_next (iter))
|
||||
{
|
||||
if (pika_color_display_get_enabled (PIKA_COLOR_DISPLAY (iter->data)))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static gboolean
|
||||
pika_display_shell_filter_changed_idle (gpointer data)
|
||||
{
|
||||
PikaDisplayShell *shell = data;
|
||||
|
||||
pika_display_shell_profile_update (shell);
|
||||
pika_display_shell_expose_full (shell);
|
||||
pika_display_shell_render_invalidate_full (shell);
|
||||
|
||||
shell->filter_idle_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_filter_changed (PikaColorDisplayStack *stack,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (shell->filter_idle_id)
|
||||
g_source_remove (shell->filter_idle_id);
|
||||
|
||||
shell->filter_idle_id =
|
||||
g_idle_add_full (G_PRIORITY_LOW,
|
||||
pika_display_shell_filter_changed_idle,
|
||||
shell, NULL);
|
||||
}
|
||||
32
app/display/pikadisplayshell-filter.h
Normal file
32
app/display/pikadisplayshell-filter.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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) 1999 Manish Singh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_FILTER_H__
|
||||
#define __PIKA_DISPLAY_SHELL_FILTER_H__
|
||||
|
||||
|
||||
void pika_display_shell_filter_set (PikaDisplayShell *shell,
|
||||
PikaColorDisplayStack *stack);
|
||||
|
||||
gboolean pika_display_shell_has_filter (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_FILTER_H__ */
|
||||
122
app/display/pikadisplayshell-grab.c
Normal file
122
app/display/pikadisplayshell-grab.c
Normal file
@ -0,0 +1,122 @@
|
||||
/* 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
|
||||
*
|
||||
* pikadisplayshell-grab.c
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "widgets/pikadevices.h"
|
||||
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-grab.h"
|
||||
|
||||
|
||||
static GdkDevice *
|
||||
get_associated_pointer (GdkDevice *device)
|
||||
{
|
||||
switch (gdk_device_get_device_type (device))
|
||||
{
|
||||
case GDK_DEVICE_TYPE_SLAVE:
|
||||
device = gdk_device_get_associated_device (device);
|
||||
break;
|
||||
|
||||
case GDK_DEVICE_TYPE_FLOATING:
|
||||
{
|
||||
GdkDisplay *display = gdk_device_get_display (device);
|
||||
GdkSeat *seat = gdk_display_get_default_seat (display);
|
||||
|
||||
return gdk_seat_get_pointer (seat);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
device = gdk_device_get_associated_device (device);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_display_shell_pointer_grab (PikaDisplayShell *shell,
|
||||
const GdkEvent *event,
|
||||
GdkEventMask event_mask)
|
||||
{
|
||||
GdkDevice *device;
|
||||
GdkDevice *source_device;
|
||||
GdkGrabStatus status;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
g_return_val_if_fail (event != NULL, FALSE);
|
||||
g_return_val_if_fail (shell->grab_pointer == NULL, FALSE);
|
||||
|
||||
source_device = pika_devices_get_from_event (shell->display->pika,
|
||||
event, &device);
|
||||
|
||||
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
{
|
||||
device = get_associated_pointer (device);
|
||||
source_device = NULL;
|
||||
}
|
||||
|
||||
status = gdk_device_grab (device,
|
||||
gtk_widget_get_window (shell->canvas),
|
||||
GDK_OWNERSHIP_APPLICATION,
|
||||
FALSE, event_mask, NULL,
|
||||
gdk_event_get_time (event));
|
||||
|
||||
if (status == GDK_GRAB_SUCCESS)
|
||||
{
|
||||
shell->grab_pointer = device;
|
||||
shell->grab_pointer_source = source_device;
|
||||
shell->grab_pointer_time = gdk_event_get_time (event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_printerr ("%s: gdk_device_grab(%s) failed with status %d\n",
|
||||
G_STRFUNC, gdk_device_get_name (device), status);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_pointer_ungrab (PikaDisplayShell *shell,
|
||||
const GdkEvent *event)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (event != NULL);
|
||||
g_return_if_fail (shell->grab_pointer != NULL);
|
||||
|
||||
gdk_device_ungrab (shell->grab_pointer, shell->grab_pointer_time);
|
||||
|
||||
shell->grab_pointer = NULL;
|
||||
shell->grab_pointer_source = NULL;
|
||||
shell->grab_pointer_time = 0;
|
||||
}
|
||||
35
app/display/pikadisplayshell-grab.h
Normal file
35
app/display/pikadisplayshell-grab.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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
|
||||
*
|
||||
* pikadisplayshell-grab.h
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_GRAB_H__
|
||||
#define __PIKA_DISPLAY_SHELL_GRAB_H__
|
||||
|
||||
|
||||
gboolean pika_display_shell_pointer_grab (PikaDisplayShell *shell,
|
||||
const GdkEvent *event,
|
||||
GdkEventMask event_mask);
|
||||
void pika_display_shell_pointer_ungrab (PikaDisplayShell *shell,
|
||||
const GdkEvent *event);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_GRAB_H__ */
|
||||
1246
app/display/pikadisplayshell-handlers.c
Normal file
1246
app/display/pikadisplayshell-handlers.c
Normal file
File diff suppressed because it is too large
Load Diff
30
app/display/pikadisplayshell-handlers.h
Normal file
30
app/display/pikadisplayshell-handlers.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_HANDLERS_H__
|
||||
#define __PIKA_DISPLAY_SHELL_HANDLERS_H__
|
||||
|
||||
|
||||
void pika_display_shell_connect (PikaDisplayShell *shell);
|
||||
void pika_display_shell_disconnect (PikaDisplayShell *shell);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_HANDLERS_H__ */
|
||||
288
app/display/pikadisplayshell-items.c
Normal file
288
app/display/pikadisplayshell-items.c
Normal file
@ -0,0 +1,288 @@
|
||||
/* 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
|
||||
*
|
||||
* pikadisplayshell-items.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <libpikamath/pikamath.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "pikacanvascanvasboundary.h"
|
||||
#include "pikacanvascursor.h"
|
||||
#include "pikacanvasgrid.h"
|
||||
#include "pikacanvaslayerboundary.h"
|
||||
#include "pikacanvaspassepartout.h"
|
||||
#include "pikacanvasproxygroup.h"
|
||||
#include "pikadisplayshell.h"
|
||||
#include "pikadisplayshell-expose.h"
|
||||
#include "pikadisplayshell-items.h"
|
||||
#include "pikadisplayshell-transform.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_display_shell_item_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region,
|
||||
PikaDisplayShell *shell);
|
||||
static void pika_display_shell_unrotated_item_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region,
|
||||
PikaDisplayShell *shell);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_display_shell_items_init (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
shell->canvas_item = pika_canvas_group_new (shell);
|
||||
|
||||
shell->passe_partout = pika_canvas_passe_partout_new (shell, 0, 0, 0, 0);
|
||||
pika_canvas_item_set_visible (shell->passe_partout, FALSE);
|
||||
pika_display_shell_add_item (shell, shell->passe_partout);
|
||||
g_object_unref (shell->passe_partout);
|
||||
|
||||
shell->preview_items = pika_canvas_group_new (shell);
|
||||
pika_display_shell_add_item (shell, shell->preview_items);
|
||||
g_object_unref (shell->preview_items);
|
||||
|
||||
shell->vectors = pika_canvas_proxy_group_new (shell);
|
||||
pika_display_shell_add_item (shell, shell->vectors);
|
||||
g_object_unref (shell->vectors);
|
||||
|
||||
shell->grid = pika_canvas_grid_new (shell, NULL);
|
||||
pika_canvas_item_set_visible (shell->grid, FALSE);
|
||||
g_object_set (shell->grid, "grid-style", TRUE, NULL);
|
||||
pika_display_shell_add_item (shell, shell->grid);
|
||||
g_object_unref (shell->grid);
|
||||
|
||||
shell->guides = pika_canvas_proxy_group_new (shell);
|
||||
pika_display_shell_add_item (shell, shell->guides);
|
||||
g_object_unref (shell->guides);
|
||||
|
||||
shell->sample_points = pika_canvas_proxy_group_new (shell);
|
||||
pika_display_shell_add_item (shell, shell->sample_points);
|
||||
g_object_unref (shell->sample_points);
|
||||
|
||||
shell->canvas_boundary = pika_canvas_canvas_boundary_new (shell);
|
||||
pika_canvas_item_set_visible (shell->canvas_boundary, FALSE);
|
||||
pika_display_shell_add_item (shell, shell->canvas_boundary);
|
||||
g_object_unref (shell->canvas_boundary);
|
||||
|
||||
shell->layer_boundary = pika_canvas_layer_boundary_new (shell);
|
||||
pika_canvas_item_set_visible (shell->layer_boundary, FALSE);
|
||||
pika_display_shell_add_item (shell, shell->layer_boundary);
|
||||
g_object_unref (shell->layer_boundary);
|
||||
|
||||
shell->tool_items = pika_canvas_group_new (shell);
|
||||
pika_display_shell_add_item (shell, shell->tool_items);
|
||||
g_object_unref (shell->tool_items);
|
||||
|
||||
g_signal_connect (shell->canvas_item, "update",
|
||||
G_CALLBACK (pika_display_shell_item_update),
|
||||
shell);
|
||||
|
||||
shell->unrotated_item = pika_canvas_group_new (shell);
|
||||
|
||||
shell->cursor = pika_canvas_cursor_new (shell);
|
||||
pika_canvas_item_set_visible (shell->cursor, FALSE);
|
||||
pika_display_shell_add_unrotated_item (shell, shell->cursor);
|
||||
g_object_unref (shell->cursor);
|
||||
|
||||
g_signal_connect (shell->unrotated_item, "update",
|
||||
G_CALLBACK (pika_display_shell_unrotated_item_update),
|
||||
shell);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_items_free (PikaDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
if (shell->canvas_item)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (shell->canvas_item,
|
||||
pika_display_shell_item_update,
|
||||
shell);
|
||||
|
||||
g_clear_object (&shell->canvas_item);
|
||||
|
||||
shell->passe_partout = NULL;
|
||||
shell->preview_items = NULL;
|
||||
shell->vectors = NULL;
|
||||
shell->grid = NULL;
|
||||
shell->guides = NULL;
|
||||
shell->sample_points = NULL;
|
||||
shell->canvas_boundary = NULL;
|
||||
shell->layer_boundary = NULL;
|
||||
shell->tool_items = NULL;
|
||||
}
|
||||
|
||||
if (shell->unrotated_item)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (shell->unrotated_item,
|
||||
pika_display_shell_unrotated_item_update,
|
||||
shell);
|
||||
|
||||
g_clear_object (&shell->unrotated_item);
|
||||
|
||||
shell->cursor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_add_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_add_item (PIKA_CANVAS_GROUP (shell->canvas_item), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_remove_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_remove_item (PIKA_CANVAS_GROUP (shell->canvas_item), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_add_preview_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_add_item (PIKA_CANVAS_GROUP (shell->preview_items), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_remove_preview_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_remove_item (PIKA_CANVAS_GROUP (shell->preview_items), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_add_unrotated_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_add_item (PIKA_CANVAS_GROUP (shell->unrotated_item), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_remove_unrotated_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_remove_item (PIKA_CANVAS_GROUP (shell->unrotated_item), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_add_tool_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_add_item (PIKA_CANVAS_GROUP (shell->tool_items), item);
|
||||
}
|
||||
|
||||
void
|
||||
pika_display_shell_remove_tool_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (PIKA_IS_CANVAS_ITEM (item));
|
||||
|
||||
pika_canvas_group_remove_item (PIKA_CANVAS_GROUP (shell->tool_items), item);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_display_shell_item_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
if (shell->rotate_transform)
|
||||
{
|
||||
gint n_rects;
|
||||
gint i;
|
||||
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gint x1, y1, x2, y2;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
|
||||
pika_display_shell_rotate_bounds (shell,
|
||||
rect.x, rect.y,
|
||||
rect.x + rect.width,
|
||||
rect.y + rect.height,
|
||||
&tx1, &ty1, &tx2, &ty2);
|
||||
|
||||
x1 = floor (tx1 - 0.5);
|
||||
y1 = floor (ty1 - 0.5);
|
||||
x2 = ceil (tx2 + 0.5);
|
||||
y2 = ceil (ty2 + 0.5);
|
||||
|
||||
pika_display_shell_expose_area (shell, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_display_shell_expose_region (shell, region);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_display_shell_unrotated_item_update (PikaCanvasItem *item,
|
||||
cairo_region_t *region,
|
||||
PikaDisplayShell *shell)
|
||||
{
|
||||
pika_display_shell_expose_region (shell, region);
|
||||
}
|
||||
53
app/display/pikadisplayshell-items.h
Normal file
53
app/display/pikadisplayshell-items.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* 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
|
||||
*
|
||||
* pikadisplayshell-items.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DISPLAY_SHELL_ITEMS_H__
|
||||
#define __PIKA_DISPLAY_SHELL_ITEMS_H__
|
||||
|
||||
|
||||
void pika_display_shell_items_init (PikaDisplayShell *shell);
|
||||
void pika_display_shell_items_free (PikaDisplayShell *shell);
|
||||
|
||||
void pika_display_shell_add_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
void pika_display_shell_remove_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
|
||||
void pika_display_shell_add_preview_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
void pika_display_shell_remove_preview_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
|
||||
void pika_display_shell_add_unrotated_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
void pika_display_shell_remove_unrotated_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
|
||||
void pika_display_shell_add_tool_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
void pika_display_shell_remove_tool_item (PikaDisplayShell *shell,
|
||||
PikaCanvasItem *item);
|
||||
|
||||
|
||||
#endif /* __PIKA_DISPLAY_SHELL_ITEMS_H__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user