From e1488da40791d3befebd0b678cd555ebf07b59cc Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Tue, 11 Mar 2025 20:47:00 +0100 Subject: [PATCH 1/2] add `xschem rect gui`, `xschem line gui`, `xschem polygon gui`, `xschem wire gui` to start placement of these objects with 1st point set to mouse coordinates --- doc/xschem_man/developer_info.html | 41 +++-- src/callback.c | 4 +- src/scheduler.c | 105 ++++++++++--- src/xinit.c | 2 +- src/xschem.h | 2 + src/xschem.tcl | 231 +++++++++++++++++++++-------- 6 files changed, 291 insertions(+), 94 deletions(-) diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 25369cc1..06d9e035 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -989,13 +989,17 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
  • is_generator symbol
  •     tell if 'symbol' is a generator (symbol(param1,param2,...) 
  • line [x1 y1 x2 y2] [pos] [propstring] [draw]
  • +       line
    +       line gui
        if 'x1 y1 x2 y2'is given place line on current
        layer (rectcolor) at indicated coordinates.
    -   if 'pos' is given insert at given position in rectangle array.
    +   if 'pos' is given insert at given position in line array.
        if 'pos' set to -1 append to last element in line array.
        'propstring' is the attribute string. Set to empty if not given.
        if 'draw' is set to 1 (default) draw the new object, else don't
    -   If no coordinates are given start a GUI operation of line placement 
    + If no coordinates are given start a GUI operation of line placement + if `gui` argument is given start a line GUI placement with 1st point + set to current mouse coordinates
  • line_width n
  •     set line width to floating point number 'n' 
  • list_hierarchy
  • @@ -1161,8 +1165,10 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        If not given take from symbol template attribute.
  • place_text
  •     Start a GUI placement of a text object 
    -
  • polygon
  • -   Start a GUI placement of a polygon 
    +
  • polygon [gui]
  • +   Start a GUI placement of a polygon
    +   if `gui` argument is given start a polygon GUI placement with 1st point
    +   set to current mouse coordinates 
  • preview_window create|draw|destroy|close [win_path] [file]
  •     destroy: will delete preview schematic data and destroy container window
        close: same as destroy but leave the container window.
    @@ -1337,14 +1343,19 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        Rebuild selection list
  • record_global_node n node
  •     call the record_global_node function (list of netlist global nodes) 
    -
  • rect [x1 y1 x2 y2] [pos] [propstring] [draw]
  • -   if 'x1 y1 x2 y2'is given place recangle on current
    -   layer (rectcolor) at indicated coordinates.
    -   if 'pos' is given insert at given position in rectangle array.
    -   if 'pos' set to -1 append rectangle to last element in rectangle array.
    -   'propstring' is the attribute string. Set to empty if not given.
    -   if 'draw' is set to 1 (default) draw the new object, else don't
    -   If no coordinates are given start a GUI operation of rectangle placement 
    +
  • rect ...
  • +   rect [x1 y1 x2 y2] [pos] [propstring] [draw]
    +     if 'x1 y1 x2 y2'is given place recangle on current
    +     layer (rectcolor) at indicated coordinates.
    +     if 'pos' is given insert at given position in rectangle array.
    +     if 'pos' set to -1 append rectangle to last element in rectangle array.
    +     'propstring' is the attribute string. Set to empty if not given.
    +     if 'draw' is set to 1 (default) draw the new object, else don't
    +   rect
    +     If no coordinates are given start a GUI operation of rectangle placement
    +   rect gui
    +     if `gui` argument is given start a GUI placement of a rectangle with 1st
    +     point starting from current mouse coordinates 
  • redo
  •     Redo last undone action 
  • redraw
  • @@ -1664,8 +1675,12 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        
  • wire_coord n
  •     return 4 coordinates of wire[n] 
  • wire [x1 y1 x2 y2] [pos] [prop] [sel]
  • +   wire
    +   wire gui
        Place a new wire
    -   if no coordinates are given start a GUI wire placement 
    + if no coordinates are given start a GUI wire placement + if `gui` argument is given start a GUI placement of a wire with 1st point + starting from current mouse coordinates
  • wire_cut [x y] [noalign]
  •     start a wire cut operation. Point the mouse in the middle of a wire and
        Alt-click right button.
    diff --git a/src/callback.c b/src/callback.c
    index f05ccbb1..c95383e6 100644
    --- a/src/callback.c
    +++ b/src/callback.c
    @@ -212,7 +212,7 @@ static void start_place_symbol(void)
         }
     }
     
    -static void start_line(double mx, double my)
    +void start_line(double mx, double my)
     {
         xctx->last_command = STARTLINE;
         if(xctx->ui_state & STARTLINE) {
    @@ -232,7 +232,7 @@ static void start_line(double mx, double my)
         new_line(PLACE, mx, my);
     }
     
    -static void start_wire(double mx, double my)
    +void start_wire(double mx, double my)
     {
       dbg(1, "start_wire(): ui_state=%d, ui_state2=%d last_command=%d\n",
           xctx->ui_state, xctx->ui_state2, xctx->last_command);
    diff --git a/src/scheduler.c b/src/scheduler.c
    index 84f94fa5..c1e66f13 100644
    --- a/src/scheduler.c
    +++ b/src/scheduler.c
    @@ -2787,13 +2787,17 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
         break;
         case 'l': /*----------------------------------------------*/
         /* line [x1 y1 x2 y2] [pos] [propstring] [draw]
    +     * line
    +     * line gui
          *   if 'x1 y1 x2 y2'is given place line on current
          *   layer (rectcolor) at indicated coordinates.
    -     *   if 'pos' is given insert at given position in rectangle array.
    +     *   if 'pos' is given insert at given position in line array.
          *   if 'pos' set to -1 append to last element in line array.
          *   'propstring' is the attribute string. Set to empty if not given.
          *   if 'draw' is set to 1 (default) draw the new object, else don't
    -     *   If no coordinates are given start a GUI operation of line placement */
    +     *   If no coordinates are given start a GUI operation of line placement
    +     *   if `gui` argument is given start a line GUI placement with 1st point
    +     *   set to current mouse coordinates */
         if(!strcmp(argv[1], "line"))
         {
           double x1,y1,x2,y2;
    @@ -2819,6 +2823,21 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
             }
             set_modify(1);
           }
    +      else if(argc == 3 && !strcmp(argv[2], "gui")) {
    +        int prev_state = xctx->ui_state;
    +        int infix_interface = tclgetboolvar("infix_interface");
    +        if(infix_interface) {
    +          start_line(xctx->mousex_snap, xctx->mousey_snap);
    +          if(prev_state == STARTLINE) {
    +            tcleval("set constr_mv 0" );
    +            xctx->constr_mv=0;
    +          }
    +        } else {
    +          xctx->last_command = 0;
    +          xctx->ui_state |= MENUSTART;
    +          xctx->ui_state2 = MENUSTARTLINE;
    +        }
    +      }
           else {
             xctx->last_command = 0;
             xctx->ui_state |= MENUSTART;
    @@ -3701,13 +3720,28 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           Tcl_ResetResult(interp);
         }
     
    -    /* polygon
    -     *   Start a GUI placement of a polygon */
    +    /* polygon [gui]
    +     *   Start a GUI placement of a polygon
    +     *   if `gui` argument is given start a polygon GUI placement with 1st point
    +     *   set to current mouse coordinates */
         else if(!strcmp(argv[1], "polygon"))
         {
           if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
    -      xctx->ui_state |= MENUSTART;
    -      xctx->ui_state2 = MENUSTARTPOLYGON;
    +      if(argc > 2 && !strcmp(argv[2], "gui")) {
    +        int infix_interface = tclgetboolvar("infix_interface");
    +        if(infix_interface) {
    +          xctx->mx_double_save=xctx->mousex_snap;
    +          xctx->my_double_save=xctx->mousey_snap;
    +          xctx->last_command = 0;
    +          new_polygon(PLACE, xctx->mousex_snap, xctx->mousey_snap);
    +        } else {
    +          xctx->ui_state |= MENUSTART;
    +          xctx->ui_state2 = MENUSTARTPOLYGON;
    +        }
    +      } else {
    +        xctx->ui_state |= MENUSTART;
    +        xctx->ui_state2 = MENUSTARTPOLYGON;
    +      }
         }
     
         /* preview_window create|draw|destroy|close [win_path] [file]
    @@ -4434,7 +4468,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
         }
     
         /* rebuild_connectivity
    -         Rebuild logical connectivity abstraction of schematic */
    +     *   Rebuild logical connectivity abstraction of schematic */
         else if(!strcmp(argv[1], "rebuild_connectivity"))
         {
           int err = 0;
    @@ -4473,14 +4507,19 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
         }
     
    -    /* rect [x1 y1 x2 y2] [pos] [propstring] [draw]
    -     *   if 'x1 y1 x2 y2'is given place recangle on current
    -     *   layer (rectcolor) at indicated coordinates.
    -     *   if 'pos' is given insert at given position in rectangle array.
    -     *   if 'pos' set to -1 append rectangle to last element in rectangle array.
    -     *   'propstring' is the attribute string. Set to empty if not given.
    -     *   if 'draw' is set to 1 (default) draw the new object, else don't
    -     *   If no coordinates are given start a GUI operation of rectangle placement */
    +    /* rect ...
    +     *   rect [x1 y1 x2 y2] [pos] [propstring] [draw]
    +     *     if 'x1 y1 x2 y2'is given place recangle on current
    +     *     layer (rectcolor) at indicated coordinates.
    +     *     if 'pos' is given insert at given position in rectangle array.
    +     *     if 'pos' set to -1 append rectangle to last element in rectangle array.
    +     *     'propstring' is the attribute string. Set to empty if not given.
    +     *     if 'draw' is set to 1 (default) draw the new object, else don't
    +     *   rect
    +     *     If no coordinates are given start a GUI operation of rectangle placement
    +     *   rect gui
    +     *     if `gui` argument is given start a GUI placement of a rectangle with 1st
    +     *     point starting from current mouse coordinates */
         else if(!strcmp(argv[1], "rect"))
         {
           double x1,y1,x2,y2;
    @@ -4510,8 +4549,18 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
               xctx->draw_window = save;
             }
             set_modify(1);
    -      }
    -      else {
    +      } else if(argc > 2 && !strcmp(argv[2], "gui")) {
    +        int infix_interface = tclgetboolvar("infix_interface");
    +        if(infix_interface) {
    +          xctx->mx_double_save=xctx->mousex_snap;
    +          xctx->my_double_save=xctx->mousey_snap;
    +          xctx->last_command = 0;
    +          new_rect(PLACE,xctx->mousex_snap, xctx->mousey_snap);
    +        } else {
    +          xctx->ui_state |= MENUSTART;
    +          xctx->ui_state2 = MENUSTARTRECT;
    +        } 
    +      } else {
             xctx->ui_state |= MENUSTART;
             xctx->ui_state2 = MENUSTARTRECT;
           }
    @@ -6374,8 +6423,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           }
         }
         /* wire [x1 y1 x2 y2] [pos] [prop] [sel]
    +     *   wire
    +     *   wire gui
          *   Place a new wire
    -     *   if no coordinates are given start a GUI wire placement */
    +     *   if no coordinates are given start a GUI wire placement
    +     *   if `gui` argument is given start a GUI placement of a wire with 1st point
    +     *   starting from current mouse coordinates */
         else if(!strcmp(argv[1], "wire"))
         {
           double x1,y1,x2,y2;
    @@ -6403,7 +6456,21 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
             if(tclgetboolvar("autotrim_wires")) trim_wires();
             set_modify(1);
           }
    -      else {
    +      else if(argc > 2 && !strcmp(argv[2], "gui")) {
    +        int prev_state = xctx->ui_state;
    +        int infix_interface = tclgetboolvar("infix_interface");
    +        if(infix_interface) {
    +          start_wire(xctx->mousex_snap, xctx->mousey_snap);
    +          if(prev_state == STARTWIRE) {
    +            tcleval("set constr_mv 0" );
    +            xctx->constr_mv=0;
    +          }
    +        } else {
    +          xctx->last_command = 0;
    +          xctx->ui_state |= MENUSTART;                   
    +          xctx->ui_state2 = MENUSTARTWIRE;
    +        }
    +      } else {
             xctx->last_command = 0;
             xctx->ui_state |= MENUSTART;
             xctx->ui_state2 = MENUSTARTWIRE;
    diff --git a/src/xinit.c b/src/xinit.c
    index 192ae975..8ffe0f5c 100644
    --- a/src/xinit.c
    +++ b/src/xinit.c
    @@ -1179,7 +1179,7 @@ static int source_tcl_file(char *s)
         fprintf(errfp, "Tcl_AppInit() error: can not execute %s, please fix:\n", s);
         fprintf(errfp, "%s", tclresult());
         #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6
    -    fprintf(errfp, "Line No: %d\n", Tcl_GetErrorLine(interp));
    +    fprintf(errfp, "\nLine No: %d\n", Tcl_GetErrorLine(interp));
         #endif
         fprintf(errfp, "\n");
         #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6
    diff --git a/src/xschem.h b/src/xschem.h
    index eb62ea35..93c93b09 100644
    --- a/src/xschem.h
    +++ b/src/xschem.h
    @@ -1401,6 +1401,8 @@ extern void tclmainloop(void);
     extern int Tcl_AppInit(Tcl_Interp *interp);
     extern void abort_operation(void);
     extern void draw_crosshair(int what, int state);
    +extern void start_line(double mx, double my);
    +extern void start_wire(double mx, double my);
     extern void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr);
     /* extern void snapped_wire(double c_snap); */
     extern void unselect_attached_floaters(void);
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index 8c42401b..ba2cbee2 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -4490,7 +4490,8 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
       set_ne file_dialog_files2 {}
       panedwindow  .load.l -orient horizontal -height 8c
       if { $loadfile == 2} {frame .load.l.recent -takefocus 0}
    -  frame .load.l.paneleft -takefocus 0 -highlightcolor red -highlightthickness 2 -bg {grey90}
    +  frame .load.l.paneleft -takefocus 0 -highlightcolor red -highlightthickness 2 -bg {grey90} \
    +    -highlightbackground [option get . background {}]
       eval [subst {listbox .load.l.paneleft.list -listvariable file_dialog_names1 -width 40 -height 12 \
         -fg black -background {grey90} -highlightthickness 0 -relief flat -borderwidth 0 \
         -yscrollcommand ".load.l.paneleft.yscroll set" -selectmode browse \
    @@ -4518,14 +4519,12 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
         }
       }
     
    -
       panedwindow .load.l.paneright -orient vertical 
       frame .load.l.paneright.f -takefocus 0
       frame .load.l.paneright.draw -background white -height 3.8c -takefocus 0
       .load.l.paneright add .load.l.paneright.f
       .load.l.paneright add .load.l.paneright.draw -minsize 150
     
    -
       if { ![catch {.load.l.paneright  panecget .load.l.paneright.f -stretch}]} {
         set optnever {-stretch never}
         set optalways {-stretch always}
    @@ -4546,6 +4545,7 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
     
       listbox .load.l.paneright.f.list  -background {grey90} -listvariable file_dialog_files2 -width 20 -height 12\
         -fg black -highlightcolor red -highlightthickness 2 \
    +    -highlightbackground [option get . background {}] \
         -yscrollcommand ".load.l.paneright.f.yscroll set" -selectmode $selmode \
         -xscrollcommand ".load.l.paneright.f.xscroll set" -exportselection 0
       scrollbar .load.l.paneright.f.yscroll -command ".load.l.paneright.f.list yview" -takefocus 0
    @@ -4596,10 +4596,12 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
         .load.l.paneleft.list selection set $file_dialog_index1
       }
       label .load.buttons_bot.label  -text { File:}
    -  entry .load.buttons_bot.entry -highlightcolor red -highlightthickness 2
    +  entry .load.buttons_bot.entry -highlightcolor red -highlightthickness 2 \
    +    -highlightbackground [option get . background {}]
       entry_replace_selection .load.buttons_bot.entry
       label .load.buttons_bot.srclab  -text { Search:}
    -  entry .load.buttons_bot.src -width 18 -highlightcolor red -highlightthickness 2
    +  entry .load.buttons_bot.src -width 18 -highlightcolor red -highlightthickness 2 \
    +    -highlightbackground [option get . background {}]
       entry_replace_selection .load.buttons_bot.src
       .load.buttons_bot.src delete 0 end
       .load.buttons_bot.src insert 0 $file_dialog_globfilter
    @@ -4627,28 +4629,6 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
         set file_dialog_retval {   }
       }
     
    -  # radiobutton .load.buttons_bot.all -text All -variable file_dialog_globfilter -value {*} -takefocus 0 \
    -  #    -command {
    -  #       set file_dialog_ext $file_dialog_globfilter
    -  #       setglob $file_dialog_dir1
    -  #       .load.buttons_bot.src delete 0 end
    -  #       .load.buttons_bot.src insert 0 $file_dialog_globfilter
    -  #     }
    -  # radiobutton .load.buttons_bot.sym -text .sym -variable file_dialog_globfilter -value {*.sym} -takefocus 0 \
    -  #    -command {
    -  #       set file_dialog_ext $file_dialog_globfilter
    -  #       setglob $file_dialog_dir1
    -  #       .load.buttons_bot.src delete 0 end
    -  #       .load.buttons_bot.src insert 0 $file_dialog_globfilter
    -  #     }
    -  # radiobutton .load.buttons_bot.sch -text .sch -variable file_dialog_globfilter -value {*.sch} -takefocus 0 \
    -  #    -command {
    -  #       set file_dialog_ext $file_dialog_globfilter
    -  #       setglob $file_dialog_dir1
    -  #       .load.buttons_bot.src delete 0 end
    -  #       .load.buttons_bot.src insert 0 $file_dialog_globfilter
    -  #     }
    -
       button .load.buttons.up -width 5 -text Up -command {load_file_dialog_up  $file_dialog_dir1} -takefocus 0
       label .load.buttons.mkdirlab -text { New dir: } 
       entry .load.buttons.newdir -width 16 -takefocus 0
    @@ -4717,7 +4697,8 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
         destroy .load
         set $global_initdir \"\$file_dialog_dir1\"
       "
    -
    +  bind .load  {.load.buttons.home invoke }
    +  bind .load  {.load.buttons.up invoke }
       ### update
     
       if { [info exists file_dialog_v_sp0] } {
    @@ -4806,6 +4787,133 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
       return [file_dialog_getresult $loadfile $confirm_overwrt]
     }
     
    +
    +
    +#### Display preview of selected symbol
    +proc insert_symbol_focusin {} {
    +  puts insert_symbol_focusin
    +  set sel [.ins.center.left.l curselection]
    +  if {$sel eq {}} {
    +    set sel [.ins.center.left.l index active]
    +    .ins.center.left.l selection set active
    +  } 
    +}
    +
    +proc insert_symbol_preview {} {
    +  puts insert_symbol_preview
    +  global insert_symbol
    +  xschem preview_window close .ins.center.right {}
    +  .ins.center.right configure -bg white
    +  bind .ins.center.right  {}
    +  bind .ins.center.right  {}
    +  set sel [.ins.center.left.l curselection]
    +  if {$sel eq {}} {
    +    set sel [.ins.center.left.l index active]
    +    .ins.center.left.l selection set active
    +  }
    +  if {$sel ne {}} {
    +    set f [lindex $insert_symbol(fullpathlist) $sel 0]
    +    if {$f ne {}} {
    +      set type [is_xschem_file $f]
    +      if {$type ne {0}} {
    +        .ins.center.right configure -bg {}
    +        xschem preview_window create .ins.center.right {}
    +        xschem preview_window draw .ins.center.right [list $f]
    +        bind .ins.center.right  "xschem preview_window draw .ins.center.right [list $f]"
    +        bind .ins.center.right  "xschem preview_window draw .ins.center.right [list $f]"
    +      }
    +    }
    +  }
    +}
    +
    +# new alternate insert_symbol browser
    +#### fill list of files matching pattern
    +proc insert_symbol_filelist {paths {maxdepth 1}} {
    +  puts insert_symbol_filelist
    +  global insert_symbol
    +  set insert_symbol(regex) [.ins.top.pat_e get]
    +  set f [match_file $insert_symbol(regex) $paths $maxdepth]
    +  set insert_symbol(list) {}
    +  set insert_symbol(fullpathlist) {}
    +  .ins.center.left.l activate 0
    +  foreach i $f {
    +    set fname [rel_sym_path $i]
    +    lappend insert_symbol(list) $fname
    +    lappend insert_symbol(fullpathlist) $i
    +  }
    +}
    +
    +proc insert_symbol_place {} {
    +  puts insert_symbol_place
    +  global insert_symbol
    +  set sel [.ins.center.left.l curselection]
    +  if {$sel eq {}} {
    +    set sel [.ins.center.left.l index active]
    +    .ins.center.left.l selection set active
    +  }
    +  if {$sel ne {}} {
    +    set f [lindex $insert_symbol(fullpathlist) $sel 0]
    +    if {$f ne {}} {
    +      set type [is_xschem_file $f]
    +      if {$type ne {0}} {
    +        xschem place_symbol $f
    +      }
    +    }
    +  }
    +}
    +
    +#### paths: list of paths to use for listing symbols
    +#### maxdepth: how many levels to descend for each $paths directory (-1: no limit)
    +proc insert_symbol {{paths {}} {maxdepth 1}} {
    +  global insert_symbol
    +  # xschem set semaphore [expr {[xschem get semaphore] +1}]
    +  toplevel .ins
    +  frame .ins.top -takefocus 0
    +  panedwindow  .ins.center -orient horizontal -height 8c
    +  frame .ins.center.left  -takefocus 0
    +  frame .ins.center.right -width 300 -height 250 -bg white -takefocus 0
    +  .ins.center add .ins.center.left
    +  .ins.center add .ins.center.right
    +  frame .ins.bottom  -takefocus 0
    +  pack .ins.top -side top -fill x
    +  pack .ins.center -side top -expand 1 -fill both
    +  pack .ins.bottom -side top -fill x
    +  listbox .ins.center.left.l -listvariable insert_symbol(list) -width 50 -height 20 \
    +    -yscrollcommand ".ins.center.left.s set" -highlightcolor red -highlightthickness 2 \
    +    -activestyle underline -highlightbackground [option get . background {}] \
    +    -exportselection 0
    +  scrollbar .ins.center.left.s -command ".ins.center.left.l yview" -takefocus 0
    +  pack .ins.center.left.l -expand 1 -fill both -side left
    +  pack .ins.center.left.s -fill y -side left
    +  label .ins.top.pat_l -text Pattern:
    +  entry .ins.top.pat_e -width 20 -highlightcolor red -highlightthickness 2 \
    +     -highlightbackground [option get . background {}]
    +  if {[info exists insert_symbol(regex)]} { 
    +    .ins.top.pat_e insert 0 $insert_symbol(regex)
    +  }
    +  bind .ins.top.pat_e  "
    +    if {{%K} ne {Tab}} {
    +      insert_symbol_filelist [list $paths] [list $maxdepth]
    +    }
    +  "
    +  bind .ins.center.left.l <> { insert_symbol_preview }
    +  bind .ins.center.left.l  { insert_symbol_focusin }
    +  button .ins.bottom.dismiss -takefocus 0 -text Dismiss -command {
    +    xschem preview_window close .ins.center.right {}
    +    destroy .ins
    +  }
    +  button .ins.bottom.insert -takefocus 0 -text Insert -command {
    +    insert_symbol_place
    +  }
    +  pack .ins.bottom.insert .ins.bottom.dismiss -side left
    +  pack .ins.top.pat_l -side left
    +  pack .ins.top.pat_e -side left
    +  insert_symbol_filelist $paths $maxdepth
    +  # tkwait window .ins
    +  # xschem set semaphore [expr {[xschem get semaphore] -1}]
    +}
    +# /new alternate insert_symbol browser
    +
     # get last n path components: example , n=1 --> /aaa/bbb/ccc/ddd.sch -> ccc/ddd.sch
     proc get_cell {s n } {
       set slist [file split $s]
    @@ -6608,24 +6716,24 @@ proc viewdata {data {ro {}} {win .view}} {
       return $tctx::rcode
     }
     
    -proc sub_match_file { f {paths {}} } {
    -  global pathlist match_file_dir_arr
    +proc sub_match_file { f {paths {}} {maxdepth -1} } {
    +  global pathlist match_file_dir_arr match_file_level
       set res {}
       if {$paths eq {}} {set paths $pathlist}
       foreach i $paths {
         foreach j [glob -nocomplain -directory $i *] {
    -      # puts "--> $j  $f"
    -      # set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
           if {[file isdirectory $j] && [file readable $j]} {
    -        set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
    -        if {[array names match_file_dir_arr -exact $jj] == {}} {
    -          set match_file_dir_arr($jj) 1
    -          # puts "********** directory $jj"
    -          set sub_res [sub_match_file $f $j] ;# recursive call
    -          if {$sub_res != {} } {set res [concat $res $sub_res]}
    +        if { $maxdepth == -1 || $match_file_level < $maxdepth} {
    +          set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
    +          if {[array names match_file_dir_arr -exact $jj] == {}} {
    +            set match_file_dir_arr($jj) 1
    +            incr match_file_level
    +            set sub_res [sub_match_file $f $j $maxdepth] ;# recursive call
    +            incr match_file_level -1
    +            if {$sub_res != {} } {set res [concat $res $sub_res]}
    +          }
             }
           } else {
    -        # set fname [file tail $j]
             set fname $j
             if {[regexp $f $fname]} {
               lappend res $j
    @@ -6639,30 +6747,33 @@ proc sub_match_file { f {paths {}} } {
     # find files into $paths directories matching $f
     # use $pathlist global search path if $paths empty
     # recursively descend directories
    -proc match_file  { f {paths {}} } {
    -  global match_file_dir_arr
    +proc match_file  { f {paths {}} {maxdepth -1}  } {
    +  global match_file_dir_arr match_file_level
    +  set match_file_level 0
       catch {unset match_file_dir_arr}
    -  set res  [sub_match_file $f $paths]
    +  set res  [sub_match_file $f $paths $maxdepth]
       catch {unset match_file_dir_arr}
       return $res
     }
     
    -proc sub_find_file { f {paths {}} {first 0} } {
    -  global pathlist match_file_dir_arr
    +proc sub_find_file { f {paths {}} {first 0} {maxdepth -1}} {
    +  global pathlist match_file_dir_arr match_file_level
       set res {}
       if {$paths eq {}} {set paths $pathlist}
       foreach i $paths {
         foreach j [glob -nocomplain -directory $i *] {
    -      # puts "--> $j  $f"
           if {[file isdirectory $j]  && [file readable $j]} {
    -        set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
    -        if {[array names match_file_dir_arr -exact $jj] == {}} {
    -          set match_file_dir_arr($jj) 1
    -          # puts "********** directory $jj"
    -          set sub_res [sub_find_file $f $j $first] ;# recursive call
    -          if {$sub_res != {} } {
    -            set res [concat $res $sub_res]
    -            if {$first} {return $res}
    +        if { $maxdepth == -1 || $match_file_level < $maxdepth} {
    +          set jj [regsub {/ $} [file normalize ${j}/\ ] {}]
    +          if {[array names match_file_dir_arr -exact $jj] == {}} {
    +            set match_file_dir_arr($jj) 1
    +            incr match_file_level
    +            set sub_res [sub_find_file $f $j $first $maxdepth] ;# recursive call
    +            incr match_file_level -1
    +            if {$sub_res != {} } {
    +              set res [concat $res $sub_res]
    +              if {$first} {return $res}
    +            }
               }
             }
           } else {
    @@ -6680,10 +6791,11 @@ proc sub_find_file { f {paths {}} {first 0} } {
     # find given file $f into $paths directories 
     # use $pathlist global search path if $paths empty
     # recursively descend directories
    -proc find_file  { f {paths {}} } {
    -  global match_file_dir_arr
    +proc find_file { f {paths {}} {maxdepth -1}} {
    +  global match_file_dir_arr match_file_level
    +  set match_file_level 0
       catch {unset match_file_dir_arr}
    -  set res  [sub_find_file $f $paths 0]
    +  set res  [sub_find_file $f $paths 0 $maxdepth]
       catch {unset match_file_dir_arr}
       return $res
     }
    @@ -6692,10 +6804,11 @@ proc find_file  { f {paths {}} } {
     # use $pathlist global search path if $paths empty
     # recursively descend directories
     # only return FIRST FOUND
    -proc find_file_first  { f {paths {}} } {
    -  global match_file_dir_arr
    +proc find_file_first  { f {paths {}} {maxdepth -1}} {
    +  global match_file_dir_arr match_file_level
    +  set match_file_level 0
       catch {unset match_file_dir_arr}
    -  set res  [sub_find_file $f $paths 1] 
    +  set res  [sub_find_file $f $paths 1 $maxdepth] 
       catch {unset match_file_dir_arr}
       return $res
     }        
    
    From 0f5c554e334201b1a995858adb5dfe767f72d791 Mon Sep 17 00:00:00 2001
    From: stefan schippers 
    Date: Wed, 12 Mar 2025 02:00:45 +0100
    Subject: [PATCH 2/2] add command `xschem get ui_state`, improvements in proc
     insert_symbol
    
    ---
     doc/xschem_man/developer_info.html |   1 +
     src/scheduler.c                    |   6 ++
     src/xschem.tcl                     | 102 +++++++++++++++++++++--------
     3 files changed, 83 insertions(+), 26 deletions(-)
    
    diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html
    index 06d9e035..e5676ad7 100644
    --- a/doc/xschem_man/developer_info.html
    +++ b/doc/xschem_man/developer_info.html
    @@ -813,6 +813,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
          
  • textlayer layer number for texts
  • top_path get top hier path of current window (always "" for tabbed if)
  • topwindow same as top_path but main window returned as "."
  • +
  • ui_state return UI state
  • version return xschem version
  • wirelayer layer used for wires
  • wires number of wires
  • diff --git a/src/scheduler.c b/src/scheduler.c index c1e66f13..f25ead3d 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1725,6 +1725,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg Tcl_SetResult(interp, top_path,TCL_VOLATILE); } break; + case 'u': + if(!strcmp(argv[2], "ui_state")) { /* return UI state */ + if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;} + Tcl_SetResult(interp, my_itoa(xctx->ui_state), TCL_VOLATILE); + } + break; case 'v': if(!strcmp(argv[2], "version")) { /* return xschem version */ Tcl_SetResult(interp, XSCHEM_VERSION, TCL_VOLATILE); diff --git a/src/xschem.tcl b/src/xschem.tcl index ba2cbee2..10b4df34 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -4791,16 +4791,17 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}} #### Display preview of selected symbol proc insert_symbol_focusin {} { - puts insert_symbol_focusin + # puts insert_symbol_focusin set sel [.ins.center.left.l curselection] if {$sel eq {}} { set sel [.ins.center.left.l index active] .ins.center.left.l selection set active + insert_symbol_preview } } proc insert_symbol_preview {} { - puts insert_symbol_preview + # puts insert_symbol_preview global insert_symbol xschem preview_window close .ins.center.right {} .ins.center.right configure -bg white @@ -4816,35 +4817,48 @@ proc insert_symbol_preview {} { if {$f ne {}} { set type [is_xschem_file $f] if {$type ne {0}} { + .ins.top.dir_e configure -state normal + .ins.top.dir_e delete 0 end + .ins.top.dir_e insert 0 [file dirname [rel_sym_path $f]] + .ins.top.dir_e configure -state readonly .ins.center.right configure -bg {} xschem preview_window create .ins.center.right {} xschem preview_window draw .ins.center.right [list $f] bind .ins.center.right "xschem preview_window draw .ins.center.right [list $f]" bind .ins.center.right "xschem preview_window draw .ins.center.right [list $f]" } + insert_symbol_place } } } # new alternate insert_symbol browser #### fill list of files matching pattern -proc insert_symbol_filelist {paths {maxdepth 1}} { - puts insert_symbol_filelist +proc insert_symbol_filelist {paths {maxdepth -1}} { + # puts insert_symbol_filelist global insert_symbol set insert_symbol(regex) [.ins.top.pat_e get] + + #check if regex is valid + set err [catch {regexp $insert_symbol(regex) {12345}} res] + if {$err} {return} + set f [match_file $insert_symbol(regex) $paths $maxdepth] set insert_symbol(list) {} set insert_symbol(fullpathlist) {} .ins.center.left.l activate 0 foreach i $f { - set fname [rel_sym_path $i] - lappend insert_symbol(list) $fname - lappend insert_symbol(fullpathlist) $i + set type [regexp $insert_symbol(ext) $i] + if {$type} { + set fname [rel_sym_path $i] + lappend insert_symbol(list) $fname + lappend insert_symbol(fullpathlist) $i + } } } proc insert_symbol_place {} { - puts insert_symbol_place + # puts insert_symbol_place global insert_symbol set sel [.ins.center.left.l curselection] if {$sel eq {}} { @@ -4856,6 +4870,7 @@ proc insert_symbol_place {} { if {$f ne {}} { set type [is_xschem_file $f] if {$type ne {0}} { + xschem abort_operation xschem place_symbol $f } } @@ -4864,9 +4879,10 @@ proc insert_symbol_place {} { #### paths: list of paths to use for listing symbols #### maxdepth: how many levels to descend for each $paths directory (-1: no limit) -proc insert_symbol {{paths {}} {maxdepth 1}} { +proc insert_symbol {{paths {}} {maxdepth -1} {ext {.*}}} { global insert_symbol # xschem set semaphore [expr {[xschem get semaphore] +1}] + set insert_symbol(ext) $ext toplevel .ins frame .ins.top -takefocus 0 panedwindow .ins.center -orient horizontal -height 8c @@ -4888,26 +4904,34 @@ proc insert_symbol {{paths {}} {maxdepth 1}} { label .ins.top.pat_l -text Pattern: entry .ins.top.pat_e -width 20 -highlightcolor red -highlightthickness 2 \ -highlightbackground [option get . background {}] + label .ins.top.dir_l -text Dir: + entry .ins.top.dir_e -width 50 -takefocus 0 -state readonly if {[info exists insert_symbol(regex)]} { .ins.top.pat_e insert 0 $insert_symbol(regex) } + + bind .ins {.ins.bottom.dismiss invoke} bind .ins.top.pat_e " if {{%K} ne {Tab}} { insert_symbol_filelist [list $paths] [list $maxdepth] + } else { } " bind .ins.center.left.l <> { insert_symbol_preview } - bind .ins.center.left.l { insert_symbol_focusin } + bind .ins.center.left.l { insert_symbol_focusin } button .ins.bottom.dismiss -takefocus 0 -text Dismiss -command { - xschem preview_window close .ins.center.right {} - destroy .ins + if { [xschem get ui_state] & 8192 } { + xschem abort_operation + } else { + xschem preview_window close .ins.center.right {} + destroy .ins + } } - button .ins.bottom.insert -takefocus 0 -text Insert -command { - insert_symbol_place - } - pack .ins.bottom.insert .ins.bottom.dismiss -side left + pack .ins.bottom.dismiss -side left pack .ins.top.pat_l -side left pack .ins.top.pat_e -side left + pack .ins.top.dir_l -side left + pack .ins.top.dir_e -side left insert_symbol_filelist $paths $maxdepth # tkwait window .ins # xschem set semaphore [expr {[xschem get semaphore] -1}] @@ -6717,15 +6741,25 @@ proc viewdata {data {ro {}} {win .view}} { } proc sub_match_file { f {paths {}} {maxdepth -1} } { - global pathlist match_file_dir_arr match_file_level + global pathlist match_file_dir_arr match_file_level nolist_libs set res {} if {$paths eq {}} {set paths $pathlist} foreach i $paths { foreach j [glob -nocomplain -directory $i *] { + set skip 0 + foreach k $nolist_libs { + if {[regexp $k $j]} { + set skip 1 + break + } + } + if {$skip} { continue } + if {[file isdirectory $j] && [file readable $j]} { if { $maxdepth == -1 || $match_file_level < $maxdepth} { set jj [regsub {/ $} [file normalize ${j}/\ ] {}] - if {[array names match_file_dir_arr -exact $jj] == {}} { + # if {[array names match_file_dir_arr -exact $jj] == {}} { ... } + if {![info exists match_file_dir_arr($jj)]} { set match_file_dir_arr($jj) 1 incr match_file_level set sub_res [sub_match_file $f $j $maxdepth] ;# recursive call @@ -6734,9 +6768,11 @@ proc sub_match_file { f {paths {}} {maxdepth -1} } { } } } else { - set fname $j - if {[regexp $f $fname]} { - lappend res $j + if {![info exists match_file_dir_arr($j)]} { + set match_file_dir_arr($j) 1 + if {[regexp $f $j]} { + lappend res $j + } } } } @@ -6757,15 +6793,26 @@ proc match_file { f {paths {}} {maxdepth -1} } { } proc sub_find_file { f {paths {}} {first 0} {maxdepth -1}} { - global pathlist match_file_dir_arr match_file_level + global pathlist match_file_dir_arr match_file_level nolist_libs set res {} if {$paths eq {}} {set paths $pathlist} foreach i $paths { foreach j [glob -nocomplain -directory $i *] { + + set skip 0 + foreach k $nolist_libs { + if {[regexp $k $j]} { + set skip 1 + break + } + } + if {$skip} { continue } + if {[file isdirectory $j] && [file readable $j]} { if { $maxdepth == -1 || $match_file_level < $maxdepth} { set jj [regsub {/ $} [file normalize ${j}/\ ] {}] - if {[array names match_file_dir_arr -exact $jj] == {}} { + # if {[array names match_file_dir_arr -exact $jj] == {}} { ... } + if {![info exists match_file_dir_arr($jj)]} { set match_file_dir_arr($jj) 1 incr match_file_level set sub_res [sub_find_file $f $j $first $maxdepth] ;# recursive call @@ -6778,9 +6825,12 @@ proc sub_find_file { f {paths {}} {first 0} {maxdepth -1}} { } } else { set fname [file tail $j] - if {$fname == $f} { - lappend res $j - if {$first} {return $res} + if {![info exists match_file_dir_arr($j)]} { + set match_file_dir_arr($j) 1 + if {$fname == $f} { + lappend res $j + if {$first} {return $res} + } } } }