Initial checkin of Pika from heckimp

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

644
app/display/display-enums.c Normal file
View 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
View 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__ */

View File

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

View File

@ -0,0 +1,462 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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);
}

View 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
View 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
View 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
View 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,
&center_x, &center_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,
&center_x, &center_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);
}

View File

@ -0,0 +1,73 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View File

@ -0,0 +1,388 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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;
}

View File

@ -0,0 +1,64 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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__ */

View 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);
}

View File

@ -0,0 +1,60 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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));
}
}
}

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View 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__ */

View File

@ -0,0 +1,232 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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);
}
}

View 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__ */

View 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);
}

View File

@ -0,0 +1,60 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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));
}
}

View 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__ */

View 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);
}

View File

@ -0,0 +1,66 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View 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__ */

View 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;
}

View 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__ */

View 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);
}
}

View File

@ -0,0 +1,151 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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;
}

View 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__ */

View 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);
}

View File

@ -0,0 +1,69 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View 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__ */

View File

@ -0,0 +1,359 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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);
}

View File

@ -0,0 +1,67 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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
View 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;
}

View File

@ -0,0 +1,64 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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__ */

View 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);
}

View 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__ */

View 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);
}

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View File

@ -0,0 +1,67 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View 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__ */

View 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);
}

View File

@ -0,0 +1,73 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View File

@ -0,0 +1,67 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View File

@ -0,0 +1,274 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 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);
}

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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

View 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);
}

View File

@ -0,0 +1,62 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View 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__ */

View 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);
}

View File

@ -0,0 +1,65 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}
}

View File

@ -0,0 +1,73 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}
}

View File

@ -0,0 +1,40 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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__ */

View 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);
}

View 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
View 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
View 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__ */

View File

@ -0,0 +1,155 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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);
}
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}
}

View 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__ */

View 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 */
}

View 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__ */

View 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;
}

View 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__ */

View 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);
}
}

View 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__ */

View 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);
}
}

View File

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

View 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);
}
}
}
}
}

View 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__ */

View File

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

View 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__ */

View File

@ -0,0 +1,155 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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);
}

View File

@ -0,0 +1,29 @@
/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 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__ */

View 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);
}

View 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__ */

View 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;
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View 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);
}

View 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