Mike Dransfield
2007-Jan-02 17:47 UTC
[compiz] Annotate, guiding line patches with questions
Attached are my first draft for patches to annotate to add the
Mike Dransfield
2007-Jan-02 18:11 UTC
[compiz] Annotate, guiding line patches with questions
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; }