From d50a3fc962d20f5a932f3063e1aebb104d2bdef1 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 25 Mar 2026 01:47:39 +0100 Subject: [PATCH] allow hilight a wave by middle button click in graph area. The closest wave will be shown in bold. This is in addition to middle-button clicking a wave label --- src/callback.c | 35 +++++++++++++--- src/draw.c | 112 +++++++++++++++++++++++++++++++++++-------------- src/xschem.h | 2 +- 3 files changed, 110 insertions(+), 39 deletions(-) diff --git a/src/callback.c b/src/callback.c index ba6a4a58..f3b05fcb 100644 --- a/src/callback.c +++ b/src/callback.c @@ -452,11 +452,33 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int /* determine if mouse pointer is below xaxis or left of yaxis in some graph */ setup_graph_data(i, 0, gr); - /* check if user clicked on a wave label -> draw wave in bold */ - if(event == ButtonPress && button == Button3 && - edit_wave_attributes(2, i, gr)) { - draw_graph(i, 1 + 8 + (xctx->graph_flags & (2 | 4 | 128 | 256)), gr, NULL); /* draw data in graph box */ - return 0; + /* check if user clicked on a wave or a wave label -> draw wave in bold */ + if(event == ButtonPress && button == Button3) { + /* button3 click on a wave */ + if(POINTINSIDE(xctx->mousex, xctx->mousey, gr->x1, gr->y1, gr->x2 , gr->y2)) { + int wcnt, save; + save = gr->hilight_wave; + find_closest_wave(i, gr, &wcnt); + if(gr->hilight_wave >= 0) { + gr->hilight_wave = -1; + my_strdup2(_ALLOC_ID_, &r->prop_ptr, + subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave))); + } else { + gr->hilight_wave = wcnt; + my_strdup2(_ALLOC_ID_, &r->prop_ptr, + subst_token(r->prop_ptr, "hilight_wave", my_itoa(gr->hilight_wave))); + } + + if(save != gr->hilight_wave) { + draw_graph(i, 1 + 8 + (xctx->graph_flags & (2 | 4 | 128 | 256)), gr, NULL); /* draw data in graph box */ + } + /* button3 click on wave label */ + } else { + if( edit_wave_attributes(2, i, gr)) { + draw_graph(i, 1 + 8 + (xctx->graph_flags & (2 | 4 | 128 | 256)), gr, NULL); /* draw data in graph box */ + return 0; + } + } } /* destroy / show measurement widget */ @@ -846,7 +868,8 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int track_dset = -1; /* all datasets */ } if(track_dset < 0) { - track_dset = find_closest_wave(i, gr); + int tmp; + track_dset = find_closest_wave(i, gr, &tmp); } else { track_dset = -1; /* all datasets */ } diff --git a/src/draw.c b/src/draw.c index f8068466..e38d2d66 100644 --- a/src/draw.c +++ b/src/draw.c @@ -3976,20 +3976,20 @@ int calc_custom_data_yrange(int sweep_idx, const char *express, Graph_ctx *gr) } /* for(dset...) */ return idx; } - -int find_closest_wave(int i, Graph_ctx *gr) +/* return in node_number the node index that is closest to mouse coordinates */ +int find_closest_wave(int i, Graph_ctx *gr, int *node_number) { double xval, yval; char *node = NULL, *sweep = NULL; int sweep_idx = 0; char *saven, *saves, *nptr, *sptr; const char *ntok, *stok; - int wcnt = 0, idx, expression; + int wcnt = -1, idx, expression; + char *ntok_copy = NULL; /* copy of ntok without % */ char *express = NULL; xRect *r = &xctx->rect[GRIDLAYER][i]; - int autoload = 0, closest_dataset = -1; + int autoload = 0, closest_dataset = -1, node_dataset = -1; double min=-1.0; - Raw *raw = NULL; char *custom_rawfile = NULL; /* "rawfile" attr. set in graph: load and switch to specified raw */ char *sim_type = NULL; const char *ptr; @@ -4000,8 +4000,11 @@ int find_closest_wave(int i, Graph_ctx *gr) } if(gr->digital) return -1; + *node_number = -1; autoload = !strboolcmp(get_tok_value(r->prop_ptr,"autoload", 0), "true"); - if(autoload == 0) autoload = 2; + if(autoload == 0) autoload = 2; /* 2: switch */ + else if(autoload == 1) autoload = 33; /* 1: read, 32: no_warning */ + yval = G_Y(xctx->mousey); xval = G_X(xctx->mousex); /* get data to plot */ @@ -4010,51 +4013,92 @@ int find_closest_wave(int i, Graph_ctx *gr) ptr = get_tok_value(r->prop_ptr,"rawfile", 0); if(!ptr[0]) { - if(raw && raw->rawfile) my_strdup2(_ALLOC_ID_, &custom_rawfile, raw->rawfile); + if(xctx->raw && xctx->raw->rawfile) my_strdup2(_ALLOC_ID_, &custom_rawfile, xctx->raw->rawfile); else my_strdup2(_ALLOC_ID_, &custom_rawfile, ""); } else { my_strdup2(_ALLOC_ID_, &custom_rawfile, ptr); } my_strdup2(_ALLOC_ID_, &sim_type, get_tok_value(r->prop_ptr,"sim_type", 0)); - if(sch_waves_loaded()!= -1 && custom_rawfile[0]) { - extra_rawfile(autoload, custom_rawfile, sim_type[0] ? sim_type : xctx->raw->sim_type, -1.0, -1.0); - } - raw = xctx->raw; nptr = node; sptr = sweep; /* process each node given in "node" attribute, get also associated sweep var if any*/ - while( (ntok = my_strtok_r(nptr, "\n", "\"", 0, &saven)) ) { + while( (ntok = my_strtok_r(nptr, "\n", "\"", 4, &saven)) ) { + char *nd = NULL; + int valid_rawfile = 1; + wcnt++; if(strstr(ntok, ",")) { if(find_nth(ntok, ";,", "\"", 0, 2)[0]) continue; /* bus signal: skip */ } stok = my_strtok_r(sptr, "\t\n ", "\"", 0, &saves); nptr = sptr = NULL; dbg(1, "ntok=%s\n", ntok); + + if(custom_rawfile[0]) { + if(extra_rawfile(autoload, custom_rawfile, sim_type[0] ? sim_type : + (xctx->raw && xctx->raw->sim_type ? xctx->raw->sim_type : NULL), -1.0, -1.0) == 0) { + valid_rawfile = 0; + } + } + if(stok && stok[0]) { sweep_idx = get_raw_index(stok, NULL); if( sweep_idx == -1) { sweep_idx = 0; } } + my_strdup2(_ALLOC_ID_, &nd, find_nth(ntok, "%", "\"", 0, 2)); + + if(nd[0]) { + int pos = 1; + if(isonlydigit(find_nth(nd, "\n ", "\"", 0, 1))) pos = 2; + if(xctx->raw && xctx->raw->values) { + char *node_rawfile = NULL; + char *node_sim_type = NULL; + tclvareval("subst {", find_nth(nd, "\n ", "\"", 0, pos), "}", NULL); + my_strdup2(_ALLOC_ID_, &node_rawfile, tclresult()); + tclvareval("subst {", find_nth(nd, "\n ", "\"", 0, pos + 1), "}", NULL); + my_strdup2(_ALLOC_ID_, &node_sim_type, tclresult()[0] ? tclresult() : + sim_type[0] ? sim_type : xctx->raw->sim_type); + dbg(1, "node_rawfile=|%s| node_sim_type=|%s|\n", node_rawfile, node_sim_type); + if(node_rawfile && node_rawfile[0]) { + if(extra_rawfile(autoload, node_rawfile, node_sim_type, -1.0, -1.0) == 0) { + my_free(_ALLOC_ID_, &node_rawfile); + my_free(_ALLOC_ID_, &node_sim_type); + valid_rawfile = 0; + } + } + my_free(_ALLOC_ID_, &node_rawfile); + my_free(_ALLOC_ID_, &node_sim_type); + } + if(pos == 2) node_dataset = atoi(nd); + else node_dataset = -1; + dbg(1, "nd=|%s|, node_dataset = %d\n", nd, node_dataset); + my_strdup(_ALLOC_ID_, &ntok_copy, find_nth(ntok, "%", "\"", 4, 1)); + } else { + node_dataset = -1; + my_strdup(_ALLOC_ID_, &ntok_copy, ntok); + } + if(nd) my_free(_ALLOC_ID_, &nd); + /* if ntok following possible 'alias;' definition contains spaces --> custom data plot */ idx = -1; expression = 0; - if(raw->values) { - if(strstr(ntok, ";")) { - my_strdup2(_ALLOC_ID_, &express, find_nth(ntok, ";", "\"", 0, 2)); + if(xctx->raw->values) { + if(strstr(ntok_copy, ";")) { + my_strdup2(_ALLOC_ID_, &express, find_nth(ntok_copy, ";", "\"", 0, 2)); } else { - my_strdup2(_ALLOC_ID_, &express, ntok); + my_strdup2(_ALLOC_ID_, &express, ntok_copy); } if(strpbrk(express, " \n\t")) { expression = 1; } } - if(expression) idx = raw->nvars; + if(expression) idx = xctx->raw->nvars; else idx = get_raw_index(express, NULL); - dbg(1, "find_closest_wave(): expression=%d, idx=%d\n", expression, idx); - if( idx != -1 ) { + dbg(1, "find_closest_wave(): expression=%d, ntok_copy=%s express=%s idx=%d\n", expression, ntok_copy, express, idx); + if( sch_waves_loaded() != -1 && valid_rawfile && idx != -1 ) { int p, dset, ofs, ofs_end; int first, last; double xx, yy ; /* the p-th point */ @@ -4066,15 +4110,16 @@ int find_closest_wave(int i, Graph_ctx *gr) start = (gr->gx1 <= gr->gx2) ? gr->gx1 : gr->gx2; end = (gr->gx1 <= gr->gx2) ? gr->gx2 : gr->gx1; /* loop through all datasets found in raw file */ - for(dset = 0 ; dset < raw->datasets; dset++) { + for(dset = 0 ; dset < xctx->raw->datasets; dset++) { double prev_x = 0.0; int cnt=0, wrap; - register SPICE_DATA *gvx = raw->values[sweep_idx]; - register SPICE_DATA *gv0 = raw->values[0]; + register SPICE_DATA *gvx = xctx->raw->values[sweep_idx]; + register SPICE_DATA *gv0 = xctx->raw->values[0]; register SPICE_DATA *gvy; - ofs_end = ofs + raw->npoints[dset]; + if(node_dataset != -1 && node_dataset != dset) goto done; + ofs_end = ofs + xctx->raw->npoints[dset]; if(expression) plot_raw_custom_data(sweep_idx, ofs, ofs_end - 1, express, NULL); - gvy = raw->values[idx]; + gvy = xctx->raw->values[idx]; dbg(1, "find_closest_wave(): dset=%d\n", dset); first = -1; /* Process "npoints" simulation items @@ -4099,21 +4144,23 @@ int find_closest_wave(int i, Graph_ctx *gr) sweepvar_wrap++; } if(xx >= start && xx <= end) { + double tmp; if(first == -1) first = p; if( p > ofs && XSIGN(xval - xx) != XSIGN(xval - prev_x)) { - + tmp = fabs(yval - yy); if(min < 0.0) { - min = fabs(yval - yy); + min = tmp; closest_dataset = sweepvar_wrap; + *node_number = wcnt; } else { - double tmp = fabs(yval - yy); if(tmp < min) { min = tmp; closest_dataset = sweepvar_wrap; + *node_number = wcnt; } } - dbg(1, "find_closest_wave(): xval=%g yval=%g xx=%g yy=%g sweepvar_wrap=%d ntok=%s stok=%s\n", - xval, yval, xx, yy, sweepvar_wrap, ntok, stok? stok : ""); + dbg(1, "find_closest_wave(): dset=%d expression=%d idx=%d wcnt=%d dist=%g sweepvar_wrap=%d ntok=%s stok=%s\n", + dset, expression, idx, wcnt, tmp, sweepvar_wrap, ntok, stok? stok : ""); } last = p; ++cnt; @@ -4121,22 +4168,24 @@ int find_closest_wave(int i, Graph_ctx *gr) prev_x = xx; } /* for(p = ofs ; p < ofs + raw->npoints[dset]; p++) */ /* offset pointing to next dataset */ + done: ofs = ofs_end; sweepvar_wrap++; } /* for(dset...) */ } /* if( (idx = get_raw_index(ntok, NULL)) != -1 ) */ - ++wcnt; } /* while( (ntok = my_strtok_r(nptr, "\n\t ", "", 0, &saven)) ) */ - dbg(0, "closest dataset=%d\n", closest_dataset); + dbg(0, "closest dataset=%d wave index=%d\n", closest_dataset, *node_number); if(express) my_free(_ALLOC_ID_, &express); if(sch_waves_loaded()!= -1 && custom_rawfile[0]) extra_rawfile(5, NULL, NULL, -1.0, -1.0); my_free(_ALLOC_ID_, &custom_rawfile); my_free(_ALLOC_ID_, &sim_type); + if(ntok_copy) my_free(_ALLOC_ID_, &ntok_copy); my_free(_ALLOC_ID_, &node); my_free(_ALLOC_ID_, &sweep); + dbg(1, "find_closest_wave(): node_number = %d\n", *node_number); return closest_dataset; } @@ -4311,7 +4360,6 @@ void draw_graph(int i, int flags, Graph_ctx *gr, void *ct) xctx->raw->npoints[0] = xctx->raw->allpoints; } - my_free(_ALLOC_ID_, &nd); dbg(1, "ntok=|%s|\nntok_copy=|%s|\nnode_dataset=%d\n", ntok, ntok_copy, node_dataset); tmp_ptr = find_nth(ntok_copy, ";", "\"", 4, 2); diff --git a/src/xschem.h b/src/xschem.h index 37745003..45d87f9c 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1312,7 +1312,7 @@ extern int calc_custom_data_yrange(int sweep_idx, const char *express, Graph_ctx extern int sch_waves_loaded(void); extern int edit_wave_attributes(int what, int i, Graph_ctx *gr); extern void draw_graph(int i, int flags, Graph_ctx *gr, void *ct); -extern int find_closest_wave(int i, Graph_ctx *gr); +extern int find_closest_wave(int i, Graph_ctx *gr, int *node_number); extern void setup_graph_data(int i, int skip, Graph_ctx *gr); extern int graph_fullyzoom(xRect *r, Graph_ctx *gr, int graph_dataset); extern int graph_fullxzoom(int i, Graph_ctx *gr, int dataset);