diff options
Diffstat (limited to 'app/wlib/gtklib/gtkdraw-cairo.c')
-rw-r--r-- | app/wlib/gtklib/gtkdraw-cairo.c | 995 |
1 files changed, 738 insertions, 257 deletions
diff --git a/app/wlib/gtklib/gtkdraw-cairo.c b/app/wlib/gtklib/gtkdraw-cairo.c index 5042667..4498a2c 100644 --- a/app/wlib/gtklib/gtkdraw-cairo.c +++ b/app/wlib/gtklib/gtkdraw-cairo.c @@ -32,6 +32,9 @@ #include <gtk/gtk.h> #include <gdk/gdk.h> +// Trace low level drawing actions +int iDrawLog = 0; + #include "gtkint.h" #include "gdk/gdkkeysyms.h" @@ -41,12 +44,16 @@ static long drawVerbose = 0; +// Hack to do TempRedraw or MainRedraw +// For Windows only +wBool_t wDrawDoTempDraw = TRUE; + struct wDrawBitMap_t { int w; int h; int x; int y; - const char * bits; + const unsigned char * bits; GdkPixmap * pixmap; GdkBitmap * mask; }; @@ -102,64 +109,148 @@ struct wDraw_t psPrint_d; * *******************************************************************************/ - - -static GdkGC * selectGC( - wDraw_p bd, +static cairo_t* gtkDrawCreateCairoCursorContext( + wControl_p ct, + cairo_surface_t * surf, wDrawWidth width, wDrawLineType_e lineType, wDrawColor color, wDrawOpts opts ) { - if(width < 0.0) - { - width = - width; - } + cairo_t* cairo; + + cairo = cairo_create(surf); + + width = width ? abs(width) : 1; + cairo_set_line_width(cairo, width); + + cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(cairo, CAIRO_LINE_JOIN_MITER); - if(opts & wDrawOptTemp) + switch(lineType) { - if(bd->lastColor != color || !bd->lastColorInverted) + case wDrawLineSolid: { - gdk_gc_set_foreground( bd->gc, wlibGetColor(color,FALSE) ); - bd->lastColor = color; - bd->lastColorInverted = TRUE; + cairo_set_dash(cairo, 0, 0, 0); + break; } - gdk_gc_set_function( bd->gc, GDK_XOR ); - gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER ); - } - else - { - if(bd->lastColor != color || bd->lastColorInverted) + case wDrawLineDash: { - gdk_gc_set_foreground( bd->gc, wlibGetColor(color,TRUE) ); - bd->lastColor = color; - bd->lastColorInverted = FALSE; + double dashes[] = { 5, 3 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; } - gdk_gc_set_function( bd->gc, GDK_COPY ); - if (lineType==wDrawLineDash) + case wDrawLineDot: { - gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER ); + double dashes[] = { 1, 2 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; } - else + case wDrawLineDashDot: + { + double dashes[] = { 5, 2, 1, 2 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; + } + case wDrawLineDashDotDot: { - gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER ); + double dashes[] = { 5, 2, 1, 2, 1, 2 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; + } + case wDrawLineCenter: + { + double dashes[] = { 8, 3, 5, 3}; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0.0); + break; + } + case wDrawLinePhantom: + { + double dashes[] = { 8, 3, 5, 3, 5, 3}; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0.0); + break; } - gdk_gc_set_function(bd->gc, GDK_NOOP); } - return bd->gc; + GdkColor * gcolor; + + + cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); + gcolor = wlibGetColor(color, TRUE); + + if (ct->type == B_DRAW) { + wDraw_p bd = (wDraw_p)ct; + bd->lastColor = color; + } + + cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 1.0); + + return cairo; +} + + +wBool_t wDrawSetTempMode( + wDraw_p bd, + wBool_t bTemp ) +{ + wBool_t ret = bd->bTempMode; + bd->bTempMode = bTemp; + if ( ret == FALSE && bTemp == TRUE ) { + // Main to Temp drawing + wDrawClearTemp( bd ); + } + return ret; } static cairo_t* gtkDrawCreateCairoContext( wDraw_p bd, + GdkDrawable * win, wDrawWidth width, wDrawLineType_e lineType, wDrawColor color, wDrawOpts opts ) { - cairo_t* cairo = gdk_cairo_create(bd->pixmap); + cairo_t* cairo; + + if (win) + cairo = gdk_cairo_create(win); + else { + if (opts & wDrawOptTemp) { + if ( ! bd->bTempMode ) + printf( "Temp draw in Main Mode. Contact Developers. See %s:%d\n", "gtkdraw-cario.c", __LINE__+1 ); +/* Temp Draw In Main Mode: + You are seeing this message because there is a wDraw*() call on tempD but you are not in the context of TempRedraw() + Typically this happens when Cmd<Object>() is processing a C_DOWN or C_MOVE action and it writes directly to tempD + Instead it sould set some state which allows c_redraw to do the actual drawing + If you set a break point on the printf you'll see the offending wDraw*() call in the traceback + It should be sufficient to remove that draw code or move it to C_REDRAW + This is not fatal but the draw will be ineffective because the next TempRedraw() will erase the temp surface + before the expose event can copy (or bitblt) it +*/ + cairo = cairo_create(bd->temp_surface); + } else { + if ( bd->bTempMode ) + printf( "Main draw in Temp Mode. Contact Developers. See %s:%d\n", "gtkdraw-cario.c", __LINE__+1 ); +/* Main Draw In Temp Mode: + You are seeing this message because there is a wDraw*() call on mainD but you are in the context of TempRedraw() + Typically this happens when C_REDRAW action calls wDraw*() on mainD, in which case it should be writing to tempD. + Or the wDraw*() call should be removed if it is redundant. + If you set a break point on the printf you'll see the offending wDraw*() call in the traceback + This is not fatal but could result in garbage being left on the screen if the command is cancelled. +*/ + cairo = gdk_cairo_create(bd->pixmap); + } + } width = width ? abs(width) : 1; + if ( color == wDrawColorWhite ) + width += 1; // Remove ghosts cairo_set_line_width(cairo, width); cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT); @@ -179,24 +270,52 @@ static cairo_t* gtkDrawCreateCairoContext( cairo_set_dash(cairo, dashes, len_dashes, 0); break; } - } + case wDrawLineDot: + { + double dashes[] = { 1, 2 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; + } + case wDrawLineDashDot: + { + double dashes[] = { 5, 2, 1, 2 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; + } + case wDrawLineDashDotDot: + { + double dashes[] = { 5, 2, 1, 2, 1, 2 }; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0); + break; + } + case wDrawLineCenter: + { + double dashes[] = { 8, 3, 5, 3}; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0.0); + break; + } + case wDrawLinePhantom: + { + double dashes[] = { 8, 3, 5, 3, 5, 3}; + static int len_dashes = sizeof(dashes) / sizeof(dashes[0]); + cairo_set_dash(cairo, dashes, len_dashes, 0.0); + break; + } - if(opts & wDrawOptTemp) - { - cairo_set_source_rgba(cairo, 0, 0, 0, 0); - cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); - } - else - { - long rgbcolor = wDrawGetRGB(color); - int r0, g0, b0; - r0 = (int)(rgbcolor>>16)&0xFF; - g0 = (int)(rgbcolor>>8)&0xFF; - b0 = (int)(rgbcolor)&0xFF; - cairo_set_source_rgb(cairo, r0/255.0, g0/255.0, b0/255.0); - - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); } + GdkColor * gcolor; + + + cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); + gcolor = wlibGetColor(color, TRUE); + + bd->lastColor = color; + + cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0); return cairo; } @@ -206,6 +325,36 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { return NULL; } +#ifdef CURSOR_SURFACE +cairo_t* CreateCursorSurface(wControl_p ct, wSurface_p surface, wPos_t width, wPos_t height, wDrawColor color, wDrawOpts opts) { + + cairo_t * cairo = NULL; + + if ((opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv)) { + + if (surface!=NULL || surface->width != width || surface->height != height) { + if (surface->surface) cairo_surface_destroy(surface->surface); + surface->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width,height ); + surface->width = width; + surface->height = height; + + } + + cairo = gtkDrawCreateCairoCursorContext(ct,surface->surface,0,wDrawLineSolid, color, opts); + cairo_save(cairo); + cairo_set_source_rgba(cairo, 0.0, 0.0, 0.0, 0.0); + cairo_paint(cairo); + cairo_restore(cairo); + surface->show = TRUE; + cairo_set_operator(cairo,CAIRO_OPERATOR_SOURCE); + + } + + return cairo; + +} +#endif + void wDrawDelayUpdate( wDraw_p bd, wBool_t delay ) @@ -239,36 +388,19 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { psPrintLine( x0, y0, x1, y1, width, lineType, color, opts ); return; } - gc = selectGC( bd, width, lineType, color, opts ); x0 = INMAPX(bd,x0); y0 = INMAPY(bd,y0); x1 = INMAPX(bd,x1); y1 = INMAPY(bd,y1); - gdk_draw_line( bd->pixmap, gc, x0, y0, x1, y1 ); - cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, width, lineType, color, opts); cairo_move_to(cairo, x0 + 0.5, y0 + 0.5); cairo_line_to(cairo, x1 + 0.5, y1 + 0.5); cairo_stroke(cairo); gtkDrawDestroyCairoContext(cairo); + if (bd->widget) + gtk_widget_queue_draw(GTK_WIDGET(bd->widget)); //,x0,y0+1,x1,y1+1); - if ( bd->delayUpdate || bd->widget == NULL ) return; - width /= 2; - if (x0 < x1) { - update_rect.x = x0-1-width; - update_rect.width = x1-x0+2+width+width; - } else { - update_rect.x = x1-1-width; - update_rect.width = x0-x1+2+width+width; - } - if (y0 < y1) { - update_rect.y = y0-1-width; - update_rect.height = y1-y0+2+width+width; - } else { - update_rect.y = y1-1-width; - update_rect.height = y0-y1+2+width+width; - } - gtk_widget_draw( bd->widget, &update_rect ); } /** @@ -299,33 +431,20 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { wDrawOpts opts ) { int x, y, w, h; - GdkGC * gc; - GdkRectangle update_rect; if ( bd == &psPrint_d ) { psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts ); return; } - gc = selectGC( bd, width, lineType, color, opts ); + if (r < 6.0/75.0) return; x = INMAPX(bd,x0-r); y = INMAPY(bd,y0+r); w = 2*r; h = 2*r; - // remove the old arc - gdk_draw_arc( bd->pixmap, gc, FALSE, x, y, w, h, (int)((-angle0 + 90)*64.0), (int)(-angle1*64.0) ); - - // and its center point - if (drawCenter) { - x = INMAPX(bd,x0); - y = INMAPY(bd,y0); - gdk_draw_line( bd->pixmap, gc, x - ( CENTERMARK_LENGTH/2), y, x + ( CENTERMARK_LENGTH/2), y ); - gdk_draw_line( bd->pixmap, gc, x, y - ( CENTERMARK_LENGTH/2), x, y + ( CENTERMARK_LENGTH/2)); - } - // now create the new arc - cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, width, lineType, color, opts); cairo_new_path(cairo); // its center point marker @@ -337,6 +456,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { cairo_move_to(cairo, INMAPX(bd, x0), INMAPY(bd, y0 - (CENTERMARK_LENGTH / 2 ))); cairo_line_to(cairo, INMAPX(bd, x0) , INMAPY(bd, y0 + (CENTERMARK_LENGTH / 2))); cairo_new_sub_path( cairo ); + } // draw the curve itself @@ -344,14 +464,10 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { cairo_stroke(cairo); gtkDrawDestroyCairoContext(cairo); + if (bd->widget && !bd->delayUpdate) + gtk_widget_queue_draw_area(bd->widget,x,y,w,h); + - if ( bd->delayUpdate || bd->widget == NULL) return; - width /= 2; - update_rect.x = x-1-width; - update_rect.y = y-1-width; - update_rect.width = w+2+width+width; - update_rect.height = h+2+width+width; - gtk_widget_draw( bd->widget, &update_rect ); } @@ -361,28 +477,21 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { wDrawColor color, wDrawOpts opts ) { - GdkGC * gc; GdkRectangle update_rect; if ( bd == &psPrint_d ) { /*psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );*/ return; } - gc = selectGC( bd, 0, wDrawLineSolid, color, opts ); - gdk_draw_point( bd->pixmap, gc, INMAPX(bd, x0 ), INMAPY(bd, y0 ) ); - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts); cairo_new_path(cairo); cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), 0.75, 0, 2 * M_PI); cairo_stroke(cairo); gtkDrawDestroyCairoContext(cairo); + if (bd->widget && !bd->delayUpdate) + gtk_widget_queue_draw_area(bd->widget,INMAPX(bd,x0-0.75),INMAPY(bd,y0+0.75),2,2); - if ( bd->delayUpdate || bd->widget == NULL) return; - update_rect.x = INMAPX(bd, x0 )-1; - update_rect.y = INMAPY(bd, y0 )-1; - update_rect.width = 2; - update_rect.height = 2; - gtk_widget_draw( bd->widget, &update_rect ); } /******************************************************************************* @@ -407,6 +516,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { int h; gint ascent; gint descent; + gint baseline; double angle = -M_PI * a / 180.0; if ( bd == &psPrint_d ) { @@ -418,23 +528,27 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { y = INMAPY(bd,y); /* draw text */ - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts); cairo_save( cairo ); - cairo_translate( cairo, x, y ); - cairo_rotate( cairo, angle ); + cairo_identity_matrix(cairo); layout = wlibFontCreatePangoLayout(bd->widget, cairo, fp, fs, s, (int *) &w, (int *) &h, - (int *) &ascent, (int *) &descent); + (int *) &ascent, (int *) &descent, (int *) &baseline); - /* cairo does not support the old method of text removal by overwrite; force always write here and - refresh on cancel event */ + /* cairo does not support the old method of text removal by overwrite; + * if color is White, then overwrite old text with a White rectangle */ GdkColor* const gcolor = wlibGetColor(color, TRUE); cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0); - cairo_move_to( cairo, 0, -ascent ); + cairo_translate( cairo, x, y ); + cairo_rotate( cairo, angle ); + cairo_translate( cairo, 0, -baseline); + + cairo_move_to(cairo, 0, 0); + pango_cairo_update_layout(cairo, layout); pango_cairo_show_layout(cairo, layout); wlibFontDestroyPangoLayout(layout); cairo_restore( cairo ); @@ -446,17 +560,21 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { * for simplicity sake I added plain text height ascent and descent, * mathematically correct would be to use the trigonometrical functions as well */ - update_rect.x = (gint) x - ascent - descent - 1; - update_rect.y = (gint) y - (gint) ascent - 1; - update_rect.width = (gint) (w * cos( angle ) + 2 + ascent + descent); - update_rect.height = (gint) (h * sin( angle ) + ascent + descent + 2 ); + update_rect.x = (gint) x - 2; + update_rect.y = (gint) y - (gint) (baseline + descent) - 2; + update_rect.width = (gint) (w * cos( angle ) + h * sin(angle))+2; + update_rect.height = (gint) (h * sin( angle ) + w * cos(angle))+2; gtk_widget_draw(bd->widget, &update_rect); + if (bd->widget && !bd->delayUpdate) + gtk_widget_queue_draw_area(bd->widget, update_rect.x, update_rect.y, update_rect.width, update_rect.height); + } void wDrawGetTextSize( wPos_t *w, wPos_t *h, wPos_t *d, + wPos_t *a, wDraw_p bd, const char * s, wFont_p fp, @@ -466,21 +584,31 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { int textHeight; int ascent; int descent; + int baseline; *w = 0; *h = 0; + /* draw text */ + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorBlack, bd->bTempMode?wDrawOptTemp:0 ); + + cairo_identity_matrix(cairo); + wlibFontDestroyPangoLayout( - wlibFontCreatePangoLayout(bd->widget, NULL, fp, fs, s, + wlibFontCreatePangoLayout(bd->widget, cairo, fp, fs, s, &textWidth, (int *) &textHeight, - (int *) &ascent, (int *) &descent)); + (int *) &ascent, (int *) &descent, (int *) &baseline) ); *w = (wPos_t) textWidth; *h = (wPos_t) textHeight; - *d = (wPos_t) textHeight-ascent; + *a = (wPos_t) ascent; + //*d = (wPos_t) textHeight-ascent; + *d = (wPos_t) descent; if (debugWindow >= 3) fprintf(stderr, "text metrics: w=%d, h=%d, d=%d\n", *w, *h, *d); + + gtkDrawDestroyCairoContext(cairo); } @@ -490,6 +618,28 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { * *******************************************************************************/ +static void wlibDrawFilled( + cairo_t * cairo, + wDrawColor color, + wDrawOpts opt ) +{ + if ( (opt & wDrawOptTransparent) != 0 ) { + if ( (opt & wDrawOptTemp) == 0 ) { + cairo_set_source_rgb(cairo, 0,0,0); + cairo_set_operator(cairo, CAIRO_OPERATOR_DIFFERENCE); + cairo_fill_preserve(cairo); + } + GdkColor * gcolor = wlibGetColor(color, TRUE); + cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 1.0); + cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); + cairo_stroke_preserve(cairo); + cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 0.3); + } + cairo_fill(cairo); +} + + void wDrawFilledRectangle( wDraw_p bd, wPos_t x, @@ -499,7 +649,6 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { wDrawColor color, wDrawOpts opt ) { - GdkGC * gc; GdkRectangle update_rect; if ( bd == &psPrint_d ) { @@ -507,47 +656,46 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { return; } - gc = selectGC( bd, 0, wDrawLineSolid, color, opt ); x = INMAPX(bd,x); y = INMAPY(bd,y)-h; - gdk_draw_rectangle( bd->pixmap, gc, TRUE, x, y, w, h ); - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opt); cairo_move_to(cairo, x, y); cairo_rel_line_to(cairo, w, 0); cairo_rel_line_to(cairo, 0, h); cairo_rel_line_to(cairo, -w, 0); - cairo_fill(cairo); + cairo_rel_line_to(cairo, 0, -h); + wlibDrawFilled( cairo, color, opt ); + gtkDrawDestroyCairoContext(cairo); + if (bd->widget && !bd->delayUpdate) + gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),x,y,w,h); - if ( bd->delayUpdate || bd->widget == NULL) return; - update_rect.x = x-1; - update_rect.y = y-1; - update_rect.width = w+2; - update_rect.height = h+2; - gtk_widget_draw( bd->widget, &update_rect ); } - void wDrawFilledPolygon( + void wDrawPolygon( wDraw_p bd, wPos_t p[][2], + wPolyLine_e type[], int cnt, wDrawColor color, - wDrawOpts opt ) + wDrawWidth dw, + wDrawLineType_e lt, + wDrawOpts opt, + int fill, + int open ) { - GdkGC * gc; static int maxCnt = 0; static GdkPoint *points; int i; - GdkRectangle update_rect; if ( bd == &psPrint_d ) { - psPrintFillPolygon( p, cnt, color, opt ); + psPrintFillPolygon( p, type, cnt, color, opt, fill, open ); return; } - if (cnt > maxCnt) { + if (cnt > maxCnt) { if (points == NULL) points = (GdkPoint*)malloc( cnt*sizeof *points ); else @@ -556,43 +704,100 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { abort(); maxCnt = cnt; } - - update_rect.x = bd->w; - update_rect.y = bd->h; - update_rect.width = 0; - update_rect.height = 0; - for (i=0; i<cnt; i++) { - points[i].x = INMAPX(bd,p[i][0]); - points[i].y = INMAPY(bd,p[i][1]); - if (update_rect.x > points[i].x) - update_rect.x = points[i].x; - if (update_rect.width < points[i].x) - update_rect.width = points[i].x; - if (update_rect.y > points[i].y) - update_rect.y = points[i].y; - if (update_rect.height < points[i].y) - update_rect.height = points[i].y; + wPos_t min_x,max_x,min_y,max_y; + min_x = max_x = INMAPX(bd,p[0][0]); + min_y = max_y = INMAPY(bd,p[0][1]); + for (i=0; i<cnt; i++) { + points[i].x = INMAPX(bd,p[i][0]); + if (points[i].x < min_x) min_x = points[i].x; + if (points[i].x > max_x) max_x = points[i].x; + if (points[i].y > max_y) max_y = points[i].y; + points[i].y = INMAPY(bd,p[i][1]); } - update_rect.x -= 1; - update_rect.y -= 1; - update_rect.width -= update_rect.x-2; - update_rect.height -= update_rect.y-2; - gc = selectGC( bd, 0, wDrawLineSolid, color, opt ); - gdk_draw_polygon( bd->pixmap, gc, TRUE, points, cnt ); - - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt); + + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, fill?0:dw, fill?wDrawLineSolid:lt, color, opt); + for(i = 0; i < cnt; ++i) { - if(i) + int j = i-1; + int k = i+1; + if (j < 0) j = cnt-1; + if (k > cnt-1) k = 0; + GdkPoint mid0, mid1, mid3, mid4; + // save is static because of an apparent compiler bug on Linux + // This happens with RelWithDebInfo target + // If the first segment is a line then save should = points[0] + // However it becomes mid0 instead which causes the last corner to be misplaced. + static GdkPoint save; + double len0, len1; + double d0x = (points[i].x-points[j].x); + double d0y = (points[i].y-points[j].y); + double d1x = (points[k].x-points[i].x); + double d1y = (points[k].y-points[i].y); + len0 = (d0x*d0x+d0y*d0y); + len1 = (d1x*d1x+d1y*d1y); + mid0.x = (d0x/2)+points[j].x; + mid0.y = (d0y/2)+points[j].y; + mid1.x = (d1x/2)+points[i].x; + mid1.y = (d1y/2)+points[i].y; + if (type && (type[i] == wPolyLineRound) && (len1>0) && (len0>0)) { + double ratio = sqrt(len0/len1); + if (len0 < len1) { + mid1.x = ((d1x*ratio)/2)+points[i].x; + mid1.y = ((d1y*ratio)/2)+points[i].y; + } else { + mid0.x = points[i].x-(d0x/(2*ratio)); + mid0.y = points[i].y-(d0y/(2*ratio)); + } + } + mid3.x = (points[i].x-mid0.x)/2+mid0.x; + mid3.y = (points[i].y-mid0.y)/2+mid0.y; + mid4.x = (mid1.x-points[i].x)/2+points[i].x; + mid4.y = (mid1.y-points[i].y)/2+points[i].y; + points[i].x = round(points[i].x)+0.5; + points[i].y = round(points[i].y)+0.5; + mid0.x = round(mid0.x)+0.5; + mid0.y = round(mid0.y)+0.5; + mid1.x = round(mid1.x)+0.5; + mid1.y = round(mid1.y)+0.5; + mid3.x = round(mid3.x)+0.5; + mid3.y = round(mid3.y)+0.5; + mid4.x = round(mid4.x)+0.5; + mid4.y = round(mid4.y)+0.5; + if(i==0) { + if (!type || type[i] == wPolyLineStraight || open) { + cairo_move_to(cairo, points[i].x, points[i].y); + save = points[0]; + } else { + cairo_move_to(cairo, mid0.x, mid0.y); + if (type[i] == 1) + cairo_curve_to(cairo, points[i].x, points[i].y, points[i].x, points[i].y, mid1.x, mid1.y); + else + cairo_curve_to(cairo, mid3.x, mid3.y, mid4.x, mid4.y, mid1.x, mid1.y); + save = mid0; + } + } else if (!type || type[i] == wPolyLineStraight || (open && (i==cnt-1))) { cairo_line_to(cairo, points[i].x, points[i].y); - else - cairo_move_to(cairo, points[i].x, points[i].y); + } else { + cairo_line_to(cairo, mid0.x, mid0.y); + if (type[i] == wPolyLineSmooth) + cairo_curve_to(cairo, points[i].x, points[i].y, points[i].x, points[i].y, mid1.x, mid1.y); + else + cairo_curve_to(cairo, mid3.x, mid3.y, mid4.x, mid4.y, mid1.x, mid1.y); + } + if ((i==cnt-1) && !open) { + cairo_line_to(cairo, save.x, save.y); + } + } + if (fill && !open) { + wlibDrawFilled( cairo, color, opt ); + } else { + cairo_stroke(cairo); } - cairo_fill(cairo); gtkDrawDestroyCairoContext(cairo); + if (bd->widget && !bd->delayUpdate) + gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),min_x,min_y,max_x-min_y,max_y-min_y); - if ( bd->delayUpdate || bd->widget == NULL) return; - gtk_widget_draw( bd->widget, &update_rect ); } void wDrawFilledCircle( @@ -603,60 +808,64 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { wDrawColor color, wDrawOpts opt ) { - GdkGC * gc; int x, y, w, h; - GdkRectangle update_rect; if ( bd == &psPrint_d ) { psPrintFillCircle( x0, y0, r, color, opt ); return; } - gc = selectGC( bd, 0, wDrawLineSolid, color, opt ); x = INMAPX(bd,x0-r); y = INMAPY(bd,y0+r); w = 2*r; h = 2*r; - gdk_draw_arc( bd->pixmap, gc, TRUE, x, y, w, h, 0, 360*64 ); - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opt); cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), r, 0, 2 * M_PI); - cairo_fill(cairo); + wlibDrawFilled( cairo, color, opt ); gtkDrawDestroyCairoContext(cairo); - if ( bd->delayUpdate || bd->widget == NULL) return; - update_rect.x = x-1; - update_rect.y = y-1; - update_rect.width = w+2; - update_rect.height = h+2; - gtk_widget_draw( bd->widget, &update_rect ); + if (bd->widget) + gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),x,y,w,h); } + void wDrawClearTemp(wDraw_p bd) { + //Wipe out temp space with 0 alpha (transparent) + + static long cDCT = 0; + if ( iDrawLog ) + printf( "wDrawClearTemp %ld\n", cDCT++ ); + cairo_t* cairo = cairo_create(bd->temp_surface); + + cairo_set_source_rgba(cairo, 0.0, 0.0, 0.0, 0.0); + cairo_set_operator (cairo, CAIRO_OPERATOR_SOURCE); + cairo_move_to(cairo, 0, 0); + cairo_rel_line_to(cairo, bd->w, 0); + cairo_rel_line_to(cairo, 0, bd->h); + cairo_rel_line_to(cairo, -bd->w, 0); + cairo_fill(cairo); + cairo_destroy(cairo); + + if (bd->widget && !bd->delayUpdate) + gtk_widget_queue_draw(bd->widget); + } void wDrawClear( wDraw_p bd ) { - GdkGC * gc; - GdkRectangle update_rect; - gc = selectGC( bd, 0, wDrawLineSolid, wDrawColorWhite, 0 ); - gdk_draw_rectangle(bd->pixmap, gc, TRUE, 0, 0, bd->w, bd->h); - - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, wDrawColorWhite, 0); + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorWhite, 0); cairo_move_to(cairo, 0, 0); cairo_rel_line_to(cairo, bd->w, 0); cairo_rel_line_to(cairo, 0, bd->h); cairo_rel_line_to(cairo, -bd->w, 0); cairo_fill(cairo); + if (bd->widget) + gtk_widget_queue_draw(bd->widget); gtkDrawDestroyCairoContext(cairo); - if ( bd->delayUpdate || bd->widget == NULL) return; - update_rect.x = 0; - update_rect.y = 0; - update_rect.width = bd->w; - update_rect.height = bd->h; - gtk_widget_draw( bd->widget, &update_rect ); + wDrawClearTemp(bd); } void * wDrawGetContext( @@ -678,7 +887,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { int h, int x, int y, - const char * fbits ) + const unsigned char * fbits ) { wDrawBitMap_p bm; @@ -700,72 +909,107 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { wDrawColor color, wDrawOpts opts ) { - //GdkGC * gc; - GdkRectangle update_rect; int i, j, wb; wPos_t xx, yy; wControl_p b; - GdkDrawable * gdk_window; + wWin_p win; + GdkDrawable * gdk_drawable, * cairo_surface; + GtkWidget * widget = bd->widget; + + static long cDBM = 0; + if ( iDrawLog ) + printf( "wDrawBitMap %ld\n", cDBM++ ); x = INMAPX( bd, x-bm->x ); y = INMAPY( bd, y-bm->y )-bm->h; wb = (bm->w+7)/8; - //gc = selectGC( bd, 0, wDrawLineSolid, color, opts ); - cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts); + + cairo_t* cairo; + +#ifdef CURSOR_SURFACE + if (opts&wDrawOptCursorRmv) color = wDrawColorWhite; //Wipeout existing cursor draw (simplistic first) + + + if ((opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) { + + cairo = CreateCursorSurface((wControl_p)bd,&bd->cursor_surface, bd->w, bd->h, color, opts); + + if ((opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) { + bd->cursor_surface.show = FALSE; + } else bd->cursor_surface.show = TRUE; + + widget = bd->widget; + + + } else { + cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts); + widget = bd->widget; + } + + GtkWidget * new_widget = widget; + GdkGC * gc = NULL; + GdkWindow * gdk_window = NULL; + + win = bd->parent; +#endif + cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts); + for ( i=0; i<bm->w; i++ ) for ( j=0; j<bm->h; j++ ) if ( bm->bits[ j*wb+(i>>3) ] & (1<<(i&07)) ) { xx = x+i; yy = y+j; +#ifdef CURSOR_SURFACE if ( 0 <= xx && xx < bd->w && 0 <= yy && yy < bd->h ) { - gdk_window = bd->pixmap; b = (wControl_p)bd; } else if ( (opts&wDrawOptNoClip) != 0 ) { xx += bd->realX; yy += bd->realY; b = wlibGetControlFromPos( bd->parent, xx, yy ); - if ( b ) { - if ( b->type == B_DRAW ) - gdk_window = ((wDraw_p)b)->pixmap; - else - gdk_window = b->widget->window; + if ( b) { xx -= b->realX; yy -= b->realY; + new_widget = b->widget; } else { - gdk_window = bd->parent->widget->window; + new_widget = bd->parent->widget; } } else { continue; } -/*printf( "gdk_draw_point( %ld, gc, %d, %d )\n", (long)gdk_window, xx, yy );*/ - //gdk_draw_point( gdk_window, gc, xx, yy ); - cairo_rectangle(cairo, xx-0.5, yy-0.5, 1, 1); - cairo_fill(cairo); - if ( b && b->type == B_DRAW ) { - update_rect.x = xx-1; - update_rect.y = yy-1; - update_rect.width = 3; - update_rect.height = 3; - gtk_widget_draw( b->widget, &update_rect ); + + if (new_widget != widget) { + if (cairo) + cairo_destroy(cairo); + cairo = NULL; + if (widget && (widget != bd->parent->widget)) + gtk_widget_queue_draw(GTK_WIDGET(widget)); + if ( (opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) { + if (!b) b = (wControl_p)(bd->parent->widget); + cairo = CreateCursorSurface(b,&b->cursor_surface, b->w, b->h, color, opts); + widget = b->widget; + gc = NULL; + if ((opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) + b->cursor_surface.show = FALSE; + else + b->cursor_surface.show = TRUE; + } else { + continue; + } + widget = new_widget; } - } - gtkDrawDestroyCairoContext(cairo); -#ifdef LATER - gdk_draw_pixmap(bd->pixmap, gc, - bm->pixmap, - 0, 0, - x, y, - bm->w, bm->h ); + if ((opts&wDrawOptCursorQuit) || (opts&wDrawOptCursorQuit) ) continue; #endif - if ( bd->delayUpdate || bd->widget == NULL) return; + cairo_rectangle(cairo, xx, yy, 1, 1); + cairo_fill(cairo); + } + + cairo_destroy(cairo); + + if (widget && !bd->delayUpdate) + gtk_widget_queue_draw_area(GTK_WIDGET(widget), x, y, bm->w, bm->h); - update_rect.x = x; - update_rect.y = y; - update_rect.width = bm->w; - update_rect.height = bm->h; - gtk_widget_draw( bd->widget, &update_rect ); } @@ -780,19 +1024,19 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { void wDrawSaveImage( wDraw_p bd ) { + cairo_t * cr; if ( bd->pixmapBackup ) { gdk_pixmap_unref( bd->pixmapBackup ); } bd->pixmapBackup = gdk_pixmap_new( bd->widget->window, bd->w, bd->h, -1 ); - selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 ); - gdk_gc_set_function(bd->gc, GDK_COPY); + cr = gdk_cairo_create(bd->pixmapBackup); + gdk_cairo_set_source_pixmap(cr, bd->pixmap, 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + + cr = NULL; - gdk_draw_pixmap( bd->pixmapBackup, bd->gc, - bd->pixmap, - 0, 0, - 0, 0, - bd->w, bd->h ); } @@ -802,14 +1046,13 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { GdkRectangle update_rect; if ( bd->pixmapBackup ) { - selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 ); - gdk_gc_set_function(bd->gc, GDK_COPY); + cairo_t * cr; + cr = gdk_cairo_create(bd->pixmap); + gdk_cairo_set_source_pixmap(cr, bd->pixmapBackup, 0, 0); + cairo_paint(cr); + cairo_destroy(cr); - gdk_draw_pixmap( bd->pixmap, bd->gc, - bd->pixmapBackup, - 0, 0, - 0, 0, - bd->w, bd->h ); + cr = NULL; if ( bd->delayUpdate || bd->widget == NULL ) return; update_rect.x = 0; @@ -845,6 +1088,9 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) { if (bd->pixmap) gdk_pixmap_unref( bd->pixmap ); bd->pixmap = gdk_pixmap_new( bd->widget->window, w, h, -1 ); + if (bd->temp_surface) + cairo_surface_destroy( bd->temp_surface); + bd->temp_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, w,h ); wDrawClear( bd ); if (!redraw) @@ -914,13 +1160,37 @@ static gint draw_expose_event( GdkEventExpose *event, wDraw_p bd) { - gdk_draw_pixmap(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE (widget)], - bd->pixmap, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - return FALSE; + static long cDEE = 0; + if ( iDrawLog ) + printf( "draw_expose_event %ld %dx%d+%dx%d %dx%d+%dx%d\n", cDEE++, + event->area.x, event->area.y, event->area.width, event->area.height, + 0, bd->w, 0, bd->h ); + + cairo_t* cairo = gdk_cairo_create (widget->window); + gdk_cairo_set_source_pixmap(cairo,bd->pixmap,0,0); + cairo_rectangle(cairo,event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_set_operator(cairo,CAIRO_OPERATOR_SOURCE); + cairo_fill(cairo); + + cairo_set_source_surface(cairo,bd->temp_surface,0,0); + cairo_rectangle(cairo,event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_set_operator(cairo,CAIRO_OPERATOR_OVER); + cairo_fill(cairo); + +#ifdef CURSOR_SURFACE + if (bd->cursor_surface.surface && bd->cursor_surface.show) { + cairo_set_source_surface(cairo,bd->cursor_surface.surface,0,0); + cairo_set_operator(cairo,CAIRO_OPERATOR_OVER); + cairo_rectangle(cairo,event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_fill(cairo); + } +#endif + cairo_destroy(cairo); + + return TRUE; } @@ -929,32 +1199,113 @@ static gint draw_configure_event( GdkEventConfigure *event, wDraw_p bd) { - return FALSE; + return TRUE; } -static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown" }; +static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown", "DblL", "ModK", "ScrU", "ScrD", "ScrL", "ScrR" }; /** * Handler for scroll events, ie mouse wheel activity */ +static int scrollTimer; +static int timer_busy_count; +static wAction_t lastAction; + +static int ScrollTimerPop(wDraw_p bd) { + + if (timer_busy_count>1) { + timer_busy_count = 0; + scrollTimer = 0; + } else { + timer_busy_count++; + return TRUE; + } + if (drawVerbose >= 2) + printf( "%s-Pop\n", actionNames[lastAction] ); + bd->action( bd, bd->context, lastAction, 0, 0 ); + + return FALSE; +} + + static gint draw_scroll_event( GtkWidget *widget, GdkEventScroll *event, wDraw_p bd) { wAction_t action; + static int oldEventX = 0; + static int oldEventY = 0; + static int newEventX = 0; + static int newEventY = 0; + + if (event->state & (GDK_SHIFT_MASK|GDK_BUTTON2_MASK|GDK_MOD1_MASK)) { + + newEventX = OUTMAPX(bd, event->x); + newEventY = OUTMAPY(bd, event->y); + oldEventX = OUTMAPX(bd, event->x_root); + oldEventY = OUTMAPX(bd, event->y_root); + + switch( event->direction ) { + case GDK_SCROLL_UP: + if (event->state & GDK_CONTROL_MASK) + action = wActionScrollRight; + else + action = wActionScrollUp; + break; + case GDK_SCROLL_DOWN: + if (event->state & GDK_CONTROL_MASK) + action = wActionScrollLeft; + else + action = wActionScrollDown; + break; + case GDK_SCROLL_LEFT: + action = wActionScrollLeft; + break; + case GDK_SCROLL_RIGHT: + action = wActionScrollRight; + break; + default: + return TRUE; + break; + } - switch( event->direction ) { - case GDK_SCROLL_UP: - action = wActionWheelUp; - break; - case GDK_SCROLL_DOWN: - action = wActionWheelDown; - break; - default: - action = 0; - break; + if (drawVerbose >= 2) + printf( "%sNew[%dx%d]Delta[%dx%d]\n", actionNames[action], + newEventX, newEventY, oldEventX, oldEventY ); + + + + if (scrollTimer) { // Already have a timer + lastAction = action; + return TRUE; + } else { + lastAction = action; + timer_busy_count = 0; + scrollTimer = g_timeout_add(25,(GSourceFunc)ScrollTimerPop,bd); // 25ms delay + return TRUE; + } + + + } else { + + switch( event->direction ) { + case GDK_SCROLL_UP: + action = wActionWheelUp; + break; + case GDK_SCROLL_DOWN: + action = wActionWheelDown; + break; + case GDK_SCROLL_LEFT: + return TRUE; + break; + case GDK_SCROLL_RIGHT: + return TRUE; + break; + default: + break; + } } if (action != 0) { @@ -973,7 +1324,7 @@ static gint draw_leave_event( GdkEvent * event ) { wlibHelpHideBalloon(); - return FALSE; + return TRUE; } @@ -996,6 +1347,7 @@ static gint draw_button_event( switch ( event->button ) { case 1: /* left mouse button */ action = event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp; + if (event->type==GDK_2BUTTON_PRESS) action = wActionLDownDouble; /*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp, bd->lastX, bd->lastY );*/ break; case 3: /* right mouse button */ @@ -1050,6 +1402,35 @@ static gint draw_motion_event( return TRUE; } +static gint draw_char_release_event( + GtkWidget * widget, + GdkEventKey *event, + wDraw_p bd ) +{ + GdkModifierType modifiers; + guint key = event->keyval; + wModKey_e modKey = wModKey_None; + switch (key) { + case GDK_KEY_Alt_L: modKey = wModKey_Alt; break; + case GDK_KEY_Alt_R: modKey = wModKey_Alt; break; + case GDK_KEY_Shift_L: modKey = wModKey_Shift; break; + case GDK_KEY_Shift_R: modKey = wModKey_Shift; break; + case GDK_KEY_Control_L: modKey = wModKey_Ctrl; break; + case GDK_KEY_Control_R: modKey = wModKey_Ctrl; break; + default: ; + } + + if (modKey!= wModKey_None && (bd->option & BD_MODKEYS)) { + bd->action(bd, bd->context, wActionModKey+((int)modKey<<8), bd->lastX, bd->lastY ); + if (!(bd->option & BD_NOFOCUS)) + gtk_widget_grab_focus( bd->widget ); + return TRUE; + } else { + return FALSE; + } + return FALSE; +} + static gint draw_char_event( GtkWidget * widget, @@ -1059,6 +1440,7 @@ static gint draw_char_event( GdkModifierType modifiers; guint key = event->keyval; wAccelKey_e extKey = wAccelKey_None; + wModKey_e modKey = wModKey_None; switch (key) { case GDK_KEY_Escape: key = 0x1B; break; case GDK_KEY_Return: @@ -1092,17 +1474,37 @@ static gint draw_char_event( case GDK_KEY_F10: extKey = wAccelKey_F10; break; case GDK_KEY_F11: extKey = wAccelKey_F11; break; case GDK_KEY_F12: extKey = wAccelKey_F12; break; - default: ; + case GDK_KEY_Alt_L: modKey = wModKey_Alt; break; + case GDK_KEY_Alt_R: modKey = wModKey_Alt; break; + case GDK_KEY_Shift_L: modKey = wModKey_Shift; break; + case GDK_KEY_Shift_R: modKey = wModKey_Shift; break; + case GDK_KEY_Control_L: modKey = wModKey_Ctrl; break; + case GDK_KEY_Control_R: modKey = wModKey_Ctrl; break; + default: ; } if (extKey != wAccelKey_None) { if ( wlibFindAccelKey( event ) == NULL ) { bd->action( bd, bd->context, wActionExtKey + ((int)extKey<<8), bd->lastX, bd->lastY ); } + if (!(bd->option & BD_NOFOCUS)) + gtk_widget_grab_focus( bd->widget ); + return TRUE; + } else if ((key >=wAccelKey_Up) && (key<=wAccelKey_Left) && bd->action) { + bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY ); + if (!(bd->option & BD_NOFOCUS)) + gtk_widget_grab_focus( bd->widget ); return TRUE; } else if (key <= 0xFF && (event->state&(GDK_CONTROL_MASK|GDK_MOD1_MASK)) == 0 && bd->action) { bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY ); + if (!(bd->option & BD_NOFOCUS)) + gtk_widget_grab_focus( bd->widget ); return TRUE; + } else if (modKey!= wModKey_None && (bd->option & BD_MODKEYS)) { + bd->action(bd, bd->context, wActionModKey+((int)modKey<<8), bd->lastX, bd->lastY ); + if (!(bd->option & BD_NOFOCUS)) + gtk_widget_grab_focus( bd->widget ); + return TRUE; } else { return FALSE; } @@ -1140,6 +1542,7 @@ int xw, xh, cw, ch; bd->context = context; bd->redraw = redraw; bd->action = action; + bd->bTempMode = FALSE; wlibComputePos( (wControl_p)bd ); bd->widget = gtk_drawing_area_new(); @@ -1159,6 +1562,8 @@ int xw, xh, cw, ch; (GtkSignalFunc) draw_scroll_event, bd); gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_press_event", (GtkSignalFunc) draw_char_event, bd); + gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_release_event", + (GtkSignalFunc) draw_char_release_event, bd); gtk_signal_connect (GTK_OBJECT (bd->widget), "leave_notify_event", (GtkSignalFunc) draw_leave_event, bd); gtk_widget_set_can_focus(bd->widget,!(option & BD_NOFOCUS)); @@ -1168,7 +1573,7 @@ int xw, xh, cw, ch; | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK -/* | GDK_SCROLL_MASK */ + | GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK @@ -1182,6 +1587,8 @@ int xw, xh, cw, ch; wlibControlGetSize( (wControl_p)bd ); gtk_widget_realize( bd->widget ); bd->pixmap = gdk_pixmap_new( bd->widget->window, width, height, -1 ); + bd->temp_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width,height ); + wDrawClear(bd); bd->gc = gdk_gc_new( parent->gtkwin->window ); gdk_gc_copy( bd->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] ); { @@ -1219,6 +1626,7 @@ wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int arg ) bd->maxH = bd->h = h; bd->pixmap = gdk_pixmap_new( gtkMainW->widget->window, w, h, -1 ); + bd->widget = gtk_pixmap_new(bd->pixmap, NULL); if ( bd->pixmap == NULL ) { wNoticeEx( NT_ERROR, "CreateBitMap: pixmap_new failed", "Ok", NULL ); return FALSE; @@ -1242,3 +1650,76 @@ wBool_t wBitMapDelete( wDraw_p d ) return TRUE; } +/******************************************************************************* + * + * Background + * + ******************************************************************************/ +int wDrawSetBackground( wDraw_p bd, char * path, char ** error) { + + GError *err = NULL; + + if (bd->background) { + g_object_unref(bd->background); + } + + if (path) { + bd->background = gdk_pixbuf_new_from_file (path, &err); + if (!bd->background) { + *error = err->message; + return -1; + } + } else { + bd->background = NULL; + return 1; + } + return 0; + +} + +void wDrawShowBackground( wDraw_p bd, wPos_t pos_x, wPos_t pos_y, wPos_t size, wAngle_t angle, int screen) { + + if (bd->background) { + cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorWhite, bd->bTempMode?wDrawOptTemp:0 ); + cairo_save(cairo); + int pixels_width = gdk_pixbuf_get_width(bd->background); + int pixels_height = gdk_pixbuf_get_height(bd->background); + double scale; + double posx,posy,width,sized; + posx = (double)pos_x; + posy = (double)pos_y; + if (size == 0) { + scale = 1.0; + } else { + sized = (double)size; + width = (double)pixels_width; + scale = sized/width; + } + cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); + double rad = M_PI*(angle/180); + posy = (double)bd->h-((pixels_height*fabs(cos(rad))+pixels_width*fabs(sin(rad)))*scale)-posy; + //width = (double)(pixels_width*scale); + //height = (double)(pixels_height*scale); + cairo_translate(cairo,posx,posy); + cairo_scale(cairo, scale, scale); + cairo_translate(cairo, fabs(pixels_width/2.0*cos(rad))+fabs(pixels_height/2.0*sin(rad)), + fabs(pixels_width/2.0*sin(rad))+fabs(pixels_height/2.0*cos(rad))); + cairo_rotate(cairo, M_PI*(angle/180.0)); + // We need to clip around the image, or cairo will paint garbage data + cairo_rectangle(cairo, -pixels_width/2.0, -pixels_height/2.0, pixels_width, pixels_height); + cairo_clip(cairo); + gdk_cairo_set_source_pixbuf(cairo, bd->background, -pixels_width/2.0, -pixels_height/2.0); + cairo_pattern_t *mask = cairo_pattern_create_rgba (1.0,1.0,1.0,(100.0-screen)/100.0); + cairo_mask(cairo,mask); + cairo_pattern_destroy(mask); + cairo_restore(cairo); + gtkDrawDestroyCairoContext(cairo); + + gtk_widget_queue_draw(bd->widget); + } + +} + + + + |