[Snap Cursor (WIP)]: Experimental feature 'snap_cursor' is now available to be selected from the Options menu (disabled by default). This is a work in progress and needs a lot more polishing to be properly usable. Currently only supports snapping to nearest component-endpoint.

This commit is contained in:
Chayan Deb 2025-01-20 23:20:53 +05:30
parent ed1a471f5d
commit 320b8efc4b
3 changed files with 154 additions and 2 deletions

View File

@ -1393,6 +1393,51 @@ void draw_crosshair(int what)
xctx->draw_pixmap = sdp;
}
/* cursor_type == 0 : only erase drawn cursor
* cursor_type == 1 : erase and draw a normal grid-snapping cursor
* cursor_type == 2 : erase and draw a diamond-shaped cursor that snaps to a component endpoint */
void draw_snap_cursor(int cursor_type)
{
int sdw, sdp;
dbg(1, "draw_snap_cursor(): cursor_type=%d\n", cursor_type);
sdw = xctx->draw_window;
sdp = xctx->draw_pixmap;
if(!xctx->mouse_inside) return;
xctx->draw_pixmap = 0;
xctx->draw_window = 1;
if(fix_broken_tiled_fill || !_unix) {
MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0],
0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw),
xctx->xrect[0].width, 4 * INT_WIDTH(xctx->lw),
0, (int)Y_TO_SCREEN(xctx->prev_crossy) - 2 * INT_WIDTH(xctx->lw));
MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0],
(int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0,
4 * INT_WIDTH(xctx->lw), xctx->xrect[0].height,
(int)X_TO_SCREEN(xctx->prev_crossx) - 2 * INT_WIDTH(xctx->lw), 0);
} else {
drawtemparc(xctx->gctiled, NOW, xctx->prev_crossx, xctx->prev_crossy, 1, 0, 360);
}
if(cursor_type != 1) {
/*drawline(xctx->crosshair_layer, NOW, xctx->mousex_snap, xctx->mousey_snap, xctx->mousex_snap, xctx->mousey_snap, 0, NULL);*/
double x, y;
find_closest_net_or_symbol_pin(xctx->mousex, xctx->mousey, &x, &y);
drawarc(xctx->crosshair_layer, NOW, x, y, 1, 1, 360, 1, 0);
draw_selection(xctx->gc[SELLAYER], 0);
xctx->prev_crossx = x;
xctx->prev_crossy = y;
} else {
drawarc(xctx->crosshair_layer, NOW, xctx->mousex_snap, xctx->mousey_snap, 1, 1, 360, 1, 0);
draw_selection(xctx->gc[SELLAYER], 0);
xctx->prev_crossx = xctx->mousex_snap;
xctx->prev_crossy = xctx->mousey_snap;
}
xctx->draw_window = sdw;
xctx->draw_pixmap = sdp;
}
/* complete the STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */
static int end_place_move_copy_zoom()
{
@ -2218,6 +2263,7 @@ int callback(const char *winpath, int event, int mx, int my, KeySym key,
#endif
int draw_xhair = tclgetboolvar("draw_crosshair");
int infix_interface = tclgetboolvar("infix_interface");
int snap_cursor = tclgetboolvar("snap_cursor");
int rstate; /* (reduced state, without ShiftMask) */
/* this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease
@ -2335,6 +2381,7 @@ int rstate; /* (reduced state, without ShiftMask) */
case LeaveNotify:
if(draw_xhair) draw_crosshair(1);
if(snap_cursor) draw_snap_cursor(0);
tclvareval(xctx->top_path, ".drw configure -cursor {}" , NULL);
xctx->mouse_inside = 0;
break;
@ -2403,11 +2450,13 @@ int rstate; /* (reduced state, without ShiftMask) */
if(draw_xhair) {
draw_crosshair(1);
}
if(snap_cursor) draw_snap_cursor(0);
if(xctx->ui_state & STARTPAN) pan(RUBBER, mx, my);
if(xctx->semaphore >= 2) {
if(draw_xhair) {
draw_crosshair(2);
}
if(snap_cursor) draw_snap_cursor(2);
break;
}
dbg(1, "ui_state=%d deltax=%g\n", xctx->ui_state, xctx->deltax);
@ -2502,6 +2551,7 @@ int rstate; /* (reduced state, without ShiftMask) */
if(draw_xhair) {
draw_crosshair(2);
}
if(snap_cursor) draw_snap_cursor(2);
break;
case KeyRelease:
@ -4259,6 +4309,7 @@ int rstate; /* (reduced state, without ShiftMask) */
statusmsg(str,1);
}
if(draw_xhair) draw_crosshair(0);
if(snap_cursor) draw_snap_cursor(2);
break;
case -3: /* double click : edit prop */
if( waves_selected(event, key, state, button)) {

View File

@ -1601,6 +1601,104 @@ void drawarc(int c, int what, double x, double y, double r, double a, double b,
}
}
void draw_snap_point(int c, int what, double x, double y, double r, double a, double b, int arc_fill, int dash)
{
static int i=0;
static XArc xarc[CADDRAWBUFFERSIZE];
double x1, y1, x2, y2; /* arc bbox */
double xx1, yy1, xx2, yy2; /* complete circle bbox in screen coords */
GC gc;
if(arc_fill || dash) what = NOW;
if(!has_x) return;
if(what & ADD)
{
if(i>=CADDRAWBUFFERSIZE)
{
if(xctx->draw_window) XDrawArcs(display, xctx->window, xctx->gc[c], xarc,i);
if(xctx->draw_pixmap) XDrawArcs(display, xctx->save_pixmap, xctx->gc[c], xarc,i);
i=0;
}
xx1=X_TO_SCREEN(x-r);
yy1=Y_TO_SCREEN(y-r);
xx2=X_TO_SCREEN(x+r);
yy2=Y_TO_SCREEN(y+r);
arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2);
x1=X_TO_SCREEN(x1);
y1=Y_TO_SCREEN(y1);
x2=X_TO_SCREEN(x2);
y2=Y_TO_SCREEN(y2);
if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) )
{
xarc[i].x=(short)xx1;
xarc[i].y=(short)yy1;
xarc[i].width =(unsigned short)(xx2 - xx1);
xarc[i].height=(unsigned short)(yy2 - yy1);
xarc[i].angle1 = (short)(a*64);
xarc[i].angle2 = (short)(b*64);
++i;
}
}
else if(what & NOW)
{
xx1=X_TO_SCREEN(x-r);
yy1=Y_TO_SCREEN(y-r);
xx2=X_TO_SCREEN(x+r);
yy2=Y_TO_SCREEN(y+r);
if(arc_fill)
arc_bbox(x, y, r, 0, 360, &x1,&y1,&x2,&y2);
else
arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2);
x1=X_TO_SCREEN(x1);
y1=Y_TO_SCREEN(y1);
x2=X_TO_SCREEN(x2);
y2=Y_TO_SCREEN(y2);
if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) )
{
if(dash) {
char dash_arr[2];
dash_arr[0] = dash_arr[1] = (char)dash;
XSetDashes(display, xctx->gc[c], 0, dash_arr, 1);
XSetLineAttributes (display, xctx->gc[c], XLINEWIDTH(xctx->lw), xDashType, xCap, xJoin);
}
if(xctx->draw_window) {
XDrawArc(display, xctx->window, xctx->gc[c], (int)xx1, (int)yy1,
(int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64));
}
if(xctx->draw_pixmap) {
XDrawArc(display, xctx->save_pixmap, xctx->gc[c], (int)xx1, (int)yy1,
(int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64));
}
if(xctx->fill_pattern && (xctx->fill_type[c] || arc_fill == 3) ){
if(arc_fill & 2) gc = xctx->gc[c];
else gc = xctx->gcstipple[c];
if(arc_fill) {
if(xctx->draw_window)
XFillArc(display, xctx->window, gc, (int)xx1, (int)yy1,
(int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64));
if(xctx->draw_pixmap)
XFillArc(display, xctx->save_pixmap, gc, (int)xx1, (int)yy1,
(int)(xx2-xx1), (int)(yy2-yy1), (int)(a*64), (int)(b*64));
}
}
if(dash) {
XSetLineAttributes (display, xctx->gc[c], XLINEWIDTH(xctx->lw) ,LineSolid, LINECAP , LINEJOIN);
}
}
}
else if((what & END) && i)
{
if(xctx->draw_window) XDrawArcs(display, xctx->window, xctx->gc[c], xarc,i);
if(xctx->draw_pixmap) XDrawArcs(display, xctx->save_pixmap, xctx->gc[c], xarc,i);
i=0;
}
}
void filledrect(int c, int what, double rectx1,double recty1,double rectx2,double recty2, int fill,
int e_a, int e_b)
{

View File

@ -7622,7 +7622,7 @@ set tctx::global_list {
PDK_ROOT PDK SKYWATER_MODELS SKYWATER_STDCELLS
INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR XSCHEM_LIBRARY_PATH
add_all_windows_drives auto_hilight auto_hilight_graph_nodes autofocus_mainwindow
autotrim_wires infix_interface orthogonal_wiring bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers
autotrim_wires orthogonal_wiring snap_cursor bespice_listen_port big_grid_points bus_replacement_char cadgrid cadlayers
cadsnap cairo_font_name cairo_font_scale change_lw color_ps tctx::colors compare_sch constr_mv
copy_cell crosshair_layer custom_label_prefix custom_token dark_colors dark_colorscheme
dark_gui_colorscheme delay_flag dim_bg dim_value disable_unique_names
@ -8042,7 +8042,7 @@ proc build_widgets { {topwin {} } } {
global recentfile color_ps transparent_svg menu_debug_var enable_stretch
global netlist_show flat_netlist split_files compare_sch intuitive_interface
global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width
global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type
global cadsnap cadgrid draw_window toolbar_visible hide_symbols undo_type snap_cursor
global disable_unique_names persistent_command autotrim_wires infix_interface orthogonal_wiring en_hilight_conn_inst
global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry
if { $dark_gui_colorscheme} {
@ -8168,6 +8168,8 @@ proc build_widgets { {topwin {} } } {
-selectcolor $selectcolor -accelerator Y
$topwin.menubar.option add checkbutton -label "Enable infix-interface" -variable infix_interface \
-selectcolor $selectcolor
$topwin.menubar.option add checkbutton -label "Enable snap cursor" -variable snap_cursor \
-selectcolor $selectcolor
$topwin.menubar.option add checkbutton -label "Enable orthogonal wiring" -variable orthogonal_wiring \
-selectcolor $selectcolor -accelerator Shift+L
$topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \
@ -9101,6 +9103,7 @@ set_ne persistent_command 0
set_ne intuitive_interface 1
set_ne autotrim_wires 0
set_ne infix_interface 0
set_ne snap_cursor 0
set_ne orthogonal_wiring 1
set_ne compare_sch 0
set_ne disable_unique_names 0