1 /* gtkplotcanvas - gtkplot canvas widget for gtk+
2  * Copyright 1999-2001  Adrian E. Feiguin <feiguin@ifir.edu.ar>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /**
21  * SECTION: gtkplotcanvasplot
22  * @short_description:
23  *
24  * A #GtkPlotCanvas object is an interactive container for
25  * GtkPlots and some graphic primitives that can be used to
26  * illustrate the plots (see #GtkCanvasChild).
27  */
28 
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <math.h>
34 #include <gtk/gtk.h>
35 #include "gtkplot.h"
36 #include "gtkplot3d.h"
37 #include "gtkplotdata.h"
38 #include "gtkplotcanvas.h"
39 #include "gtkplotcanvasplot.h"
40 #include "gtkplotgdk.h"
41 #include "gtkplotps.h"
42 
43 #define DEFAULT_MARKER_SIZE 6
44 
45 static void gtk_plot_canvas_plot_init		(GtkPlotCanvasPlot *plot);
46 static void gtk_plot_canvas_plot_class_init(GtkPlotCanvasChildClass *klass);
47 static void gtk_plot_canvas_plot_destroy	(GtkObject *object);
48 static void gtk_plot_canvas_plot_draw 		(GtkPlotCanvas *canvas,
49 						 GtkPlotCanvasChild *child);
50 static void gtk_plot_canvas_plot_move		(GtkPlotCanvas *canvas,
51 						 GtkPlotCanvasChild *child,
52 						 gdouble x, gdouble y);
53 static void gtk_plot_canvas_plot_resize		(GtkPlotCanvas *canvas,
54 						 GtkPlotCanvasChild *child,
55 						 gdouble x1, gdouble y1,
56 						 gdouble x2, gdouble y2);
57 static void gtk_plot_canvas_plot_size_allocate	(GtkPlotCanvas *canvas,
58 						 GtkPlotCanvasChild *child);
59 static void gtk_plot_canvas_plot_set_magnification(GtkPlotCanvas *canvas,
60 						 GtkPlotCanvasChild *child,
61 						 gdouble m);
62 static void gtk_plot_canvas_plot_unselect	(GtkPlotCanvas *canvas,
63 						 GtkPlotCanvasChild *child);
64 static GtkPlotCanvasPos gtk_plot_canvas_plot_button_press
65 						(GtkPlotCanvas *canvas,
66 				  		 GtkPlotCanvasChild *child,
67 				  		 gint x, gint y);
68 static void gtk_plot_canvas_plot_button_release (GtkPlotCanvas *canvas,
69 						 GtkPlotCanvasChild *child);
70 static void reset_plot_allocation		(GtkPlotCanvas *canvas,
71 						 GtkPlotCanvasPlot *child);
72 extern gint roundint                     (gdouble x);
73 static GtkPlotCanvasChildClass *parent_class = NULL;
74 
75 extern GtkPlotCanvasPos possible_selection	(GtkAllocation area,
76 						 gint x, gint y);
77 
78 GType
gtk_plot_canvas_plot_get_type(void)79 gtk_plot_canvas_plot_get_type (void)
80 {
81   static GType plot_canvas_plot_type = 0;
82 
83   if (!plot_canvas_plot_type)
84     {
85       plot_canvas_plot_type = g_type_register_static_simple (
86 		gtk_plot_canvas_child_get_type(),
87 		"GtkPlotCanvasPlot",
88 		sizeof (GtkPlotCanvasPlotClass),
89 		(GClassInitFunc) gtk_plot_canvas_plot_class_init,
90 		sizeof (GtkPlotCanvasPlot),
91 		(GInstanceInitFunc) gtk_plot_canvas_plot_init,
92 		0);
93     }
94   return plot_canvas_plot_type;
95 }
96 
97 /**
98  * gtk_plot_canvas_plot_new:
99  * @plot: a #GtkPlot.
100  *
101  *
102  *
103  * Return value:
104  */
105 GtkPlotCanvasChild*
gtk_plot_canvas_plot_new(GtkPlot * plot)106 gtk_plot_canvas_plot_new (GtkPlot *plot)
107 {
108   GtkPlotCanvasPlot *child;
109 
110   child = g_object_new (gtk_plot_canvas_plot_get_type (), NULL);
111   child->plot = plot;
112 
113   return GTK_PLOT_CANVAS_CHILD (child);
114 }
115 
116 static void
gtk_plot_canvas_plot_init(GtkPlotCanvasPlot * plot)117 gtk_plot_canvas_plot_init (GtkPlotCanvasPlot *plot)
118 {
119   plot->plot = NULL;
120   plot->pos = GTK_PLOT_CANVAS_PLOT_IN_PLOT;
121   plot->axis = NULL;
122   plot->data = NULL;
123   plot->marker = NULL;
124   GTK_PLOT_CANVAS_PLOT(plot)->datapoint = -1;
125   GTK_PLOT_CANVAS_PLOT(plot)->flags = 0; /* GTK_PLOT_CANVAS_PLOT_SELECT_POINT; */
126 }
127 
128 static void
gtk_plot_canvas_plot_class_init(GtkPlotCanvasChildClass * klass)129 gtk_plot_canvas_plot_class_init (GtkPlotCanvasChildClass *klass)
130 {
131   GtkObjectClass *object_class = (GtkObjectClass *)klass;
132 
133   parent_class = g_type_class_ref (gtk_plot_canvas_child_get_type ());
134 
135   klass->draw = gtk_plot_canvas_plot_draw;
136   klass->move = gtk_plot_canvas_plot_move;
137   klass->move_resize = gtk_plot_canvas_plot_resize;
138   klass->size_allocate = gtk_plot_canvas_plot_size_allocate;
139   klass->button_press = gtk_plot_canvas_plot_button_press;
140   klass->button_release = gtk_plot_canvas_plot_button_release;
141   klass->unselect = gtk_plot_canvas_plot_unselect;
142   klass->set_magnification = gtk_plot_canvas_plot_set_magnification;
143 
144   object_class->destroy = gtk_plot_canvas_plot_destroy;
145 }
146 
147 static void
gtk_plot_canvas_plot_destroy(GtkObject * object)148 gtk_plot_canvas_plot_destroy(GtkObject *object)
149 {
150   GtkWidget *widget = GTK_WIDGET(GTK_PLOT_CANVAS_PLOT(object)->plot);
151   g_object_unref(widget);
152 
153   /* 28.06.13/fp - dropped the following line
154      - do not access widget data after g_object_unref()
155      - calling gtk_widget_unparent() before g_object_unref() -> invalid GObject warnings
156 
157   widget->parent = NULL;
158   */
159 }
160 
gtk_plot_canvas_plot_flags(GtkPlotCanvasPlot * plot)161 GtkPlotCanvasPlotFlags gtk_plot_canvas_plot_flags(GtkPlotCanvasPlot *plot)
162 {
163   g_return_val_if_fail(plot != NULL, 0);
164   return(plot->flags);
165 }
166 
gtk_plot_canvas_plot_set_flags(GtkPlotCanvasPlot * plot,GtkPlotCanvasPlotFlags flags)167 void gtk_plot_canvas_plot_set_flags(GtkPlotCanvasPlot *plot,
168     GtkPlotCanvasPlotFlags flags)
169 {
170   g_return_if_fail(plot != NULL);
171   plot->flags |= flags;
172 }
173 
gtk_plot_canvas_plot_unset_flags(GtkPlotCanvasPlot * plot,GtkPlotCanvasPlotFlags flags)174 void gtk_plot_canvas_plot_unset_flags(GtkPlotCanvasPlot *plot,
175     GtkPlotCanvasPlotFlags flags)
176 {
177   g_return_if_fail(plot != NULL);
178   plot->flags &= ~flags;
179 }
180 
181 
182 static void
gtk_plot_canvas_plot_draw(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child)183 gtk_plot_canvas_plot_draw 		(GtkPlotCanvas *canvas,
184 					 GtkPlotCanvasChild *child)
185 {
186   GtkPlotCanvasPlot *plot_child = GTK_PLOT_CANVAS_PLOT(child);
187   GtkPlot *plot = plot_child->plot;
188   gint width = child->allocation.width;
189   gint height = child->allocation.height;
190   gdouble m = canvas->magnification;
191   GtkPlotPC *pc;
192   GtkAllocation allocation;
193 
194   if(width == 0 && height == 0) return;
195 
196   gtk_plot_set_drawable(plot, canvas->pixmap);
197   allocation.x = 0;
198   allocation.y = 0;
199   allocation.width = canvas->pixmap_width;
200   allocation.height = canvas->pixmap_height;
201   gtk_widget_set_allocation(GTK_WIDGET(plot), &allocation);
202   gtk_plot_set_magnification(plot, m);
203   reset_plot_allocation(canvas, plot_child);
204 
205   pc = plot->pc;
206   plot->pc = canvas->pc;
207 
208   gtk_plot_paint(GTK_PLOT_CANVAS_PLOT(child)->plot);
209 
210   plot->pc = pc;
211 }
212 
213 static void
reset_plot_allocation(GtkPlotCanvas * canvas,GtkPlotCanvasPlot * child)214 reset_plot_allocation(GtkPlotCanvas *canvas, GtkPlotCanvasPlot *child)
215 {
216   GtkPlot *plot = child->plot;
217   gdouble x1 = plot->internal_allocation.x;
218   gdouble y1 = plot->internal_allocation.y;
219   gdouble x2 = x1 + plot->internal_allocation.width;
220   gdouble y2 = y1 + plot->internal_allocation.height;
221 
222   GTK_PLOT_CANVAS_CHILD(child)->allocation = plot->internal_allocation;
223   GTK_PLOT_CANVAS_CHILD(child)->rx1 = x1 / (gdouble) canvas->pixmap_width;
224   GTK_PLOT_CANVAS_CHILD(child)->rx2 = x2 / (gdouble) canvas->pixmap_width;
225   GTK_PLOT_CANVAS_CHILD(child)->ry1 = y1 / (gdouble) canvas->pixmap_height;
226   GTK_PLOT_CANVAS_CHILD(child)->ry2 = y2 / (gdouble) canvas->pixmap_height;
227 /*
228   GTK_PLOT_CANVAS_CHILD(child)->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
229   GTK_PLOT_CANVAS_CHILD(child)->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
230   GTK_PLOT_CANVAS_CHILD(child)->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE | GTK_PLOT_CANVAS_CHILD_CAN_RESIZE;
231 */
232 }
233 
234 static void
gtk_plot_canvas_plot_move(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child,gdouble x,gdouble y)235 gtk_plot_canvas_plot_move		(GtkPlotCanvas *canvas,
236 					 GtkPlotCanvasChild *child,
237 					 gdouble x, gdouble y)
238 {
239   GtkPlotCanvasPlot *cplot = GTK_PLOT_CANVAS_PLOT(child);
240   GtkPlot *plot = cplot->plot;
241   if(!plot) return;
242 }
243 
244 static void
gtk_plot_canvas_plot_resize(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child,gdouble x1,gdouble y1,gdouble x2,gdouble y2)245 gtk_plot_canvas_plot_resize	(GtkPlotCanvas *canvas,
246 				 GtkPlotCanvasChild *child,
247 				 gdouble x1, gdouble y1,
248 				 gdouble x2, gdouble y2)
249 {
250   GtkPlotCanvasPlot *cplot = GTK_PLOT_CANVAS_PLOT(child);
251   GtkPlot *plot = cplot->plot;
252 
253   if(!plot) return;
254 
255   gtk_plot_move_resize(plot, x1, y1, fabs(x2-x1), fabs(y2-y1));
256   GTK_PLOT_CANVAS_CHILD_CLASS(GTK_OBJECT_GET_CLASS(GTK_OBJECT(child)))->size_allocate(canvas, child);
257   gtk_plot_canvas_paint(canvas);
258   gtk_plot_canvas_refresh(canvas);
259 }
260 
261 static void
gtk_plot_canvas_plot_button_release(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child)262 gtk_plot_canvas_plot_button_release	(GtkPlotCanvas *canvas,
263 				 	 GtkPlotCanvasChild *child)
264 {
265   GtkPlotCanvasPlot *cplot = GTK_PLOT_CANVAS_PLOT(child);
266   GtkPlot *plot = cplot->plot;
267   gdouble fx, fy, fz, fa;
268   gdouble fdx, fdy, fdz, fda;
269   gdouble mx, my;
270   gchar *label = NULL;
271   gboolean error;
272   gint i;
273   gdouble new_x, new_y, new_width, new_height;
274   gdouble old_x, old_y;
275   gdouble dx, dy;
276   gdouble x1, x2, y1, y2;
277   gboolean moved = FALSE;
278 
279   gtk_plot_canvas_get_position(canvas,
280                                child->drag_area.x,
281                                child->drag_area.y,
282                                &old_x, &old_y);
283 
284   gtk_plot_canvas_get_position(canvas,
285                                canvas->drag_area.width,
286                                canvas->drag_area.height,
287                                &new_width, &new_height);
288 
289   gtk_plot_canvas_get_position(canvas,
290                                canvas->drag_area.x,
291                                canvas->drag_area.y,
292                                &new_x, &new_y);
293 
294   dx = new_x - old_x;
295   dy = new_y - old_y;
296   x1 = MIN(child->rx1, child->rx2);
297   y1 = MIN(child->ry1, child->ry2);
298   x2 = MAX(child->rx1, child->rx2);
299   y2 = MAX(child->ry1, child->ry2);
300   x1 += dx;
301   y1 += dy;
302   x2 = x1 + new_width;
303   y2 = y1 + new_height;
304 
305   if(!plot) return;
306 
307   switch(cplot->pos){
308     case GTK_PLOT_CANVAS_PLOT_IN_LEGENDS:
309       gtk_plot_legends_move(plot, (new_x - plot->x)*canvas->pixmap_width/plot->internal_allocation.width, (new_y - plot->y)*canvas->pixmap_height/plot->internal_allocation.height);
310       child->drag_area = canvas->drag_area;
311       break;
312     case GTK_PLOT_CANVAS_PLOT_IN_TITLE:
313       if(!GTK_IS_PLOT3D(plot) && cplot->axis){
314          GtkPlotText *text = &cplot->axis->title;
315          text->x += (new_x - old_x);
316          text->y += (new_y - old_y);
317          child->drag_area = canvas->drag_area;
318       }
319       break;
320     case GTK_PLOT_CANVAS_PLOT_IN_DATA:
321       if(GTK_PLOT_CANVAS_PLOT_DND_POINT(cplot)){
322         gdouble *array_x = NULL;
323         gdouble *array_y = NULL;
324         gdouble px, py;
325         gint n;
326 	gdouble x, y;
327         array_x = gtk_plot_data_get_x(cplot->data, &n);
328         array_y = gtk_plot_data_get_y(cplot->data, &n);
329 	gtk_plot_get_pixel(plot, array_x[cplot->datapoint], array_y[cplot->datapoint], &px, &py);
330         new_x = px + (canvas->pointer_x - canvas->drag_x);
331         new_y = py + (canvas->pointer_y - canvas->drag_y);
332 	gtk_plot_get_point(plot, new_x, new_y, &x, &y);
333         array_x[cplot->datapoint] = x;
334         array_y[cplot->datapoint] = y;
335         gtk_plot_canvas_get_position(canvas, new_x, new_y,
336                                      &child->rx1, &child->ry1);
337         child->drag_area.x = new_x - DEFAULT_MARKER_SIZE;
338         child->drag_area.y = new_y - DEFAULT_MARKER_SIZE;
339       }
340       break;
341     case GTK_PLOT_CANVAS_PLOT_IN_MARKER:
342       gtk_plot_data_get_point(cplot->marker->data, cplot->marker->point,
343                               &fx, &fy, &fz, &fa, &fdx, &fdy, &fdz, &fda,
344                               &label, &error);
345 
346       gtk_plot_get_pixel(plot,
347                          fx, fy,
348                          &mx, &my);
349 
350       new_x = mx + (canvas->pointer_x - canvas->drag_x);
351       new_y = my + (canvas->pointer_y - canvas->drag_y);
352 
353       for(i = 0; i < cplot->marker->data->num_points; i++){
354         gdouble px, py;
355 
356         gtk_plot_data_get_point(cplot->marker->data, i,
357                                 &fx, &fy, &fz, &fa, &fdx, &fdy, &fdz, &fda,
358                                 &label, &error);
359 
360         gtk_plot_get_pixel(plot,
361                            fx, fy,
362                            &px, &py);
363 
364         if(abs(new_x - px) <= DEFAULT_MARKER_SIZE &&
365            abs(new_y - py) <= DEFAULT_MARKER_SIZE){
366              cplot->marker->point = i;
367              cplot->datapoint = i;
368              gtk_plot_canvas_get_position(canvas, px, py,
369                                           &child->rx1, &child->ry1);
370              child->drag_area.x = px - 10;
371              child->drag_area.y = py - 10;
372              canvas->drag_area = child->drag_area;
373              moved = TRUE;
374              break;
375         }
376       }
377       if(!moved){
378         child->drag_area.x = mx - 10;
379         child->drag_area.y = my - 10;
380         canvas->drag_area = child->drag_area;
381       }
382       break;
383     case GTK_PLOT_CANVAS_PLOT_IN_GRADIENT:
384       gtk_plot_data_move_gradient(cplot->data, (new_x - plot->x)*canvas->pixmap_width/plot->internal_allocation.width, (new_y - plot->y)*canvas->pixmap_height/plot->internal_allocation.height);
385       child->drag_area = canvas->drag_area;
386       break;
387     case GTK_PLOT_CANVAS_PLOT_IN_AXIS:
388       break;
389     case GTK_PLOT_CANVAS_PLOT_IN_PLOT:
390     default:
391       child->rx1 = x1;
392       child->ry1 = y1;
393       child->rx2 = x2;
394       child->ry2 = y2;
395       child->drag_area = canvas->drag_area;
396       gtk_plot_move_resize(plot,
397   		           x1, y1, fabs(x2-x1), fabs(y2-y1));
398       GTK_PLOT_CANVAS_CHILD_CLASS(GTK_OBJECT_GET_CLASS(GTK_OBJECT(child)))->size_allocate(canvas, child);
399       break;
400   }
401   gtk_plot_canvas_paint(canvas);
402   gtk_plot_canvas_refresh(canvas);
403 }
404 
405 static void
gtk_plot_canvas_plot_set_magnification(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child,gdouble m)406 gtk_plot_canvas_plot_set_magnification	(GtkPlotCanvas *canvas,
407 					 GtkPlotCanvasChild *child,
408 					 gdouble m)
409 {
410   GtkPlot *plot = GTK_PLOT_CANVAS_PLOT(child)->plot;
411 
412   gtk_plot_set_magnification(plot, m);
413 }
414 
415 static void
gtk_plot_canvas_plot_size_allocate(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child)416 gtk_plot_canvas_plot_size_allocate	(GtkPlotCanvas *canvas,
417 					 GtkPlotCanvasChild *child)
418 {
419   GtkAllocation allocation;
420   GtkPlot *plot = GTK_PLOT_CANVAS_PLOT(child)->plot;
421   if(!plot) return;
422 
423   switch(GTK_PLOT_CANVAS_PLOT(child)->pos){
424     case GTK_PLOT_CANVAS_PLOT_IN_PLOT:
425     case GTK_PLOT_CANVAS_PLOT_OUT:
426       allocation.x = 0;
427       allocation.y = 0;
428       allocation.width = canvas->pixmap_width;
429       allocation.height = canvas->pixmap_height;
430       gtk_widget_set_allocation(GTK_WIDGET(plot), &allocation);
431 
432       if(!gtk_widget_get_parent(GTK_WIDGET(plot)))
433         gtk_widget_set_parent(GTK_WIDGET(plot), GTK_WIDGET(canvas));
434 
435       gtk_plot_move_resize(plot, child->rx1, child->ry1,
436                            fabs(child->rx2-child->rx1), fabs(child->ry2-child->ry1));
437       reset_plot_allocation(canvas, GTK_PLOT_CANVAS_PLOT(child));
438       break;
439     case GTK_PLOT_CANVAS_PLOT_IN_LEGENDS:
440       break;
441     case GTK_PLOT_CANVAS_PLOT_IN_GRADIENT:
442       child->drag_area.x = roundint(child->rx1 * canvas->pixmap_width);
443       child->drag_area.y = roundint(child->ry1 * canvas->pixmap_height);
444       break;
445     case GTK_PLOT_CANVAS_PLOT_IN_TITLE:
446       {
447         GtkPlotText text = GTK_PLOT_CANVAS_PLOT(child)->axis->title;
448         gint tx, ty, twidth, theight;
449         gint rx, ry;
450 
451         gtk_plot_text_get_area(text.text, text.angle,
452                                text.justification,
453                                text.font,
454 		   	       roundint(canvas->magnification * text.height),
455                                &tx, &ty, &twidth, &theight);
456 
457         gtk_plot_canvas_get_pixel(canvas,
458                                   text.x, text.y,
459                                   &rx, &ry);
460 
461         if(text.border != GTK_PLOT_BORDER_NONE){
462           tx -= text.border_space;
463           ty -= text.border_space;
464           twidth += 2 * text.border_space;
465           theight += 2 * text.border_space;
466         }
467 
468         child->drag_area.x = tx + rx;
469         child->drag_area.y = ty + ry;
470         child->drag_area.width = twidth;
471         child->drag_area.height = theight;
472       }
473       break;
474     default:
475       break;
476   }
477 }
478 
479 static void
gtk_plot_canvas_plot_unselect(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child)480 gtk_plot_canvas_plot_unselect(GtkPlotCanvas *canvas, GtkPlotCanvasChild *child)
481 {
482   reset_plot_allocation(canvas, GTK_PLOT_CANVAS_PLOT(child));
483 }
484 
485 static void
canvas_unselect(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child)486 canvas_unselect(GtkPlotCanvas *canvas, GtkPlotCanvasChild *child)
487 {
488   gtk_plot_canvas_unselect(canvas);
489   reset_plot_allocation(canvas, GTK_PLOT_CANVAS_PLOT(child));
490   GTK_PLOT_CANVAS_CHILD(child)->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
491   GTK_PLOT_CANVAS_CHILD(child)->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
492   GTK_PLOT_CANVAS_CHILD(child)->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE | GTK_PLOT_CANVAS_CHILD_CAN_RESIZE;
493 }
494 
495 static GtkPlotCanvasPos
gtk_plot_canvas_plot_button_press(GtkPlotCanvas * canvas,GtkPlotCanvasChild * child,gint x,gint y)496 gtk_plot_canvas_plot_button_press(GtkPlotCanvas *canvas,
497 				  GtkPlotCanvasChild *child,
498 				  gint x, gint y)
499 {
500   GtkAllocation area;
501   GtkPlot *plot = GTK_PLOT_CANVAS_PLOT(child)->plot;
502   GtkPlotCanvasPos pos;
503   GList *dataset = NULL;
504 
505   if(!plot) return GTK_PLOT_CANVAS_OUT;
506 
507   /* Legends */
508 
509   area = gtk_plot_legends_get_allocation(plot);
510   if((pos = possible_selection(area, x, y)) != GTK_PLOT_CANVAS_OUT) {
511     if(canvas->active_item == child &&
512        GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_LEGENDS)
513          return pos;
514 
515     canvas_unselect(canvas, child);
516     child->drag_area = area;
517 
518     GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_LEGENDS;
519     child->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
520     child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
521     child->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE;
522     child->state = GTK_STATE_SELECTED;
523     return pos;
524   }
525 
526   /* Gradient */
527 
528   dataset = plot->data_sets;
529 
530   while(dataset) {
531     GtkPlotData *data;
532     data = GTK_PLOT_DATA(dataset->data);
533 
534     area = gtk_plot_data_get_gradient_allocation(data);
535     if((pos = possible_selection(area, x, y)) != GTK_PLOT_CANVAS_OUT) {
536       if(canvas->active_item == child &&
537          GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_GRADIENT &&
538          GTK_PLOT_CANVAS_PLOT(child)->data == data) return pos;
539 
540       canvas_unselect(canvas, child);
541       child->drag_area = area;
542 
543       GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_GRADIENT;
544       GTK_PLOT_CANVAS_PLOT(child)->data = data;
545       child->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
546       child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
547       child->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE;
548       child->state = GTK_STATE_SELECTED;
549       return pos;
550     }
551     dataset = dataset->next;
552   }
553 
554   /* Titles */
555 
556   if(!GTK_IS_PLOT3D(plot)){
557     GtkPlotAxis *axis[4];
558     gint i;
559 
560     axis[0]=plot->left;
561     axis[1]=plot->right;
562     axis[2]=plot->top;
563     axis[3]=plot->bottom;
564 
565     for(i = 0; i <= 3; i++){
566       if(axis[i]->title_visible){
567         GtkPlotText *child_text = &axis[i]->title;
568         gint tx, ty, twidth, theight;
569         gint rx, ry;
570 
571         gtk_plot_canvas_get_pixel(canvas,
572                                   child_text->x, child_text->y,
573                                   &rx, &ry);
574 
575         gtk_plot_text_get_area(child_text->text,
576                                child_text->angle,
577                                child_text->justification,
578                                child_text->font,
579                                roundint(child_text->height * canvas->magnification),
580                                &tx, &ty, &twidth, &theight);
581 
582         area.x = rx + tx;
583         area.y = ry + ty;
584         area.width = twidth;
585         area.height = theight;
586 
587         if(child_text->border != GTK_PLOT_BORDER_NONE){
588           area.x -= child_text->border_space;
589           area.y -= child_text->border_space;
590           area.width += 2 * child_text->border_space;
591           area.height += 2 * child_text->border_space;
592         }
593 
594         if((pos = possible_selection(area, x, y)) != GTK_PLOT_CANVAS_OUT){
595           if(canvas->active_item == child &&
596              GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_TITLE &&
597              GTK_PLOT_CANVAS_PLOT(child)->axis == axis[i])
598             return pos;
599 
600           canvas_unselect(canvas, child);
601           child->drag_area = area;
602 
603           GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_TITLE;
604           GTK_PLOT_CANVAS_PLOT(child)->axis = axis[i];
605           child->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
606           child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
607           child->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE;
608           child->state = GTK_STATE_SELECTED;
609           return pos;
610         }
611       }
612     }
613 
614   }
615 
616   /* Plot markers */
617 
618   area = plot->internal_allocation;
619   if((pos = possible_selection(area, x, y)) != GTK_PLOT_CANVAS_OUT &&
620       pos != GTK_PLOT_CANVAS_IN) {
621     if(canvas->active_item == child &&
622        GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_PLOT)
623          return pos;
624 
625     canvas_unselect(canvas, child);
626     child->drag_area = area;
627 
628     GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_PLOT;
629     child->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
630     child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
631     child->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE;
632     child->state = GTK_STATE_SELECTED;
633     return pos;
634   }
635 
636   /* Axes */
637 
638   if(!GTK_IS_PLOT3D(plot)){
639     gint px, py, pwidth, pheight;
640     GtkAllocation _area[4];
641     GtkPlotAxis *axis[4];
642     gint i;
643 
644     axis[0]=plot->left;
645     axis[1]=plot->right;
646     axis[2]=plot->top;
647     axis[3]=plot->bottom;
648 
649     px = plot->internal_allocation.x;
650     py = plot->internal_allocation.y;
651     pwidth = plot->internal_allocation.width;
652     pheight = plot->internal_allocation.height;
653 
654     _area[0].x = px - 6;
655     _area[0].y = _area[1].y = py;
656     _area[0].width = _area[1].width = 6;
657     _area[0].height = _area[1].height = pheight;
658     _area[1].x = px + pwidth;
659     _area[2].x = _area[3].x = px;
660     _area[2].y = py - 6;
661     _area[2].width = _area[3].width = pwidth;
662     _area[2].height = _area[3].height = 6;
663     _area[3].y = py + pheight;
664 
665     for(i = 0; i < 4; i++){
666       area = _area[i];
667       if((pos = possible_selection(area, x, y)) != GTK_PLOT_CANVAS_OUT){
668 
669         if(canvas->active_item == child &&
670            GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_AXIS &&
671            GTK_PLOT_CANVAS_PLOT(child)->axis == axis[i])
672           return pos;
673 
674         canvas_unselect(canvas, child);
675         child->drag_area = area;
676 
677         GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_AXIS;
678         GTK_PLOT_CANVAS_PLOT(child)->axis = axis[i];
679         child->state = GTK_STATE_SELECTED;
680         child->flags = GTK_PLOT_CANVAS_CHILD_FROZEN;
681         child->selection = GTK_PLOT_CANVAS_SELECT_MARKERS;
682         child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_2;
683         return pos;
684       }
685     }
686   }
687 
688   /* Markers */
689 
690   if(!GTK_IS_PLOT3D(plot)){
691     dataset = plot->data_sets;
692 
693     while(dataset) {
694       GtkPlotData *data = GTK_PLOT_DATA(dataset->data);
695       GList *markers = data->markers;
696       while(markers){
697         GtkPlotMarker *marker;
698         gdouble fx, fy, fz, fa, fdx, fdy, fdz, fda;
699         gboolean error;
700         gchar *label;
701         gdouble xi, yi;
702 
703         marker = (GtkPlotMarker *) markers->data;
704 
705         gtk_plot_data_get_point(data, marker->point,
706                                 &fx, &fy, &fz, &fa, &fdx, &fdy, &fdz, &fda,
707                                 &label, &error);
708         gtk_plot_get_pixel(GTK_PLOT(plot), fx, fy, &xi, &yi);
709         if(abs(xi-x) <= 20 && abs(yi-y) <= 20){
710 
711           if(canvas->active_item == child &&
712              GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_MARKER &&
713 	     GTK_PLOT_CANVAS_PLOT(child)->marker == marker)
714              return GTK_PLOT_CANVAS_IN;
715 
716           canvas_unselect(canvas, child);
717 
718           GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_MARKER;
719           GTK_PLOT_CANVAS_PLOT(child)->data = data;
720           GTK_PLOT_CANVAS_PLOT(child)->marker = marker;
721           GTK_PLOT_CANVAS_PLOT(child)->datapoint = marker->point;
722           child->drag_area.x = xi - 10;
723           child->drag_area.y = yi - 10;
724           child->drag_area.width = 20;
725           child->drag_area.height = 20;
726           canvas->drag_area = child->drag_area;
727           child->state = GTK_STATE_SELECTED;
728           child->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE;
729           child->selection = GTK_PLOT_CANVAS_SELECT_TARGET;
730           child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_1;
731           return GTK_PLOT_CANVAS_IN;
732         }
733         markers = markers->next;
734       }
735       dataset = dataset->next;
736     }
737   }
738 
739   /* Dataset */
740 
741   if(!GTK_IS_PLOT3D(plot)
742      && GTK_PLOT_CANVAS_PLOT_SELECT_POINT(GTK_PLOT_CANVAS_PLOT(child))){
743     dataset = plot->data_sets;
744 
745     while(dataset) {
746       GtkPlotData *data = GTK_PLOT_DATA(dataset->data);
747 
748       if(!data->is_function){
749         gdouble fx, fy, fz, fa, fdx, fdy, fdz, fda;
750         gboolean error;
751         gchar *label;
752         gint i;
753 
754         for(i = 0; i < data->num_points; i++){
755           gdouble xi, yi;
756           gtk_plot_data_get_point(data, i,
757                                   &fx, &fy, &fz, &fa, &fdx, &fdy, &fdz, &fda,
758                                   &label, &error);
759           gtk_plot_get_pixel(GTK_PLOT(plot), fx, fy, &xi, &yi);
760           if(abs(xi-x) <= DEFAULT_MARKER_SIZE &&
761              abs(yi-y) <= DEFAULT_MARKER_SIZE){
762 
763             if(canvas->active_item == child &&
764                GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_DATA &&
765                GTK_PLOT_CANVAS_PLOT(child)->data == data &&
766                GTK_PLOT_CANVAS_PLOT(child)->datapoint == i)
767                return GTK_PLOT_CANVAS_IN;
768 
769             canvas_unselect(canvas, child);
770 
771             GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_DATA;
772             GTK_PLOT_CANVAS_PLOT(child)->data = data;
773             GTK_PLOT_CANVAS_PLOT(child)->datapoint = i;
774             child->drag_area.x = xi - DEFAULT_MARKER_SIZE;
775             child->drag_area.y = yi - DEFAULT_MARKER_SIZE;
776             child->drag_area.width = 2*DEFAULT_MARKER_SIZE;
777             child->drag_area.height = 2*DEFAULT_MARKER_SIZE;
778             canvas->drag_area = child->drag_area;
779             child->state = GTK_STATE_SELECTED;
780             child->flags = GTK_PLOT_CANVAS_CHILD_FROZEN;
781             if(GTK_PLOT_CANVAS_PLOT_DND_POINT(GTK_PLOT_CANVAS_PLOT(child)))
782               child->flags = GTK_PLOT_CANVAS_CHILD_CAN_MOVE;
783             child->selection = GTK_PLOT_CANVAS_SELECT_TARGET;
784             child->mode = GTK_PLOT_CANVAS_SELECT_CLICK_1;
785             return GTK_PLOT_CANVAS_IN;
786           }
787         }
788       }
789       dataset = dataset->next;
790     }
791   }
792 
793   /* Actual plot */
794 
795   area = plot->internal_allocation;
796   if((pos = possible_selection(area, x, y)) != GTK_PLOT_CANVAS_OUT) {
797     if(canvas->active_item == child &&
798        GTK_PLOT_CANVAS_PLOT(child)->pos == GTK_PLOT_CANVAS_PLOT_IN_PLOT)
799        return pos;
800 
801     canvas_unselect(canvas, child);
802     child->drag_area = area;
803 
804     GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_IN_PLOT;
805     child->state = GTK_STATE_SELECTED;
806     return pos;
807   }
808 
809 
810   GTK_PLOT_CANVAS_PLOT(child)->pos = GTK_PLOT_CANVAS_PLOT_OUT;
811   return GTK_PLOT_CANVAS_OUT;
812 }
813 
814