Design for general drag logic
authorThomas White <taw@bitwiz.org.uk>
Tue, 11 Oct 2011 21:38:05 +0000 (23:38 +0200)
committerThomas White <taw@bitwiz.org.uk>
Tue, 11 Oct 2011 21:38:05 +0000 (23:38 +0200)
src/mainwindow.c
src/presentation.c
src/presentation.h
src/slide_render.c
src/tool_select.c
src/tool_text.c

index 6dc82a4..c74abd5 100644 (file)
@@ -609,69 +609,6 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event,
 }
 
 
-static void start_drag_create(struct presentation *p, double x, double y)
-{
-       p->start_corner_x = x;
-       p->start_corner_y = y;
-       p->create_dragging = 1;
-}
-
-
-static void drag_create(struct presentation *p, double x, double y)
-{
-       p->drag_corner_x = x;
-       p->drag_corner_y = y;
-       redraw_overlay(p);
-}
-
-
-static void finish_drag_create(struct presentation *p, double x, double y)
-{
-       p->drag_corner_x = x;
-       p->drag_corner_y = y;
-       p->create_dragging = 0;
-       redraw_overlay(p);
-       p->cur_tool->create_region(p->cur_tool, p,
-                                  p->start_corner_x, p->start_corner_y,
-                                  p->drag_corner_x, p->drag_corner_y);
-}
-
-
-static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event,
-                           struct presentation *p)
-{
-       switch ( p->drag_reason ) {
-
-       case DRAG_REASON_NONE :
-               /* If there was no reason before, now there is */
-               p->drag_reason = DRAG_REASON_CREATE;
-
-               /* Start the drag, and send the first drag event */
-               start_drag_create(p, p->start_create_drag_x,
-                                    p->start_create_drag_y);
-               drag_create(p, event->x - p->border_offs_x,
-                              event->y - p->border_offs_y);
-               break;
-
-       case DRAG_REASON_MOVE :
-               p->cur_tool->drag_object(p->cur_tool, p, p->editing_object,
-                                        event->x - p->border_offs_x,
-                                        event->y - p->border_offs_y);
-               break;
-
-       case DRAG_REASON_CREATE :
-               drag_create(p, event->x - p->border_offs_x,
-                              event->y - p->border_offs_y);
-
-               break;
-
-       }
-
-       gdk_event_request_motions(event);
-       return FALSE;
-}
-
-
 static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
                                  struct presentation *p)
 {
@@ -685,23 +622,33 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
 
        if ( clicked == NULL ) {
 
+               /* Clicked no object. Deselect old object and set up for
+                * (maybe) creating a new one. */
+
                if ( p->editing_object != NULL ) {
                        p->cur_tool->deselect(p->editing_object, p->cur_tool);
                        p->editing_object = NULL;
                }
-               p->start_create_drag_x = x;
-               p->start_create_drag_y = y;
-               p->drag_reason = DRAG_REASON_NONE;
+               p->start_corner_x = event->x - p->border_offs_x;
+               p->start_corner_y = event->y - p->border_offs_y;
+               p->drag_status = DRAG_STATUS_COULD_DRAG;
+               p->drag_reason = DRAG_REASON_CREATE;
 
        } else {
 
-               if ( p->editing_object != NULL ) {
+               /* If the clicked object is not the same as the previously
+                * selected one, deselect the old one. */
+               if ( p->editing_object != clicked ) {
                        p->cur_tool->deselect(p->editing_object, p->cur_tool);
+                       p->editing_object = NULL;
                }
-               p->editing_object = clicked;
-               p->cur_tool->click_select(p, p->cur_tool, x, y);
-               p->drag_reason = DRAG_REASON_MOVE;
 
+               p->editing_object = clicked;
+               p->drag_status = DRAG_STATUS_NONE;
+               p->drag_reason = DRAG_REASON_NONE;
+               p->cur_tool->click_select(p, p->cur_tool, x, y, event,
+                                         &p->drag_status,
+                                         &p->drag_reason);
        }
 
        gtk_widget_grab_focus(GTK_WIDGET(da));
@@ -710,6 +657,41 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
 }
 
 
+static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event,
+                           struct presentation *p)
+{
+       if ( p->drag_status == DRAG_STATUS_COULD_DRAG ) {
+
+               /* We just got a motion signal, and the status was "could drag",
+                * therefore the drag has started. */
+               p->drag_status = DRAG_STATUS_DRAGGING;
+
+       }
+
+       switch ( p->drag_reason ) {
+
+       case DRAG_REASON_NONE :
+               break;
+
+       case DRAG_REASON_CREATE :
+               p->drag_corner_x = event->x - p->border_offs_x;
+               p->drag_corner_y = event->y - p->border_offs_y;
+               redraw_overlay(p);
+               break;
+
+       case DRAG_REASON_TOOL :
+               p->cur_tool->drag(p->cur_tool, p, p->editing_object,
+                                 event->x - p->border_offs_x,
+                                 event->y - p->border_offs_y);
+               break;
+
+       }
+
+       gdk_event_request_motions(event);
+       return FALSE;
+}
+
+
 static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event,
                                    struct presentation *p)
 {
@@ -718,22 +700,37 @@ static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event,
        x = event->x - p->border_offs_x;
        y = event->y - p->border_offs_y;
 
-       switch ( p->drag_reason ) {
+       /* Not dragging?  Then I don't care. */
+       if ( p->drag_status != DRAG_STATUS_DRAGGING ) return FALSE;
+
+       p->drag_corner_x = x;
+       p->drag_corner_y = y;
+       p->drag_status = DRAG_STATUS_NONE;
+
+       switch ( p->drag_reason )
+       {
 
        case DRAG_REASON_NONE :
-               p->cur_tool->click_create(p, p->cur_tool, x, y);
+               printf("Release on pointless drag.\n");
                break;
 
        case DRAG_REASON_CREATE :
-               finish_drag_create(p, x, y);
-               break;
-
-       case DRAG_REASON_MOVE :
-               /* FIXME: Update presentation and other stuff? */
+               redraw_overlay(p);
+               p->cur_tool->create_region(p->cur_tool, p,
+                                          p->start_corner_x,
+                                          p->start_corner_y,
+                                          p->drag_corner_x,
+                                          p->drag_corner_y);
+       break;
+
+       case DRAG_REASON_TOOL :
+               p->cur_tool->end_drag(p->cur_tool, p, p->editing_object, x, y);
                break;
 
        }
 
+       p->drag_reason = DRAG_REASON_NONE;
+
        gtk_widget_grab_focus(GTK_WIDGET(da));
        redraw_overlay(p);
        return FALSE;
@@ -771,7 +768,9 @@ static void draw_overlay(cairo_t *cr, struct presentation *p)
                cairo_stroke(cr);
        }
 
-       if ( p->create_dragging ) {
+       if ( (p->drag_status == DRAG_STATUS_DRAGGING)
+         && (p->drag_reason == DRAG_REASON_CREATE) ) {
+
                cairo_new_path(cr);
                cairo_rectangle(cr, p->start_corner_x, p->start_corner_y,
                                    p->drag_corner_x - p->start_corner_x,
@@ -779,6 +778,7 @@ static void draw_overlay(cairo_t *cr, struct presentation *p)
                cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
                cairo_set_line_width(cr, 0.5);
                cairo_stroke(cr);
+
        }
 }
 
index c66507d..b05ba4b 100644 (file)
@@ -220,6 +220,7 @@ struct presentation *new_presentation()
 
        new->editing_object = NULL;
        new->completely_empty = 1;
+       new->drag_status = DRAG_STATUS_NONE;
 
        new->ss = new_stylesheet();
 
index a06fbc9..5b319ab 100644 (file)
@@ -50,7 +50,15 @@ enum drag_reason
 {
        DRAG_REASON_NONE,
        DRAG_REASON_CREATE,
-       DRAG_REASON_MOVE,
+       DRAG_REASON_TOOL,
+};
+
+
+enum drag_status
+{
+       DRAG_STATUS_NONE,
+       DRAG_STATUS_COULD_DRAG,
+       DRAG_STATUS_DRAGGING,
 };
 
 
@@ -59,13 +67,17 @@ struct toolinfo
        void (*click_create)(struct presentation *p, struct toolinfo *tip,
                             double x, double y);
        void (*click_select)(struct presentation *p, struct toolinfo *tip,
-                            double x, double y);
+                            double x, double y, GdkEventButton *event,
+                            enum drag_status *drag_status,
+                            enum drag_reason *drag_reason);
        void (*create_default)(struct presentation *p, struct style *sty,
                               struct toolinfo *tip);
        void (*select)(struct object *o, struct toolinfo *tip);
        int  (*deselect)(struct object *o, struct toolinfo *tip);
-       void (*drag_object)(struct toolinfo *tip, struct presentation *p,
-                           struct object *o, double x, double y);
+       void (*drag)(struct toolinfo *tip, struct presentation *p,
+                    struct object *o, double x, double y);
+       void (*end_drag)(struct toolinfo *tip, struct presentation *p,
+                        struct object *o, double x, double y);
 
        void (*create_region)(struct toolinfo *tip, struct presentation *p,
                              double x1, double y1, double x2, double y2);
@@ -128,16 +140,14 @@ struct presentation
 
        /* Tool status */
        struct toolinfo  *cur_tool;
-       double            drag_offs_x;
-       double            drag_offs_y;
-       double            start_create_drag_x;
-       double            start_create_drag_y;
-       int               create_dragging;
+
+       /* Rubber band boxes and related stuff */
        double            start_corner_x;
        double            start_corner_y;
        double            drag_corner_x;
        double            drag_corner_y;
        enum drag_reason  drag_reason;
+       enum drag_status  drag_status;
 
        unsigned int      num_slides;
        struct slide    **slides;
index 3c05f70..e68499a 100644 (file)
@@ -82,9 +82,20 @@ void check_redraw_slide(struct slide *s)
 void draw_editing_box(cairo_t *cr, double xmin, double ymin,
                       double width, double height)
 {
+       const double dash[] = {2.0, 2.0};
+
        cairo_new_path(cr);
        cairo_rectangle(cr, xmin-5.0, ymin-5.0, width+10.0, height+10.0);
        cairo_set_source_rgb(cr, 0.0, 0.69, 1.0);
        cairo_set_line_width(cr, 0.5);
        cairo_stroke(cr);
+
+       cairo_new_path(cr);
+       cairo_rectangle(cr, xmin, ymin, width, height);
+       cairo_set_dash(cr, dash, 2, 0.0);
+       cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+       cairo_set_line_width(cr, 0.1);
+       cairo_stroke(cr);
+
+       cairo_set_dash(cr, NULL, 0, 0.0);
 }
index c03ebd1..57e6721 100644 (file)
@@ -51,18 +51,23 @@ static void click_create(struct presentation *p, struct toolinfo *tip,
 
 
 static void click_select(struct presentation *p, struct toolinfo *tip,
-                         double x, double y)
+                         double x, double y, GdkEventButton *event,
+                         enum drag_status *drag_status,
+                        enum drag_reason *drag_reason)
 {
        struct select_toolinfo *ti = (struct select_toolinfo *)tip;
        struct object *clicked = p->editing_object;
 
        ti->drag_offs_x = clicked->x - x;
        ti->drag_offs_y = clicked->y - y;
+
+       *drag_status = DRAG_STATUS_COULD_DRAG;
+       *drag_reason = DRAG_REASON_TOOL;
 }
 
 
-static void drag_object(struct toolinfo *tip, struct presentation *p,
-                        struct object *o, double x, double y)
+static void drag(struct toolinfo *tip, struct presentation *p,
+                 struct object *o, double x, double y)
 {
        struct select_toolinfo *ti = (struct select_toolinfo *)tip;
        double eright, ebottom;
@@ -85,6 +90,13 @@ static void drag_object(struct toolinfo *tip, struct presentation *p,
 }
 
 
+static void end_drag(struct toolinfo *tip, struct presentation *p,
+                     struct object *o, double x, double y)
+{
+       /* FIXME: Update projection or something? */
+}
+
+
 static void create_region(struct toolinfo *tip, struct presentation *p,
                           double x1, double y1, double x2, double y2)
 {
@@ -136,7 +148,8 @@ struct toolinfo *initialise_select_tool()
        ti->base.create_default = NULL;
        ti->base.select = select_object;
        ti->base.deselect = deselect_object;
-       ti->base.drag_object = drag_object;
+       ti->base.drag = drag;
+       ti->base.end_drag = end_drag;
        ti->base.create_region = create_region;
        ti->base.draw_editing_overlay = draw_overlay;
        ti->base.key_pressed = key_pressed;
index a7f27c2..4af8b8e 100644 (file)
 #include "slide_render.h"
 
 
+enum text_drag_reason
+{
+       TEXT_DRAG_REASON_NONE,
+       TEXT_DRAG_REASON_RESIZE,
+};
+
+
 struct text_toolinfo
 {
-       struct toolinfo  base;
-       PangoContext    *pc;
+       struct toolinfo        base;
+       PangoContext          *pc;
+       enum text_drag_reason  drag_reason;
+       double                 box_x;
+       double                 box_y;
+       double                 box_width;
+       double                 box_height;
+       double                 drag_offset_x;
+       double                 drag_offset_y;
 };
 
 
@@ -446,17 +460,48 @@ static void click_create(struct presentation *p, struct toolinfo *tip,
 
 
 static void click_select(struct presentation *p, struct toolinfo *tip,
-                         double x, double y)
+                         double x, double y, GdkEventButton *event,
+                         enum drag_status *drag_status,
+                        enum drag_reason *drag_reason)
 {
        int xp, yp;
+       double xo, yo;
        gboolean v;
+       struct text_toolinfo *ti = (struct text_toolinfo *)tip;
        struct text_object *o = (struct text_object *)p->editing_object;
        int idx, trail;
 
        assert(o->base.type == TEXT);
 
-       xp = (x - o->base.x + o->offs_x)*PANGO_SCALE;
-       yp = (y - o->base.y + o->offs_y)*PANGO_SCALE;
+       xo = x - o->base.x;  yo = y - o->base.y;
+
+       /* Within the resizing region? */
+       if ( (xo > o->base.bb_width - 20.0) && (yo > o->base.bb_height - 20.0) )
+       {
+               double cx, cy;
+
+               ti->drag_reason = TEXT_DRAG_REASON_RESIZE;
+
+               /* Initial size of rubber band box */
+               ti->box_x = o->base.x;  ti->box_y = o->base.y;
+               ti->box_width = o->base.bb_width;
+               ti->box_height = o->base.bb_height;
+
+               /* Coordinates of the bottom right corner */
+               cx = o->base.x + o->base.bb_width;
+               cy = o->base.y + o->base.bb_height;
+
+               ti->drag_offset_x = x - cx;
+               ti->drag_offset_y = y - cy;
+
+               /* Tell the MCP what we did, and return */
+               *drag_status = DRAG_STATUS_DRAGGING;
+               *drag_reason = DRAG_REASON_TOOL;
+               return;
+       }
+
+       xp = (xo + o->offs_x)*PANGO_SCALE;
+       yp = (yo + o->offs_y)*PANGO_SCALE;
 
        v = pango_layout_xy_to_index(o->layout, xp, yp, &idx, &trail);
 
@@ -465,10 +510,37 @@ static void click_select(struct presentation *p, struct toolinfo *tip,
 }
 
 
-static void drag_object(struct toolinfo *tip, struct presentation *p,
-                        struct object *o, double x, double y)
+static void drag(struct toolinfo *tip, struct presentation *p,
+                 struct object *o, double x, double y)
 {
-       /* Do nothing */
+       struct text_toolinfo *ti = (struct text_toolinfo *)tip;
+
+       ti->box_width = x - ti->drag_offset_x - ti->box_x;
+       ti->box_height = y - ti->drag_offset_y - ti->box_y;
+       if ( ti->box_width < 20.0 ) ti->box_width = 20.0;
+       if ( ti->box_height < 20.0 ) ti->box_height = 20.0;
+
+       redraw_overlay(p);
+}
+
+
+static void end_drag(struct toolinfo *tip, struct presentation *p,
+                     struct object *o, double x, double y)
+{
+       struct text_toolinfo *ti = (struct text_toolinfo *)tip;
+
+       ti->box_width = x - ti->drag_offset_x - ti->box_x;
+       ti->box_height = y - ti->drag_offset_y - ti->box_y;
+       if ( ti->box_width < 20.0 ) ti->box_width = 20.0;
+       if ( ti->box_height < 20.0 ) ti->box_height = 20.0;
+
+       o->bb_width = ti->box_width;
+       o->bb_height = ti->box_height;
+       update_text((struct text_object *)o);
+       o->parent->object_seq++;
+
+       ti->drag_reason = TEXT_DRAG_REASON_NONE;
+       redraw_overlay(p);
 }
 
 
@@ -524,10 +596,33 @@ static int deselect_object(struct object *o, struct toolinfo *tip)
 
 static void draw_overlay(struct toolinfo *tip, cairo_t *cr, struct object *o)
 {
+       struct text_toolinfo *ti = (struct text_toolinfo *)tip;
+
        if ( o != NULL ) {
+
                draw_editing_box(cr, o->x, o->y, o->bb_width, o->bb_height);
+
+               cairo_new_path(cr);
+               cairo_rectangle(cr, o->x+o->bb_width-20.0,
+                                   o->y+o->bb_height-20.0, 20.0, 20.0);
+               cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 0.2);
+               cairo_fill(cr);
+
                draw_caret(cr, o);
        }
+
+       if ( ti->drag_reason == TEXT_DRAG_REASON_RESIZE ) {
+
+               /* FIXME: Use common draw_rubberband_box() routine */
+               cairo_new_path(cr);
+               cairo_rectangle(cr, ti->box_x, ti->box_y,
+                                   ti->box_width, ti->box_height);
+               cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+               cairo_set_line_width(cr, 0.5);
+               cairo_stroke(cr);
+
+       }
+
 }
 
 
@@ -572,7 +667,8 @@ struct toolinfo *initialise_text_tool(GtkWidget *w)
        ti->base.create_default = create_default;
        ti->base.select = select_object;
        ti->base.deselect = deselect_object;
-       ti->base.drag_object = drag_object;
+       ti->base.drag = drag;
+       ti->base.end_drag = end_drag;
        ti->base.create_region = create_region;
        ti->base.draw_editing_overlay = draw_overlay;
        ti->base.key_pressed = key_pressed;