[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