summaryrefslogtreecommitdiff
path: root/src/ld-canvas.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ld-canvas.c')
-rw-r--r--src/ld-canvas.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/ld-canvas.c b/src/ld-canvas.c
index 9ee7d5b..7d79fec 100644
--- a/src/ld-canvas.c
+++ b/src/ld-canvas.c
@@ -46,6 +46,11 @@
/* Tolerance on all sides of symbols for strokes. */
#define SYMBOL_CLIP_TOLERANCE 5
+/* Size of a highlighted terminal. */
+#define TERMINAL_RADIUS 5
+/* Tolerance around terminal points. */
+#define TERMINAL_HOVER_TOLERANCE 8
+
/*
* OperationEnd:
*
@@ -73,6 +78,7 @@ enum
COLOR_GRID,
COLOR_OBJECT,
COLOR_SELECTION,
+ COLOR_TERMINAL,
COLOR_COUNT
};
@@ -112,6 +118,9 @@ struct _LdCanvasPrivate
gdouble y;
gdouble zoom;
+ LdPoint terminal;
+ gboolean terminal_highlighted;
+
gint operation;
union
{
@@ -200,8 +209,10 @@ static gboolean get_object_area (LdCanvas *self, LdDiagramObject *object,
LdRectangle *rect);
static gboolean object_hit_test (LdCanvas *self, LdDiagramObject *object,
gdouble x, gdouble y);
+static void check_terminals (LdCanvas *self, gdouble x, gdouble y);
static void queue_draw (LdCanvas *self, LdRectangle *rect);
static void queue_object_draw (LdCanvas *self, LdDiagramObject *object);
+static void queue_terminal_draw (LdCanvas *self, LdPoint *terminal);
static void ld_canvas_real_cancel_operation (LdCanvas *self);
static void ld_canvas_add_object_end (LdCanvas *self);
@@ -210,6 +221,7 @@ static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event,
gpointer user_data);
static void draw_grid (GtkWidget *widget, DrawData *data);
static void draw_diagram (GtkWidget *widget, DrawData *data);
+static void draw_terminal (GtkWidget *widget, DrawData *data);
static void draw_object (LdDiagramObject *diagram_object, DrawData *data);
static void draw_symbol (LdDiagramSymbol *diagram_symbol, DrawData *data);
@@ -302,6 +314,7 @@ ld_canvas_init (LdCanvas *self)
ld_canvas_color_set (COLOR_GET (self, COLOR_GRID), 0.5, 0.5, 0.5, 1);
ld_canvas_color_set (COLOR_GET (self, COLOR_OBJECT), 0, 0, 0, 1);
ld_canvas_color_set (COLOR_GET (self, COLOR_SELECTION), 0, 0, 1, 1);
+ ld_canvas_color_set (COLOR_GET (self, COLOR_TERMINAL), 1, 0.5, 0.5, 1);
g_signal_connect (self, "size-allocate",
G_CALLBACK (on_size_allocate), NULL);
@@ -919,6 +932,72 @@ object_hit_test (LdCanvas *self, LdDiagramObject *object, gdouble x, gdouble y)
}
static void
+check_terminals (LdCanvas *self, gdouble x, gdouble y)
+{
+ GSList *objects, *iter;
+ LdDiagramSymbol *closest_symbol = NULL;
+ gdouble closest_distance = TERMINAL_HOVER_TOLERANCE;
+ LdPoint closest_terminal;
+
+ objects = (GSList *) ld_diagram_get_objects (self->priv->diagram);
+ for (iter = objects; iter; iter = g_slist_next (iter))
+ {
+ LdDiagramObject *diagram_object;
+ gdouble object_x, object_y;
+ LdDiagramSymbol *diagram_symbol;
+ LdSymbol *symbol;
+ const LdPointArray *terminals;
+ gint i;
+
+ if (!LD_IS_DIAGRAM_SYMBOL (iter->data))
+ continue;
+
+ diagram_symbol = LD_DIAGRAM_SYMBOL (iter->data);
+ symbol = resolve_diagram_symbol (self, diagram_symbol);
+ if (!symbol)
+ continue;
+
+ diagram_object = LD_DIAGRAM_OBJECT (iter->data);
+ object_x = ld_diagram_object_get_x (diagram_object);
+ object_y = ld_diagram_object_get_y (diagram_object);
+
+ terminals = ld_symbol_get_terminals (symbol);
+
+ for (i = 0; i < terminals->num_points; i++)
+ {
+ LdPoint cur_term;
+ gdouble distance;
+
+ cur_term = terminals->points[i];
+ cur_term.x += object_x;
+ cur_term.y += object_y;
+ ld_canvas_diagram_to_widget_coords (self,
+ cur_term.x, cur_term.y, &cur_term.x, &cur_term.y);
+
+ distance = ld_point_distance (&cur_term, x, y);
+ if (distance <= closest_distance)
+ {
+ closest_symbol = diagram_symbol;
+ closest_distance = distance;
+ closest_terminal = cur_term;
+ }
+ }
+ }
+
+ if (self->priv->terminal_highlighted)
+ queue_terminal_draw (self, &self->priv->terminal);
+
+ if (closest_symbol)
+ {
+ self->priv->terminal_highlighted = TRUE;
+ self->priv->terminal = closest_terminal;
+ queue_terminal_draw (self, &closest_terminal);
+ }
+ else
+ self->priv->terminal_highlighted = FALSE;
+}
+
+static void
queue_draw (LdCanvas *self, LdRectangle *rect)
{
LdRectangle area;
@@ -942,6 +1021,18 @@ queue_object_draw (LdCanvas *self, LdDiagramObject *object)
}
}
+static void
+queue_terminal_draw (LdCanvas *self, LdPoint *terminal)
+{
+ LdRectangle rect;
+
+ rect.x = terminal->x - TERMINAL_RADIUS;
+ rect.y = terminal->y - TERMINAL_RADIUS;
+ rect.width = 2 * TERMINAL_RADIUS;
+ rect.height = 2 * TERMINAL_RADIUS;
+ queue_draw (self, &rect);
+}
+
static gboolean
on_motion_notify (GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
{
@@ -960,6 +1051,9 @@ on_motion_notify (GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
move_object_to_coords (self, data->object, event->x, event->y);
queue_object_draw (self, data->object);
break;
+ case OPER_0:
+ check_terminals (self, event->x, event->y);
+ break;
}
return FALSE;
}
@@ -1051,6 +1145,7 @@ on_scroll (GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
}
update_adjustments (self);
+ check_terminals (self, event->x, event->y);
gtk_widget_queue_draw (widget);
return TRUE;
}
@@ -1076,6 +1171,7 @@ on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
draw_grid (widget, &data);
draw_diagram (widget, &data);
+ draw_terminal (widget, &data);
cairo_destroy (data.cr);
return FALSE;
@@ -1117,6 +1213,24 @@ draw_grid (GtkWidget *widget, DrawData *data)
}
static void
+draw_terminal (GtkWidget *widget, DrawData *data)
+{
+ LdCanvasPrivate *priv;
+
+ priv = data->self->priv;
+ if (!priv->terminal_highlighted)
+ return;
+
+ ld_canvas_color_apply (COLOR_GET (data->self, COLOR_TERMINAL), data->cr);
+ cairo_set_line_width (data->cr, 1);
+
+ cairo_new_path (data->cr);
+ cairo_arc (data->cr, priv->terminal.x, priv->terminal.y,
+ TERMINAL_RADIUS, 0, 2 * G_PI);
+ cairo_stroke (data->cr);
+}
+
+static void
draw_diagram (GtkWidget *widget, DrawData *data)
{
GSList *objects;