1 /* This file is part of GEGL 2 * 3 * GEGL is free software; you can redistribute it and/or 4 * modify it under the terms of the GNU Lesser General Public 5 * License as published by the Free Software Foundation; either 6 * version 3 of the License, or (at your option) any later version. 7 * 8 * GEGL is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public 14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>. 15 * 16 * Copyright 2020 Øyvind Kolås 17 */ 18 19 #include "config.h" 20 #include <glib/gi18n-lib.h> 21 22 #ifdef GEGL_PROPERTIES 23 24 property_double (x, _("X"), 0.5) 25 description (_("Horizontal justification 0.0 is left 0.5 centered and 1.0 right.")) 26 value_range (-2.0, 3.0) 27 ui_range (0.0, 1.0) 28 ui_meta ("axis", "x") 29 30 property_double (y, _("Y"), 0.5) 31 description (_("Vertical justification 0.0 is top 0.5 middle and 1.0 bottom.")) 32 value_range (-2.0, 3.0) 33 ui_range (0.0, 1.0) 34 ui_meta ("axis", "y") 35 36 property_double (horizontal_margin, "Horizontal Margin", 0.0) 37 property_double (vertical_margin, "Vertical Margin", 0.0) 38 39 property_boolean (snap_integer, "snap to integer position", TRUE) 40 41 42 #else 43 44 #include "gegl-operation-filter.h" 45 #include "transform-core.h" 46 #define GEGL_OP_NO_SOURCE 47 #define GEGL_OP_Parent OpTransform 48 #define GEGL_OP_PARENT TYPE_OP_TRANSFORM 49 #define GEGL_OP_NAME border_align 50 #define GEGL_OP_BUNDLE 51 #define GEGL_OP_C_FILE "border-align.c" 52 53 #include "gegl-op.h" 54 55 #include <stdio.h> 56 57 static GeglNode *gegl_node_get_consumer_no (GeglNode *node, 58 const char *output_pad, 59 const char **consumer_pad, 60 int no) 61 { 62 GeglNode *consumer = NULL; 63 GeglNode **nodes = NULL; 64 const gchar **consumer_names = NULL; 65 int count; 66 if (node == NULL) 67 return NULL; 68 69 count = gegl_node_get_consumers (node, "output", &nodes, &consumer_names); 70 if (count > no){ 71 /* XXX : look into inverting list in get_consumers */ 72 //consumer = nodes[count-no-1]; 73 consumer = nodes[no]; 74 if (consumer_pad) 75 *consumer_pad = g_intern_string (consumer_names[count-no-1]); 76 } 77 g_free (nodes); 78 g_free (consumer_names); 79 return consumer; 80 } 81 82 static GeglNode *gegl_node_find_composite_target (GeglNode *node) 83 { 84 const char *dest_pad = NULL; 85 GeglNode *iter = node; 86 iter = gegl_node_get_consumer_no (iter, "output", &dest_pad, 0); 87 while (iter && dest_pad && g_str_equal (dest_pad, "input")) 88 { 89 iter = gegl_node_get_consumer_no (iter, "output", &dest_pad, 0); 90 } 91 if (dest_pad && !strcmp (dest_pad, "aux")) 92 { 93 return gegl_node_get_producer (iter, "input", NULL); 94 } 95 return NULL; 96 } 97 98 static void 99 create_matrix (OpTransform *op, 100 GeglMatrix3 *matrix) 101 { 102 GeglOperation *operation = GEGL_OPERATION (op); 103 GeglProperties *o = GEGL_PROPERTIES (op); 104 105 gdouble x = 0.0; 106 gdouble y = 0.0; 107 108 GeglNode *border_node = gegl_operation_get_source_node (operation, "aux"); 109 GeglNode *box_node = gegl_operation_get_source_node (operation, "input"); 110 111 GeglRectangle box_rect = {0,}; 112 GeglRectangle border_rect = {0,}; 113 114 if (box_node) 115 box_rect = gegl_node_get_bounding_box (box_node); 116 117 if (border_node) 118 { 119 border_rect = gegl_node_get_bounding_box (border_node); 120 } 121 else 122 { 123 border_node = gegl_node_find_composite_target (operation->node); 124 if (border_node) 125 border_rect = gegl_node_get_bounding_box (border_node); 126 } 127 128 x = o->x * (border_rect.width - box_rect.width - o->horizontal_margin * 2) + 129 o->horizontal_margin; 130 y = o->y * (border_rect.height - box_rect.height - o->vertical_margin * 2)+ 131 o->vertical_margin; 132 133 x -= box_rect.x; 134 y -= box_rect.y; 135 136 if (o->snap_integer) 137 { 138 x = roundf (x); 139 y = roundf (y); 140 } 141 142 matrix->coeff [0][2] = x; 143 matrix->coeff [1][2] = y; 144 } 145 146 static void attach (GeglOperation *operation) 147 { 148 GeglOperationComposerClass *klass = GEGL_OPERATION_COMPOSER_GET_CLASS (operation); 149 GParamSpec *pspec; 150 GeglOperationClass *parent_class = g_type_class_peek_parent (klass); 151 152 if (parent_class->attach) 153 parent_class->attach (operation); 154 155 pspec = g_param_spec_object ("aux", 156 klass->aux_label?klass->aux_label:"Aux", 157 klass->aux_description?klass->aux_description:_("Auxiliary image buffer input pad."), 158 GEGL_TYPE_BUFFER, 159 G_PARAM_READWRITE | 160 GEGL_PARAM_PAD_INPUT); 161 gegl_operation_create_pad (operation, pspec); 162 g_param_spec_sink (pspec); 163 164 } 165 166 static void 167 gegl_op_class_init (GeglOpClass *klass) 168 { 169 GeglOperationClass *operation_class; 170 OpTransformClass *transform_class; 171 172 operation_class = GEGL_OPERATION_CLASS (klass); 173 transform_class = OP_TRANSFORM_CLASS (klass); 174 175 operation_class->attach = attach; 176 transform_class->create_matrix = create_matrix; 177 178 gegl_operation_class_set_keys (operation_class, 179 "name", "gegl:border-align", 180 "title", _("Border Align"), 181 "categories", "transform", 182 "reference-hash", "109c3f3685488a9952ca07ef18387850", 183 "description", _("Aligns box of input rectangle with border of compositing target or aux' bounding-box border, if aux pad is not connected the op tries to figure out which bounding box' border applies."), 184 NULL); 185 } 186 187 #endif 188