> > 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