From 9f167f956888c2de10d92b12677d521cceddcfe9 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Sat, 2 Mar 2024 02:29:03 +0100 Subject: [PATCH] allow launcher style behaviourrt (tclcommand / url attributes) on all objects. Add (shift + but1 click) and Delete (Ctrl+ But1 click) polygon points. fixed some graphical artifacs when adding new object while some selection is present --- src/actions.c | 39 ++++++++++++++++++++------ src/callback.c | 74 ++++++++++++++++++++++++++++++++++++++++---------- src/draw.c | 15 ++++++---- src/move.c | 9 +++--- src/select.c | 4 +-- 5 files changed, 107 insertions(+), 34 deletions(-) diff --git a/src/actions.c b/src/actions.c index 32851e20..812df473 100644 --- a/src/actions.c +++ b/src/actions.c @@ -1715,21 +1715,30 @@ void launcher(void) { const char *url; char program[PATH_MAX]; - int n; + int n, c; + char *prop_ptr; rebuild_selected_array(); tcleval("update"); - if(xctx->lastsel ==1 && xctx->sel_array[0].type==ELEMENT) + if(xctx->lastsel ==1) { double mx=xctx->mousex, my=xctx->mousey; - /* select_object(mx,my,SELECTED, 0); */ n=xctx->sel_array[0].n; - my_strncpy(program, get_tok_value(xctx->inst[n].prop_ptr,"program",0), S(program)); /* handle backslashes */ - url = get_tok_value(xctx->inst[n].prop_ptr,"url",0); /* handle backslashes */ + c=xctx->sel_array[0].col; + if (xctx->sel_array[0].type==ELEMENT) prop_ptr = xctx->inst[n].prop_ptr; + else if(xctx->sel_array[0].type==xRECT) prop_ptr = xctx->rect[c][n].prop_ptr; + else if(xctx->sel_array[0].type==POLYGON) prop_ptr = xctx->poly[c][n].prop_ptr; + else if(xctx->sel_array[0].type==ARC) prop_ptr = xctx->arc[c][n].prop_ptr; + else if(xctx->sel_array[0].type==LINE) prop_ptr = xctx->line[c][n].prop_ptr; + else if(xctx->sel_array[0].type==WIRE) prop_ptr = xctx->wire[n].prop_ptr; + else if(xctx->sel_array[0].type==xTEXT) prop_ptr = xctx->text[n].prop_ptr; + /* select_object(mx,my,SELECTED, 0); */ + my_strncpy(program, get_tok_value(prop_ptr,"program",0), S(program)); /* handle backslashes */ + url = get_tok_value(prop_ptr,"url",0); /* handle backslashes */ dbg(1, "launcher(): url=%s\n", url); if(url[0] || (program[0])) { /* open url with appropriate program */ tclvareval("launcher {", url, "} {", program, "}", NULL); } else { - my_strncpy(program, get_tok_value(xctx->inst[n].prop_ptr,"tclcommand",0), S(program)); + my_strncpy(program, get_tok_value(prop_ptr,"tclcommand",0), S(program)); if(program[0]) { /* execute tcl command */ tcleval(program); } @@ -2818,12 +2827,13 @@ void draw_stuff(void) static void restore_selection(double x1, double y1, double x2, double y2) { double xx1,yy1,xx2,yy2; + int intlw = 2 * INT_WIDTH(xctx->lw) + (int)xctx->cadhalfdotsize; xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2; RECTORDER(xx1,yy1,xx2,yy2); rebuild_selected_array(); if(!xctx->lastsel) return; bbox(START,0.0, 0.0, 0.0, 0.0); - bbox(ADD, xx1-xctx->lw, yy1-xctx->lw, xx2+xctx->lw, yy2+xctx->lw); + bbox(ADD, xx1 - intlw, yy1 - intlw, xx2 + intlw, yy2 + intlw); bbox(SET,0.0, 0.0, 0.0, 0.0); draw_selection(xctx->gc[SELLAYER], 0); bbox(END,0.0, 0.0, 0.0, 0.0); @@ -3106,7 +3116,8 @@ void new_arc(int what, double sweep) arc_3_points(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2, xctx->nl_x3, xctx->nl_y3, &xctx->nl_x, &xctx->nl_y, &xctx->nl_r, &xctx->nl_a, &xctx->nl_b); if(xctx->nl_sweep_angle==360.) xctx->nl_b=360.; - if(xctx->nl_r>0.) drawtemparc(xctx->gc[xctx->rectcolor], NOW, xctx->nl_x, xctx->nl_y, xctx->nl_r, xctx->nl_a, xctx->nl_b); + if(xctx->nl_r>0.) drawtemparc(xctx->gc[xctx->rectcolor], NOW, + xctx->nl_x, xctx->nl_y, xctx->nl_r, xctx->nl_a, xctx->nl_b); } } } @@ -3264,6 +3275,7 @@ void new_rect(int what) xctx->nl_xx1=xctx->nl_x1;xctx->nl_yy1=xctx->nl_y1;xctx->nl_xx2=xctx->nl_x2;xctx->nl_yy2=xctx->nl_y2; RECTORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); drawtemprect(xctx->gctiled,NOW, xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); + restore_selection(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); xctx->nl_x2=xctx->mousex_snap;xctx->nl_y2=xctx->mousey_snap; xctx->nl_xx1=xctx->nl_x1;xctx->nl_yy1=xctx->nl_y1;xctx->nl_xx2=xctx->nl_x2;xctx->nl_yy2=xctx->nl_y2; RECTORDER(xctx->nl_xx1,xctx->nl_yy1,xctx->nl_xx2,xctx->nl_yy2); @@ -3291,11 +3303,16 @@ void new_polygon(int what) xctx->nl_polyy[xctx->nl_points] = xctx->nl_polyy[xctx->nl_points-1]; /* fprintf(errfp, "added point: %.16g %.16g\n", xctx->nl_polyx[xctx->nl_points-1], xctx->nl_polyy[xctx->nl_points-1]); */ + xctx->nl_x1=xctx->nl_x2=xctx->mousex_snap;xctx->nl_y1=xctx->nl_y2=xctx->mousey_snap; xctx->ui_state |= STARTPOLYGON; set_modify(1); } if( what & ADD) { + if(xctx->mousex_snap < xctx->nl_x1) xctx->nl_x1 = xctx->mousex_snap; + if(xctx->mousex_snap > xctx->nl_x2) xctx->nl_x2 = xctx->mousex_snap; + if(xctx->mousey_snap < xctx->nl_y1) xctx->nl_y1 = xctx->mousey_snap; + if(xctx->mousey_snap > xctx->nl_y2) xctx->nl_y2 = xctx->mousey_snap; /* closed poly */ if(what & END) { /* delete last rubber */ @@ -3333,10 +3350,16 @@ void new_polygon(int what) } if(what & RUBBER) { + if(xctx->mousex_snap < xctx->nl_x1) xctx->nl_x1 = xctx->mousex_snap; + if(xctx->mousex_snap > xctx->nl_x2) xctx->nl_x2 = xctx->mousex_snap; + if(xctx->mousey_snap < xctx->nl_y1) xctx->nl_y1 = xctx->mousey_snap; + if(xctx->mousey_snap > xctx->nl_y2) xctx->nl_y2 = xctx->mousey_snap; /* fprintf(errfp, "new_poly: RUBBER\n"); */ drawtemppolygon(xctx->gctiled, NOW, xctx->nl_polyx, xctx->nl_polyy, xctx->nl_points+1, 0); xctx->nl_polyy[xctx->nl_points] = xctx->mousey_snap; xctx->nl_polyx[xctx->nl_points] = xctx->mousex_snap; + restore_selection(xctx->nl_x1, xctx->nl_y1, xctx->nl_x2, xctx->nl_y2); + /* xctx->nl_x2 = xctx->mousex_snap; xctx->nl_y2 = xctx->mousey_snap; */ drawtemppolygon(xctx->gc[xctx->rectcolor], NOW, xctx->nl_polyx, xctx->nl_polyy, xctx->nl_points+1, 0); } } diff --git a/src/callback.c b/src/callback.c index 7dfefca9..4d3e3b5c 100644 --- a/src/callback.c +++ b/src/callback.c @@ -3134,7 +3134,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; } /* Button1Press to select objects */ - if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) { + if( !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & STARTWIRE) && !(xctx->ui_state & STARTLINE) ) { Selected sel; int prev_last_sel = xctx->lastsel; int polygon_n = -1, polygon_c = -1; @@ -3149,10 +3149,10 @@ int rstate; /* (reduced state, without ShiftMask) */ polygon_c = xctx->sel_array[0].col; } /* If no shift was pressed while Button1Press delete selection */ - if( !(state & ShiftMask) && !(SET_MODMASK) ) { + if( !(state & (ShiftMask | ControlMask)) && !(SET_MODMASK) ) { unselect_all(1); } - /* Check is user is clicking a control point of a polygon */ + /* polygon point: Check is user is clicking a control point of a polygon */ if(polygon_n >= 0) { int i; double ds = xctx->cadhalfdotsize; @@ -3173,11 +3173,58 @@ int rstate; /* (reduced state, without ShiftMask) */ } } if(xctx->poly_point_selected) { - xctx->poly[polygon_c][polygon_n].sel = SELECTED1; - xctx->need_reb_sel_arr=1; - move_objects(START,0,0,0); - } - } + int j; + int c = polygon_c; + int n = polygon_n; + int points = xctx->poly[c][n].points; + + /* add a new polygon/bezier point after selected one and start moving it*/ + if(state & ShiftMask) { + xctx->push_undo(); + points++; + my_realloc(_ALLOC_ID_, &xctx->poly[c][n].x, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &xctx->poly[c][n].y, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &xctx->poly[c][n].selected_point, sizeof(unsigned short) * points); + xctx->poly[c][n].selected_point[i] = 0; + for(j = points - 2; j > i; j--) { + xctx->poly[c][n].x[j + 1] = xctx->poly[c][n].x[j]; + xctx->poly[c][n].y[j + 1] = xctx->poly[c][n].y[j]; + xctx->poly[c][n].selected_point[j + 1] = xctx->poly[c][n].selected_point[j]; + } + xctx->poly[c][n].selected_point[i + 1] = 1; + xctx->poly[c][n].x[i + 1] = xctx->poly[c][n].x[i]; + xctx->poly[c][n].y[i + 1] = xctx->poly[c][n].y[i]; + xctx->poly[c][n].points = points; + xctx->poly[polygon_c][polygon_n].sel = SELECTED1; + xctx->need_reb_sel_arr=1; + move_objects(START,0,0,0); + } + /* delete polygon/bezier selected point */ + else if(points > 2 && state & ControlMask) { + xctx->push_undo(); + points--; + for(j = i ; j < points ; j++) { + xctx->poly[c][n].x[j] = xctx->poly[c][n].x[j + 1]; + xctx->poly[c][n].y[j] = xctx->poly[c][n].y[j + 1]; + xctx->poly[c][n].selected_point[j] = xctx->poly[c][n].selected_point[j + 1]; + } + my_realloc(_ALLOC_ID_, &xctx->poly[c][n].x, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &xctx->poly[c][n].y, sizeof(double) * points); + my_realloc(_ALLOC_ID_, &xctx->poly[c][n].selected_point, sizeof(unsigned short) * points); + xctx->poly[c][n].points = points; + xctx->poly[polygon_c][polygon_n].sel = SELECTED; + xctx->need_reb_sel_arr=1; + #ifdef __unix__ + draw_selection(xctx->gc[SELLAYER], 0); + #endif + } else if(!(state & (ControlMask | ShiftMask))){ + xctx->push_undo(); + xctx->poly[polygon_c][polygon_n].sel = SELECTED1; + xctx->need_reb_sel_arr=1; + move_objects(START,0,0,0); + } + } /* if(xctx->poly_point_selected) */ + } /* if(polygon_n >= 0) */ if(!xctx->poly_point_selected) { sel = select_object(xctx->mousex, xctx->mousey, SELECTED, 0); } @@ -3185,24 +3232,22 @@ int rstate; /* (reduced state, without ShiftMask) */ #ifndef __unix__ draw_selection(xctx->gc[SELLAYER], 0); #endif - if(sel.type && state == ControlMask) { + /* control-click on an instance: execute command */ + if(sel.type && state == ControlMask && !xctx->poly_point_selected) { int savesem = xctx->semaphore; xctx->semaphore = 0; launcher(); xctx->semaphore = savesem; } - if( !(state & ShiftMask) ) { - if(tclgetboolvar("auto_hilight") && xctx->hilight_nets && sel.type == 0 ) { + if(tclgetboolvar("auto_hilight") && !xctx->poly_point_selected) { + if(!(state & ShiftMask) && xctx->hilight_nets && sel.type == 0 ) { if(!prev_last_sel) { redraw_hilights(1); /* 1: clear all hilights, then draw */ } } - } - if(tclgetboolvar("auto_hilight")) { hilight_net(0); if(xctx->lastsel) { redraw_hilights(0); - /* draw_hilight_net(1); */ } } break; @@ -3220,6 +3265,7 @@ int rstate; /* (reduced state, without ShiftMask) */ int c = xctx->sel_array[0].col; move_objects(END,0,0,0); xctx->poly[c][n].sel = SELECTED; + xctx->poly_point_selected = 0; for(k=0; kpoly[c][n].points; ++k) { xctx->poly[c][n].selected_point[k] = 0; } diff --git a/src/draw.c b/src/draw.c index 7126290e..30230c43 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1770,7 +1770,7 @@ void drawpolygon(int c, int what, double *x, double *y, int points, int poly_fil } fill = xctx->fill_pattern && xctx->fill_type[c] && poly_fill && (x[0] == x[points-1]) && (y[0] == y[points-1]); - bezier = flags && (points > 2); + bezier = (flags & 1) && (points > 2); if(dash) { char dash_arr[2]; dash_arr[0] = dash_arr[1] = (char)dash; @@ -1803,6 +1803,8 @@ void drawpolygon(int c, int what, double *x, double *y, int points, int poly_fil my_free(_ALLOC_ID_, &p); } +/* flags: bit 0: bezier + * bit 1: draw control point circles */ void drawtemppolygon(GC gc, int what, double *x, double *y, int points, int flags) { double x1,y1,x2,y2; @@ -1810,7 +1812,7 @@ void drawtemppolygon(GC gc, int what, double *x, double *y, int points, int flag XPoint *p; int i; short sx, sy; - int bezier; + int bezier, drawpoints; if(!has_x) return; polygon_bbox(x, y, points, &x1,&y1,&x2,&y2); sx1=X_TO_SCREEN(x1); @@ -1819,14 +1821,15 @@ void drawtemppolygon(GC gc, int what, double *x, double *y, int points, int flag sy2=Y_TO_SCREEN(y2); if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&sx1,&sy1,&sx2,&sy2) ) { - bezier = flags && (points > 2); + bezier = (flags & 1) && (points > 2); + drawpoints = (flags & 2); if((fix_broken_tiled_fill || !_unix) && gc == xctx->gctiled) { MyXCopyAreaDouble(display, xctx->save_pixmap, xctx->window, xctx->gc[0], x1 - xctx->cadhalfdotsize, y1 - xctx->cadhalfdotsize, x2 + xctx->cadhalfdotsize, y2 + xctx->cadhalfdotsize, x1 - xctx->cadhalfdotsize, y1 - xctx->cadhalfdotsize, xctx->lw); } else { - if(gc == xctx->gc[SELLAYER] || gc == xctx->gctiled ) for(i = 0; i < points; i++) { + if(drawpoints && (gc == xctx->gc[SELLAYER] || gc == xctx->gctiled) ) for(i = 0; i < points; i++) { if( POINTINSIDE(X_TO_SCREEN(x[i]), Y_TO_SCREEN(y[i]), xctx->areax1, xctx->areay1, xctx->areax2, xctx->areay2)) { drawtemparc(gc, NOW, x[i], y[i], xctx->cadhalfdotsize, 0., 360.); @@ -4222,7 +4225,7 @@ void draw(void) if(xctx->enable_layer[c]) for(i=0;ipolygons[c]; ++i) { int bezier; xPoly *p = &xctx->poly[c][i]; - bezier = !strboolcmp(get_tok_value(p->prop_ptr, "bezier", 0), "true"); + bezier = 2 + !strboolcmp(get_tok_value(p->prop_ptr, "bezier", 0), "true"); drawpolygon(cc, NOW, p->x, p->y, p->points, p->fill, p->dash, bezier); } if(use_hash) init_inst_iterator(&ctx, x1, y1, x2, y2); @@ -4400,7 +4403,7 @@ void MyXCopyAreaDouble(Display* display, Drawable src, Drawable dest, GC gc, double isx1, isy1, isx2, isy2, idx1, idy1; unsigned int width, height; int intlw = INT_WIDTH(lw); - dbg(1, "MyXCopyAreaDouble(%g, %g, %g, %g)\n", sx1, sy1, sx2, sy2); + dbg(1, "MyXCopyAreaDouble(%g, %g, %g, %g, intlw=%d)\n", sx1, sy1, sx2, sy2, intlw); isx1=X_TO_SCREEN(sx1) - 2 * intlw; isy1=Y_TO_SCREEN(sy1) - 2 * intlw; isx2=X_TO_SCREEN(sx2) + 2 * intlw; diff --git a/src/move.c b/src/move.c index b210bc75..b4847792 100644 --- a/src/move.c +++ b/src/move.c @@ -308,7 +308,7 @@ void draw_selection(GC g, int interruptable) int bezier; double *x = my_malloc(_ALLOC_ID_, sizeof(double) *xctx->poly[c][n].points); double *y = my_malloc(_ALLOC_ID_, sizeof(double) *xctx->poly[c][n].points); - bezier = !strboolcmp(get_tok_value(xctx->poly[c][n].prop_ptr, "bezier", 0), "true"); + bezier = 2 + !strboolcmp(get_tok_value(xctx->poly[c][n].prop_ptr, "bezier", 0), "true"); if(xctx->poly[c][n].sel==SELECTED || xctx->poly[c][n].sel==SELECTED1) { for(k=0;kpoly[c][n].points; ++k) { if( xctx->poly[c][n].sel==SELECTED || xctx->poly[c][n].selected_point[k]) { @@ -928,9 +928,10 @@ void move_objects(int what, int merge, double dx, double dy) int firsti, firstw; if(xctx->connect_by_kissing == 2) xctx->connect_by_kissing = 0; - /* no undo push for MERGE ad PLACE, already done before */ - if( !xctx->kissing && !(xctx->ui_state & (STARTMERGE | PLACE_SYMBOL | PLACE_TEXT)) ) { - dbg(1, "move_objects(): push undo state\n"); + /* no undo push for MERGE ad PLACE and polygon point drag, already done before */ + if(!xctx->poly_point_selected && !xctx->kissing && + !(xctx->ui_state & (STARTMERGE | PLACE_SYMBOL | PLACE_TEXT)) ) { + dbg(1, "move_objects(END): push undo state\n"); xctx->push_undo(); } if((xctx->ui_state & PLACE_SYMBOL)) { diff --git a/src/select.c b/src/select.c index 858e46e6..d482fc96 100644 --- a/src/select.c +++ b/src/select.c @@ -867,7 +867,7 @@ void unselect_all(int dr) if(xctx->poly[c][i].sel) { int k; - int bezier = !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); + int bezier = 2 + !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); for(k=0;kpoly[c][i].points; ++k) xctx->poly[c][i].selected_point[k] = 0; xctx->poly[c][i].sel = 0; if(dr) { @@ -1108,7 +1108,7 @@ void select_polygon(int c, int i, unsigned short select_mode, int fast ) my_snprintf(str, S(str), "n=%4d x0 = %.16g y0 = %.16g ...", i, xctx->poly[c][i].x[0], xctx->poly[c][i].y[0]); statusmsg(str,1); } - bezier = !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); + bezier = 2 + !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); xctx->poly[c][i].sel = select_mode; if(select_mode) { drawtemppolygon(xctx->gc[SELLAYER], NOW,