[compiz] Annotate, guiding line patches with questions

Mike Dransfield mike at blueroot.co.uk
Tue Jan 2 18:30:35 PST 2007


Attached are my first draft for annotate to add the
guiding lines.

I have added them for line, circle and rectangle
so far.

I have also added an action to quickly change the tool.

I have some questions about them.

1) I used an enum for the tool type but if it is
changed by the tool_next action then it does not 
update in the settings, Is there an easy way to
do this other than a couple of conversion functions?
Does this look like the best way to avoid all the
sring comparisons?

2) It seems like adding text with cairo/opengl would
lead to lots of headaches, limitations and bloat.
My idea is that a seperate helper app could be written
which could provide a palette as well as text entering
functionality.  I could add an extra action to launch 
it, and it could launch the app via dbus to enter text.
Does this sound like a good idea?

3) In the annoHandleMotionEvent I have added a
damageScreen call.  I suspect this should be
damageScreenRegion but in the case of the rectangle
is there much benefit in damaging 4 small rectangles 
rather than the whole thing?

I still need to add onscreen feedback when the tool
changes and I want to add SVG and different line 
endings and tidy things up a bit.  Does everything 
look OK so far?

Regards
Mike

-------------- next part --------------
--- plugins/annotate.c.orig	2006-12-12 18:39:09.046115408 +0000
+++ plugins/annotate.c	2007-01-02 17:14:58.799983264 +0000
@@ -36,6 +36,12 @@
 #define ANNO_ERASE_BUTTON_DEFAULT	    Button3
 #define ANNO_ERASE_BUTTON_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
 
+#define ANNO_PREV_TOOL_BUTTON_DEFAULT	    Button4
+#define ANNO_PREV_TOOL_BUTTON_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
+
+#define ANNO_NEXT_TOOL_BUTTON_DEFAULT	    Button5
+#define ANNO_NEXT_TOOL_BUTTON_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
+
 #define ANNO_CLEAR_KEY_DEFAULT	         "k"
 #define ANNO_CLEAR_KEY_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
 
@@ -70,13 +76,26 @@
 #define ANNO_DISPLAY_OPTION_STROKE_COLOR 5
 #define ANNO_DISPLAY_OPTION_LINE_WIDTH   6
 #define ANNO_DISPLAY_OPTION_STROKE_WIDTH 7
-#define ANNO_DISPLAY_OPTION_NUM	         8
+#define ANNO_DISPLAY_OPTION_TOOL         8
+#define ANNO_DISPLAY_OPTION_TOOL_PREV    9
+#define ANNO_DISPLAY_OPTION_TOOL_NEXT    10
+#define ANNO_DISPLAY_OPTION_NUM	         11
+
+typedef enum {
+    AnnoToolBrush,
+    AnnoToolLine,
+    AnnoToolRectangle,
+    AnnoToolCircle,
+    AnnoToolNull
+} AnnoTool;
 
 typedef struct _AnnoDisplay {
     int		    screenPrivateIndex;
     HandleEventProc handleEvent;
 
     CompOption opt[ANNO_DISPLAY_OPTION_NUM];
+
+    AnnoTool currentTool;
 } AnnoDisplay;
 
 typedef struct _AnnoScreen {
@@ -90,6 +109,8 @@
     Bool            content;
 
     Bool eraseMode;
+
+    int x1, y1;
 } AnnoScreen;
 
 #define GET_ANNO_DISPLAY(d)				     \
@@ -109,6 +130,11 @@
 
 #define NUM_TOOLS (sizeof (tools) / sizeof (tools[0]))
 
+#define DELTA(x, y) (MAX(x, y) - MIN(x, y))
+
+#define CIRCLE_RADIUS(x1, x2, y1, y2) 						\
+	(int) sqrt(pow(DELTA(x1, x2), 2) + pow(DELTA(y1, y2), 2))
+
 static void
 annoCairoClear (CompScreen *s,
 		cairo_t    *cr)
@@ -494,8 +520,8 @@
 	if (state & CompActionStateInitKey)
 	    action->state |= CompActionStateTermKey;
 
-	annoLastPointerX = pointerX;
-	annoLastPointerY = pointerY;
+	as->x1 = annoLastPointerX = pointerX;
+	as->y1 = annoLastPointerY = pointerY;
 
 	as->eraseMode = FALSE;
     }
@@ -513,15 +539,50 @@
     CompScreen *s;
     Window     xid;
 
+    ANNO_DISPLAY(d);
+
     xid = getIntOptionNamed (option, nOption, "root", 0);
 
     for (s = d->screens; s; s = s->next)
     {
-	ANNO_SCREEN (s);
-
 	if (xid && s->root != xid)
 	    continue;
 
+	ANNO_SCREEN (s);
+
+        switch (ad->currentTool)
+        {
+	case AnnoToolLine:
+    	    annoDrawLine (s,
+			  as->x1, as->y1,
+			  pointerX, pointerY,
+			  ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f,
+			  ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c);
+	    break;
+	case AnnoToolRectangle:{
+	    int x, y, h, w;
+	    x = MIN (as->x1, pointerX);
+	    y = MIN (as->y1, pointerY);
+	    w = DELTA (as->x1, pointerX);
+	    h = DELTA (as->y1, pointerY);
+	    annoDrawRectangle (s, x, y, w, h,
+			       ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c,
+			       ad->opt[ANNO_DISPLAY_OPTION_STROKE_COLOR].value.c,
+			       ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f);
+	}
+	    break;
+	case AnnoToolCircle:{
+	    int r = CIRCLE_RADIUS (as->x1, pointerX, as->y1, pointerY);
+
+	    annoDrawCircle (s, as->x1, as->y1, r,
+			      ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c,
+			      ad->opt[ANNO_DISPLAY_OPTION_STROKE_COLOR].value.c,
+			      ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f);
+	}
+	default:
+	    break;
+        }
+
 	if (as->grabIndex)
 	{
 	    removeScreenGrab (s, as->grabIndex, NULL);
@@ -607,6 +668,41 @@
 }
 
 static Bool
+annoToolPrev (CompDisplay     *d,
+	      CompAction      *action,
+	      CompActionState state,
+	      CompOption      *option,
+	      int	      nOption)
+{
+	ANNO_DISPLAY (d);
+
+	ad->currentTool++;
+
+	if (ad->currentTool == AnnoToolNull)
+	    ad->currentTool = 0;
+
+	return TRUE;
+
+}
+
+static Bool
+annoToolNext (CompDisplay     *d,
+	      CompAction      *action,
+	      CompActionState state,
+	      CompOption      *option,
+	      int	      nOption)
+{
+	ANNO_DISPLAY (d);
+
+	if (ad->currentTool == 0)
+	    ad->currentTool = AnnoToolNull;
+
+	ad->currentTool--;
+
+	return TRUE;
+}
+
+static Bool
 annoPaintScreen (CompScreen		 *s,
 		 const ScreenPaintAttrib *sAttrib,
 		 Region			 region,
@@ -616,6 +712,7 @@
     Bool status;
 
     ANNO_SCREEN (s);
+    ANNO_DISPLAY (s->display);
 
     UNWRAP (as, s, paintScreen);
     status = (*s->paintScreen) (s, sAttrib, region, output, mask);
@@ -668,6 +765,58 @@
 	glPopMatrix ();
     }
 
+    /* draw the guiding lines */
+    if (status && as->grabIndex)
+    {
+	glPushMatrix ();
+
+	prepareXCoords (s, output, -DEFAULT_Z_CAMERA);
+
+	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+	glEnable (GL_BLEND);
+	glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
+
+	switch (ad->currentTool)
+	{
+	    case AnnoToolLine:
+		glBegin(GL_LINES);
+		glVertex2i(as->x1, as->y1);
+		glVertex2i(pointerX, pointerY);
+		glEnd ();
+	    break;
+	    case AnnoToolRectangle:
+		glBegin(GL_LINE_LOOP);
+		glVertex2i(as->x1, as->y1);
+		glVertex2i(pointerX, as->y1);
+		glVertex2i(pointerX, pointerY);
+		glVertex2i(as->x1, pointerY);
+		glEnd ();
+	    break;
+	    case AnnoToolCircle:{
+		int radius;
+		float agl;
+
+		radius = CIRCLE_RADIUS (as->x1, pointerX, as->y1, pointerY);
+
+		glBegin(GL_LINE_LOOP);
+		for (agl=0.0f;agl<(2.0f*3.1415927f);agl+=0.1f)
+		    glVertex2i((int) (cos(agl)*radius) + as->x1,
+			       (int) (sin(agl)*radius) + as->y1);
+		glEnd ();
+	    }
+	    default:
+
+	break;
+	}
+
+	glColor4usv(defaultColor);
+
+	glDisable (GL_BLEND);
+	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+	glPopMatrix ();
+    }
+
     return status;
 }
 
@@ -677,6 +826,7 @@
 		       int	  yRoot)
 {
     ANNO_SCREEN (s);
+    ANNO_DISPLAY (s->display);
 
     if (as->grabIndex)
     {
@@ -689,7 +839,7 @@
 			  xRoot, yRoot,
 			  20.0, color);
 	}
-	else
+	else if (ad->currentTool == AnnoToolBrush)
 	{
 	    ANNO_DISPLAY(s->display);
 
@@ -699,6 +849,10 @@
 			  ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f,
 			  ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c);
 	}
+	else
+	{
+	    damageScreen(s);
+	}
 
 	annoLastPointerX = xRoot;
 	annoLastPointerY = yRoot;
@@ -838,6 +992,46 @@
     o->rest.f.min       = ANNO_STROKE_WIDTH_MIN;
     o->rest.f.max       = ANNO_STROKE_WIDTH_MAX;
     o->rest.f.precision = ANNO_STROKE_WIDTH_PRECISION;
+
+    o = &ad->opt[ANNO_DISPLAY_OPTION_TOOL];
+    o->name             = "tool";
+    o->shortDesc        = N_("The current tool");
+    o->longDesc         = N_("The current tool to use (Brush, Rectangle," \
+			     " Line or Circle)");
+    o->type             = CompOptionTypeString;
+    o->value.s          = strdup("");
+    o->rest.s.string    = 0;
+    o->rest.s.nString   = 0;
+
+    o = &ad->opt[ANNO_DISPLAY_OPTION_TOOL_PREV];
+    o->name			     = "tool_prev";
+    o->shortDesc		     = N_("Select the previous tool");
+    o->longDesc			     = N_("Select the previous tool");
+    o->type			     = CompOptionTypeAction;
+    o->value.action.initiate	     = annoToolPrev;
+    o->value.action.terminate	     = 0;
+    o->value.action.bell	     = FALSE;
+    o->value.action.edgeMask	     = 0;
+    o->value.action.type	     = CompBindingTypeButton;
+    o->value.action.state	     = CompActionStateInitButton;
+    o->value.action.state	    |= CompActionStateInitKey;
+    o->value.action.button.modifiers = ANNO_PREV_TOOL_BUTTON_MODIFIERS_DEFAULT;
+    o->value.action.button.button    = ANNO_PREV_TOOL_BUTTON_DEFAULT;
+
+    o = &ad->opt[ANNO_DISPLAY_OPTION_TOOL_NEXT];
+    o->name			     = "tool_next";
+    o->shortDesc		     = N_("Select the next tool");
+    o->longDesc			     = N_("Select the next tool");
+    o->type			     = CompOptionTypeAction;
+    o->value.action.initiate	     = annoToolNext;
+    o->value.action.terminate	     = 0;
+    o->value.action.bell	     = FALSE;
+    o->value.action.edgeMask	     = 0;
+    o->value.action.type	     = CompBindingTypeButton;
+    o->value.action.state	     = CompActionStateInitButton;
+    o->value.action.state	    |= CompActionStateInitKey;
+    o->value.action.button.modifiers = ANNO_NEXT_TOOL_BUTTON_MODIFIERS_DEFAULT;
+    o->value.action.button.button    = ANNO_NEXT_TOOL_BUTTON_DEFAULT;
 }
 
 static CompOption *
@@ -868,6 +1062,8 @@
     case ANNO_DISPLAY_OPTION_INITIATE:
     case ANNO_DISPLAY_OPTION_ERASE:
     case ANNO_DISPLAY_OPTION_CLEAR:
+    case ANNO_DISPLAY_OPTION_TOOL_PREV:
+    case ANNO_DISPLAY_OPTION_TOOL_NEXT:
 	if (setDisplayAction (display, o, value))
 	    return TRUE;
 	break;
@@ -880,6 +1076,20 @@
     case ANNO_DISPLAY_OPTION_STROKE_WIDTH:
 	if (compSetFloatOption (o, value))
 	    return TRUE;
+	break;
+    case ANNO_DISPLAY_OPTION_TOOL:
+	if (compSetStringOption (o, value))
+	{
+	    if (strcmp(value->s, "Line") == 0)
+		ad->currentTool = AnnoToolLine;
+	    else if (strcmp(value->s, "Rectangle") == 0)
+		ad->currentTool = AnnoToolRectangle;
+	    else if (strcmp(value->s, "Circle") == 0)
+		ad->currentTool = AnnoToolCircle;
+	    else
+		ad->currentTool = AnnoToolBrush;
+	    return TRUE;
+	}
     default:
 	break;
     }


More information about the compiz mailing list