1 /*
2  * textbox.c
3  *
4  *
5  * Author:
6  *  Richard Hult <rhult@hem.passagen.se>
7  *  Ricardo Markiewicz <rmarkie@fi.uba.ar>
8  *  Andres de Barbara <adebarbara@fi.uba.ar>
9  *  Marc Lorber <lorber.marc@wanadoo.fr>
10  *
11  * Web page: https://ahoi.io/project/oregano
12  *
13  * Copyright (C) 1999-2001  Richard Hult
14  * Copyright (C) 2003,2006  Ricardo Markiewicz
15  * Copyright (C) 2009-2012  Marc Lorber
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of the
20  * License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public
28  * License along with this program; if not, write to the
29  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
30  * Boston, MA 02110-1301, USA.
31  */
32 
33 #include <math.h>
34 #include <goocanvas.h>
35 
36 #include "textbox.h"
37 #include "clipboard.h"
38 #include "node-store.h"
39 #include "schematic-print-context.h"
40 
41 #define TEXTBOX_DEFAULT_FONT "Arial 10"
42 
43 // Private declarations
44 
45 static void textbox_class_init (TextboxClass *klass);
46 static void textbox_init (Textbox *textbox);
47 static void textbox_copy (ItemData *dest, ItemData *src);
48 static ItemData *textbox_clone (ItemData *src);
49 static void textbox_rotate (ItemData *data, int angle, Coords *center);
50 static void textbox_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx);
51 static int textbox_register (ItemData *data);
52 static void textbox_unregister (ItemData *data);
53 static gboolean textbox_has_properties (ItemData *data);
54 
55 static void textbox_flip (ItemData *data, IDFlip direction, Coords *center);
56 
57 enum { TEXT_CHANGED, FONT_CHANGED, LAST_SIGNAL };
58 
59 struct _TextboxPriv
60 {
61 	char *text;
62 	char *font;
63 };
64 
65 G_DEFINE_TYPE (Textbox, textbox, TYPE_ITEM_DATA)
66 
67 static guint textbox_signals[LAST_SIGNAL] = {0};
68 
textbox_finalize(GObject * object)69 static void textbox_finalize (GObject *object)
70 {
71 	Textbox *textbox = TEXTBOX (object);
72 	TextboxPriv *priv = textbox->priv;
73 
74 	g_free (priv);
75 
76 	G_OBJECT_CLASS (textbox_parent_class)->finalize (object);
77 }
78 
textbox_dispose(GObject * object)79 static void textbox_dispose (GObject *object)
80 {
81 	G_OBJECT_CLASS (textbox_parent_class)->dispose (object);
82 }
83 
textbox_class_init(TextboxClass * klass)84 static void textbox_class_init (TextboxClass *klass)
85 {
86 	GObjectClass *object_class;
87 	ItemDataClass *item_data_class;
88 
89 	textbox_parent_class = g_type_class_peek (TYPE_ITEM_DATA);
90 	item_data_class = ITEM_DATA_CLASS (klass);
91 	object_class = G_OBJECT_CLASS (klass);
92 
93 	textbox_signals[TEXT_CHANGED] =
94 	    g_signal_new ("text_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
95 	                  NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
96 
97 	textbox_signals[FONT_CHANGED] =
98 	    g_signal_new ("font_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
99 	                  NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
100 
101 	object_class->finalize = textbox_finalize;
102 	object_class->dispose = textbox_dispose;
103 
104 	item_data_class->clone = textbox_clone;
105 	item_data_class->copy = textbox_copy;
106 	item_data_class->rotate = textbox_rotate;
107 	item_data_class->flip = textbox_flip;
108 	item_data_class->unreg = textbox_unregister;
109 	item_data_class->reg = textbox_register;
110 	item_data_class->has_properties = textbox_has_properties;
111 	item_data_class->print = textbox_print;
112 }
113 
textbox_init(Textbox * textbox)114 static void textbox_init (Textbox *textbox)
115 {
116 	TextboxPriv *priv = g_new0 (TextboxPriv, 1);
117 	textbox->priv = priv;
118 }
119 
textbox_new(char * font)120 Textbox *textbox_new (char *font)
121 {
122 	Textbox *textbox;
123 
124 	textbox = TEXTBOX (g_object_new (TYPE_TEXTBOX, NULL));
125 
126 	if (font == NULL)
127 		textbox->priv->font = g_strdup (TEXTBOX_DEFAULT_FONT);
128 	else
129 		textbox->priv->font = g_strdup (font);
130 
131 	return textbox;
132 }
133 
textbox_clone(ItemData * src)134 static ItemData *textbox_clone (ItemData *src)
135 {
136 	Textbox *new_textbox;
137 	ItemDataClass *id_class;
138 
139 	g_return_val_if_fail (src != NULL, NULL);
140 	g_return_val_if_fail (IS_TEXTBOX (src), NULL);
141 
142 	id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (src));
143 	if (id_class->copy == NULL)
144 		return NULL;
145 
146 	new_textbox = TEXTBOX (g_object_new (TYPE_TEXTBOX, NULL));
147 	id_class->copy (ITEM_DATA (new_textbox), src);
148 
149 	return ITEM_DATA (new_textbox);
150 }
151 
textbox_copy(ItemData * dest,ItemData * src)152 static void textbox_copy (ItemData *dest, ItemData *src)
153 {
154 	Textbox *dest_textbox, *src_textbox;
155 
156 	g_return_if_fail (dest != NULL);
157 	g_return_if_fail (IS_TEXTBOX (dest));
158 	g_return_if_fail (src != NULL);
159 	g_return_if_fail (IS_TEXTBOX (src));
160 
161 	if (ITEM_DATA_CLASS (textbox_parent_class)->copy != NULL)
162 		ITEM_DATA_CLASS (textbox_parent_class)->copy (dest, src);
163 
164 	dest_textbox = TEXTBOX (dest);
165 	src_textbox = TEXTBOX (src);
166 
167 	dest_textbox->priv->text = src_textbox->priv->text;
168 	dest_textbox->priv->font = src_textbox->priv->font;
169 }
170 
textbox_rotate(ItemData * data,int angle,Coords * center)171 static void textbox_rotate (ItemData *data, int angle, Coords *center)
172 {
173 	cairo_matrix_t affine;
174 	double x, y;
175 	Textbox *textbox;
176 	Coords b1, b2;
177 	Coords textbox_center, delta;
178 
179 	g_return_if_fail (data != NULL);
180 	g_return_if_fail (IS_TEXTBOX (data));
181 
182 	if (angle == 0)
183 		return;
184 
185 	textbox = TEXTBOX (data);
186 
187 	if (center) {
188 		item_data_get_absolute_bbox (ITEM_DATA (textbox), &b1, &b2);
189 		textbox_center.x = b1.x + (b2.x - b1.x) / 2;
190 		textbox_center.y = b1.y + (b2.y - b1.y) / 2;
191 	}
192 
193 	cairo_matrix_init_rotate (&affine, (double)angle * M_PI / 180);
194 
195 	// Let the views (canvas items) know about the rotation.
196 	g_signal_emit_by_name (G_OBJECT (textbox), "rotated", angle);
197 
198 	if (center) {
199 		Coords textbox_pos;
200 
201 		item_data_get_pos (ITEM_DATA (textbox), &textbox_pos);
202 
203 		x = textbox_center.x - center->x;
204 		y = textbox_center.y - center->y;
205 		cairo_matrix_transform_point (&affine, &x, &y);
206 
207 		delta.x = x - (textbox_center.x - center->x);
208 		delta.y = y - (textbox_center.y - center->y);
209 
210 		item_data_move (ITEM_DATA (textbox), &delta);
211 	}
212 }
213 
textbox_flip(ItemData * data,IDFlip direction,Coords * center)214 static void textbox_flip (ItemData *data, IDFlip direction, Coords *center)
215 {
216 	cairo_matrix_t affine;
217 	double x, y;
218 	Textbox *textbox;
219 	Coords b1, b2;
220 	Coords textbox_center = {0.0, 0.0}, delta;
221 
222 	g_return_if_fail (data != NULL);
223 	g_return_if_fail (IS_TEXTBOX (data));
224 
225 	textbox = TEXTBOX (data);
226 
227 	if (center) {
228 		item_data_get_absolute_bbox (ITEM_DATA (textbox), &b1, &b2);
229 		textbox_center.x = b1.x + (b2.x - b1.x) / 2;
230 		textbox_center.y = b1.y + (b2.y - b1.y) / 2;
231 	}
232 
233 	if (direction == ID_FLIP_HORIZ)
234 		cairo_matrix_init_scale (&affine, -1, 1);
235 	else
236 		cairo_matrix_init_scale (&affine, 1, -1);
237 
238 	// Let the views (canvas items) know about the rotation.
239 	g_signal_emit_by_name (G_OBJECT (textbox), "flipped", direction);
240 
241 	if (center) {
242 		Coords textbox_pos;
243 
244 		item_data_get_pos (ITEM_DATA (textbox), &textbox_pos);
245 
246 		x = textbox_center.x - center->x;
247 		y = textbox_center.y - center->y;
248 		cairo_matrix_transform_point (&affine, &x, &y);
249 
250 		delta.x = x - (textbox_center.x - center->x);
251 		delta.y = y - (textbox_center.y - center->y);
252 
253 		item_data_move (ITEM_DATA (textbox), &delta);
254 	}
255 }
256 
textbox_update_bbox(Textbox * textbox)257 void textbox_update_bbox (Textbox *textbox)
258 {
259 	Coords b1, b2;
260 	b1.x = 0.0;
261 	b1.y = 0.0 - 5; // - font->ascent;
262 	b2.x = 0.0 + 5; // + rbearing;
263 	b2.y = 0.0 + 5; // + font->descent;
264 
265 	item_data_set_relative_bbox (ITEM_DATA (textbox), &b1, &b2);
266 }
267 
textbox_has_properties(ItemData * data)268 static gboolean textbox_has_properties (ItemData *data) { return TRUE; }
269 
textbox_set_text(Textbox * textbox,const char * text)270 void textbox_set_text (Textbox *textbox, const char *text)
271 {
272 	g_return_if_fail (textbox != NULL);
273 	g_return_if_fail (IS_TEXTBOX (textbox));
274 
275 	g_free (textbox->priv->text);
276 	textbox->priv->text = g_strdup (text);
277 
278 	textbox_update_bbox (textbox);
279 	g_signal_emit_by_name (G_OBJECT (textbox), "text_changed", text);
280 }
281 
textbox_get_text(Textbox * textbox)282 char *textbox_get_text (Textbox *textbox)
283 {
284 	g_return_val_if_fail (textbox != NULL, NULL);
285 	g_return_val_if_fail (IS_TEXTBOX (textbox), NULL);
286 
287 	return textbox->priv->text;
288 }
289 
textbox_set_font(Textbox * textbox,char * font)290 void textbox_set_font (Textbox *textbox, char *font)
291 {
292 	g_return_if_fail (textbox != NULL);
293 	g_return_if_fail (IS_TEXTBOX (textbox));
294 
295 	g_free (textbox->priv->font);
296 	if (font == NULL)
297 		textbox->priv->font = g_strdup (TEXTBOX_DEFAULT_FONT);
298 	else
299 		textbox->priv->font = g_strdup (font);
300 
301 	textbox_update_bbox (textbox);
302 
303 	g_signal_emit_by_name (G_OBJECT (textbox), "font_changed", textbox->priv->font);
304 }
305 
textbox_get_font(Textbox * textbox)306 char *textbox_get_font (Textbox *textbox)
307 {
308 	g_return_val_if_fail (textbox != NULL, NULL);
309 	g_return_val_if_fail (IS_TEXTBOX (textbox), NULL);
310 
311 	return textbox->priv->font;
312 }
313 
textbox_print(ItemData * data,cairo_t * cr,SchematicPrintContext * ctx)314 static void textbox_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
315 {
316 	/*	GnomeCanvasPoints *line;
317 	        double x0, y0;
318 	        ArtPoint dst, src;
319 	        double affine[6];
320 	        int i;
321 	        Textbox *textbox;
322 	        TextboxPriv *priv;
323 	        Coords pos;
324 
325 	        g_return_if_fail (data != NULL);
326 	        g_return_if_fail (IS_TEXTBOX (data));
327 
328 	        textbox = TEXTBOX (data);
329 	        priv = textbox->priv;
330 
331 	        item_data_get_pos (ITEM_DATA (textbox), &pos);
332 	        src.x = pos.x;
333 	        src.y = pos.y;
334 
335 	        art_affine_identity (affine);
336 
337 	        gnome_print_setfont (opc->ctx,
338 	                gnome_font_face_get_font_default (opc->label_font, 6));
339 	        print_draw_text (opc->ctx, priv->text, &src);
340 	        */
341 }
342 
textbox_unregister(ItemData * data)343 static void textbox_unregister (ItemData *data)
344 {
345 	NodeStore *store;
346 
347 	g_return_if_fail (IS_TEXTBOX (data));
348 
349 	store = item_data_get_store (data);
350 	node_store_remove_textbox (store, TEXTBOX (data));
351 }
352 
textbox_register(ItemData * data)353 static int textbox_register (ItemData *data)
354 {
355 	NodeStore *store;
356 
357 	g_return_val_if_fail (IS_TEXTBOX (data), 0);
358 
359 	store = item_data_get_store (data);
360 	node_store_add_textbox (store, TEXTBOX (data));
361 	return 0;
362 }
363