Re: Patch: changing % complete by dragging in gantt (corrected)



> > I've attached a patch that allows you to change the % complete for a
> > task by dragging it in the gantt chart. 
> 
> I like it, except that cursor movement seems to automatically scroll the
> gantt pane, which at first I thought was cool, but then decided it
> wasn't such a good idea since the user has no contol over the scrolling
> effect (i.e. it even scrolls when another application has focus, and the
> mouse is moved to navigate within that application).
> 
> If you have a look at fixing that, I'll be happy to give it another go.

I fixed my patch (see attachment). The problem was that I did not remove
the scroll timeout when the mouse button was released.

When looking at this issue, I noticed that dragging the duration does
not use the scroll timeout. This means that you cannot drag the duration
beyond the end of the viewport. Is this intended behaviour?

Regards,
Maurice.

-- 
Maurice van der Pot

Gentoo Linux Developer   griffon26 gentoo org     http://www.gentoo.org
Creator of BiteMe!       griffon26 kfk4ever com   http://www.kfk4ever.com

Index: src/planner-gantt-row.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-gantt-row.c,v
retrieving revision 1.31
diff -u -B -r1.31 planner-gantt-row.c
--- src/planner-gantt-row.c	12 Nov 2006 20:26:31 -0000	1.31
+++ src/planner-gantt-row.c	12 Feb 2007 18:05:44 -0000
@@ -55,6 +55,8 @@
 
 #define MILESTONE_SIZE 5
 
+#define FUZZ  3
+
 /* Minimum width for a task to keep it visible. */
 #define MIN_WIDTH 2
 
@@ -97,10 +99,19 @@
 	STATE_NONE          = 0,
 	STATE_DRAG_LINK     = 1 << 0,
 	STATE_DRAG_DURATION = 1 << 1,
+	STATE_DRAG_COMPLETE = 1 << 2,
 
-	STATE_DRAG_ANY = STATE_DRAG_LINK | STATE_DRAG_DURATION
+	STATE_DRAG_ANY = STATE_DRAG_LINK | STATE_DRAG_DURATION | STATE_DRAG_COMPLETE
 } State;
 
+typedef enum
+{
+	DRAG_NONE_SPOT,
+	DRAG_DURATION_SPOT,
+	DRAG_COMPLETE_SPOT,
+	DRAG_RELATION_SPOT
+} DragSpot;
+
 struct _PlannerGanttRowPriv {
 	/* FIXME: Don't need those per gantt row. */
 	GdkGC       *complete_gc;
@@ -2305,13 +2316,48 @@
 	return TRUE;
 }
 
-#define IN_DRAG_DURATION_SPOT(x,y,right,top,ymin,ymax)	\
-	((abs (x - (right)) <= 3) && \
-	 (y > top + ymin) && (y < top + ymax))
-
-#define IN_DRAG_RELATION_SPOT(x,y,right,top,ymin,ymax)	\
-	((x <= right) && \
-	 (y > top + ymin) && (y < top + ymax))
+static DragSpot get_drag_spot(gdouble x, gdouble y, PlannerGanttRowPriv *priv)
+{
+	gdouble x2 = priv->x + priv->width;
+	if( (y > priv->y + priv->bar_top) &&
+	    (y < priv->y + priv->bar_bot) &&
+	    (x < x2 + FUZZ) ) {
+		gdouble complete_x2 = priv->x + floor(priv->width * (mrp_task_get_percent_complete (priv->task) / 100.0) + 0.5);
+
+		/* if not way left of end of completion bar */
+		if(x > complete_x2 - FUZZ) {
+
+			/* if end of completion bar and end of task bar are not very close together */
+			if(x2 - complete_x2 > 2 * FUZZ) {
+
+				/* if not way right of the completion bar */
+				if(x < complete_x2 + FUZZ) {
+					return DRAG_COMPLETE_SPOT;
+				} else { /* if way right of completion bar and ... */
+
+					/* if less than FUZZ from the end of the task bar */
+					if(x > x2 - FUZZ) {
+						return DRAG_DURATION_SPOT;
+					} else { /* if more than FUZZ left of the end of the task bar */
+						return DRAG_RELATION_SPOT;
+					}
+				}
+			} else { /* if DRAG_DURATION_SPOT and DRAG_COMPLETE_SPOT are connected and ... */
+
+				/* if closer to the end of the task bar than to the end of the completion bar */
+				if(x > complete_x2 + (x2 - complete_x2) / 2) {
+					return DRAG_DURATION_SPOT;
+				} else {
+					return DRAG_COMPLETE_SPOT;
+				}
+			}
+		} else { /* if way left of end of completion bar */
+			return DRAG_RELATION_SPOT;
+		}
+	} else { /* above, below or too far to the right of bar */
+		return DRAG_NONE_SPOT;
+	}
+}
 
 static gboolean
 gantt_row_event (GnomeCanvasItem *item, GdkEvent *event)
@@ -2333,6 +2379,7 @@
 	gboolean                  summary;
 	MrpTaskType               type;
 	gchar                    *message;
+	DragSpot                  drag_spot;
 	
 	row = PLANNER_GANTT_ROW (item);
 	priv = row->priv;
@@ -2345,9 +2392,9 @@
 	case GDK_BUTTON_PRESS:
 		switch (event->button.button) {
 		case 3:
-			if (IN_DRAG_RELATION_SPOT (event->button.x, event->button.y,
-						   priv->x + priv->width, priv->y, 
-						   priv->bar_top, priv->bar_bot)) {
+			drag_spot = get_drag_spot(event->button.x, event->button.y, priv);
+
+			if (drag_spot == DRAG_RELATION_SPOT) {
 				PlannerGanttChart *chart;
 				PlannerTaskTree   *tree;
 				GtkTreePath       *path;
@@ -2395,13 +2442,10 @@
 				break;
 			}
 
+			drag_spot = get_drag_spot(event->button.x, event->button.y, priv);
+
 			if (type != MRP_TASK_TYPE_MILESTONE &&
-			    !summary && IN_DRAG_DURATION_SPOT (event->button.x,
-							       event->button.y,
-							       priv->x + priv->width,
-							       priv->y,
-							       priv->bar_top, 
-							       priv->bar_bot)) {
+			    !summary && drag_spot == DRAG_DURATION_SPOT) {
 				guint rgba;
 				
 				priv->state = STATE_DRAG_DURATION;
@@ -2430,12 +2474,43 @@
 									   NULL);
 					gnome_canvas_item_hide (drag_item);
 				}
-			} else if (IN_DRAG_RELATION_SPOT (event->button.x,
-							  event->button.y,
-							  priv->x + priv->width,
-							  priv->y,
-							  priv->bar_top, 
-							  priv->bar_bot)) {
+			} else if (type != MRP_TASK_TYPE_MILESTONE &&
+			    !summary && drag_spot == DRAG_COMPLETE_SPOT) {
+				guint rgba;
+
+				priv->state = STATE_DRAG_COMPLETE;
+
+				wx1 = priv->x;
+				wy1 = priv->y + priv->bar_top + 4;
+				wx2 = event->button.x;
+				wy2 = priv->y + priv->bar_bot - 4;
+
+				gnome_canvas_item_i2w (item, &wx1, &wy1);
+				gnome_canvas_item_i2w (item, &wx2, &wy2);
+
+				/*      red            green          blue          alpha */
+				rgba = (0xb7 << 24) | (0xc3 << 16) | (0xc9 << 8) | (127 << 0);
+				
+				if (drag_item == NULL) {
+					drag_item = gnome_canvas_item_new (gnome_canvas_root (item->canvas),
+									   EEL_TYPE_CANVAS_RECT,
+									   "x1", wx1,
+									   "y1", wy1,
+									   "x2", wx2,
+									   "y2", wy2,
+									   "fill_color_rgba", rgba,
+									   "outline_color_rgba", 0,
+									   "width_pixels", 1,
+									   NULL);
+					gnome_canvas_item_hide (drag_item);
+				}
+
+				/* Start the autoscroll timeout. */
+				priv->scroll_timeout_id = gtk_timeout_add (
+					50,
+					(GSourceFunc) gantt_row_scroll_timeout_cb,
+					row);
+			} else if (drag_spot == DRAG_RELATION_SPOT) {
 				priv->state = STATE_DRAG_LINK;
 				if (drag_points == NULL) {
 					drag_points = gnome_canvas_points_new (2);
@@ -2531,17 +2606,23 @@
 		}
 
 		if (!(priv->state & STATE_DRAG_ANY)) {
-			if (type != MRP_TASK_TYPE_MILESTONE &&
-			    !summary && IN_DRAG_DURATION_SPOT (event->button.x,
-							       event->button.y,
-							       priv->x + priv->width,
-							       priv->y,
-							       priv->bar_top, 
-							       priv->bar_bot)) {
-				cursor = gdk_cursor_new (GDK_RIGHT_SIDE);
-				gdk_window_set_cursor (canvas_widget->window, cursor);
-				if (cursor) {
-					gdk_cursor_unref (cursor);
+			drag_spot = get_drag_spot(event->button.x, event->button.y, priv);
+
+			if (type != MRP_TASK_TYPE_MILESTONE && !summary && 
+			    ( (drag_spot == DRAG_DURATION_SPOT) || (drag_spot == DRAG_COMPLETE_SPOT) ) ) {
+				if(drag_spot == DRAG_DURATION_SPOT) {
+					cursor = gdk_cursor_new (GDK_RIGHT_SIDE);
+					gdk_window_set_cursor (canvas_widget->window, cursor);
+					if (cursor) {
+						gdk_cursor_unref (cursor);
+					}
+				}
+				else { /* DRAG_COMPLETE_SPOT */
+					cursor = gdk_cursor_new (GDK_HAND2);
+					gdk_window_set_cursor (canvas_widget->window, cursor);
+					if (cursor) {
+						gdk_cursor_unref (cursor);
+					}
 				}
 			} else { /* Mouse over resource names (or short_name) ? */
  				gint res_index;
@@ -2625,6 +2706,24 @@
 			
 			old_target_item = target_item;
 		}
+		else if (priv->state == STATE_DRAG_COMPLETE) {
+			chart = g_object_get_data (G_OBJECT (item->canvas), "chart");
+
+			wx2 = MIN(event->motion.x, priv->x + priv->width);
+			wy2 = priv->y + priv->bar_bot - 4;
+			
+			gnome_canvas_item_i2w (item, &wx2, &wy2);
+
+			gnome_canvas_item_set (drag_item,
+					       "x2", wx2,
+					       "y2", wy2,
+					       NULL);
+			
+			gnome_canvas_item_raise_to_top (drag_item);
+			gnome_canvas_item_show (drag_item);
+
+			planner_gantt_chart_status_updated (chart, NULL);
+		}
 		else if (priv->state == STATE_DRAG_DURATION) {
 			gint         duration;
 			gint         work;
@@ -2718,6 +2817,32 @@
 
 			planner_gantt_chart_status_updated (chart, NULL);
 		}
+		else if (priv->state == STATE_DRAG_COMPLETE) {
+			GValue      value = { 0 };
+			gint        percent_complete = floor((MIN(MAX(0, event->button.x - priv->x), priv->width) * 100.0) / priv->width + 0.5);
+
+			chart = g_object_get_data (G_OBJECT (item->canvas), "chart");
+			tree = planner_gantt_chart_get_view (chart);
+
+			g_value_init (&value, G_TYPE_INT);
+			g_value_set_int (&value, percent_complete);
+
+			task_cmd_edit_property (planner_task_tree_get_window (tree),
+						tree,
+						priv->task,
+						"percent_complete", 
+						&value);
+
+			if (priv->scroll_timeout_id) {
+				g_source_remove (priv->scroll_timeout_id);
+				priv->scroll_timeout_id = 0;
+			}
+
+			gtk_object_destroy (GTK_OBJECT (drag_item));
+			drag_item = NULL;
+
+			planner_gantt_chart_status_updated (chart, NULL);
+		}
 		else if (priv->state == STATE_DRAG_LINK) {
 			if (old_target_item) {
 				g_object_set (old_target_item,
@@ -2835,9 +2960,8 @@
 		
 	case GDK_2BUTTON_PRESS:
 		if (event->button.button == 1) {
-			if (IN_DRAG_RELATION_SPOT (event->button.x, event->button.y,
-						   priv->x + priv->width, priv->y, 
-						   priv->bar_top, priv->bar_bot)) {
+			drag_spot = get_drag_spot(event->button.x, event->button.y, priv);
+			if (drag_spot == DRAG_RELATION_SPOT) {
 				PlannerTaskTree  *tree;
 				GtkTreePath      *path;
 				GtkTreeSelection *selection;

Attachment: pgpKlOLhuXMz2.pgp
Description: PGP signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]