diff --git a/src/callback.c b/src/callback.c index 7db702b7..03323132 100644 --- a/src/callback.c +++ b/src/callback.c @@ -2932,8 +2932,8 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m descend_symbol(); } else if(rstate == ControlMask) { /* insert sym */ - if(tclgetboolvar("new_symbol_browser")) { - tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + if(tclgetboolvar("new_file_browser")) { + tcleval("file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext"); } else { tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); } @@ -2949,8 +2949,8 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m case 'I': if(rstate == 0) { /* insert sym */ if(xctx->semaphore >= 2) break; - if(tclgetboolvar("new_symbol_browser")) { - tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + if(tclgetboolvar("new_file_browser")) { + tcleval("file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext"); } else { start_place_symbol(); } @@ -3208,7 +3208,7 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m if(xctx->semaphore >= 2) break; if(tclgetboolvar("new_file_browser")) { tcleval( - "insert_symbol $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext load" + "file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext" ); } else { xctx->semaphore--; @@ -3955,16 +3955,16 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m case XK_Insert: if(state == ShiftMask) { /* insert sym */ - if(tclgetboolvar("new_symbol_browser")) { - tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + if(tclgetboolvar("new_file_browser")) { + tcleval("file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext"); } else { tcleval("load_file_dialog {Insert symbol} *.\\{sym,tcl\\} INITIALINSTDIR 2"); } } else { if(xctx->semaphore >= 2) break; - if(tclgetboolvar("new_symbol_browser")) { - tcleval("insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext"); + if(tclgetboolvar("new_file_browser")) { + tcleval("file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext"); } else { start_place_symbol(); } @@ -4608,7 +4608,7 @@ static int handle_window_switching(int event, int tabbed_interface, const char * redraw_only = 1; my_strncpy(old_win_path, xctx->current_win_path, S(old_win_path)); new_schematic("switch_no_tcl_ctx", win_path, "", 1); - /* This does a "temporary" switch just to redraw obcured window parts */ + /* This does a "temporary" switch just to redraw obscured window parts */ } else if(event == Expose || xctx->semaphore >= 1 ) { dbg(1, "callback(): switching window context for redraw ONLY: %s --> %s\n", xctx->current_win_path, win_path); diff --git a/src/scheduler.c b/src/scheduler.c index da89a3f5..ccfcd79d 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -3040,7 +3040,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg if(argc==first && !(lastclosed || lastopened)) { if(tclgetboolvar("new_file_browser")) { tcleval( - "insert_symbol $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext load" + "file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext" ); } else { ask_new_file(0, NULL); diff --git a/src/xschem.tcl b/src/xschem.tcl index 7128c567..aac9c134 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -1552,6 +1552,39 @@ proc tolist {s} { } } +# where: +# begin: remove $needle if it is at the beginning of $haystack +# end : remove $needle if it is at the end of $haystack +# any : remove first found $needle anywhere inside $haystack +proc substring_remove {needle haystack {where {begin}}} { + if {$where eq {begin}} { + set needle_length [string length $needle] + if {[string compare -length $needle_length $needle $haystack] == 0} { + return [string range $haystack $needle_length end] + } + return $haystack + } elseif {$where eq {end}} { + set needle_length [string length $needle] + set pos [expr {[string length $haystack] -$needle_length}] + set haystack_end [string range $haystack $pos end] + if {[string compare $needle $haystack_end] == 0} { + incr pos -1 + return [string range $haystack 0 $pos] + } + return $haystack + } elseif {$where eq {any}} { + set needle_length [string length $needle] + set pos [string first $needle $haystack] + if {$pos >= 0} { + set before [expr {$pos - 1}] + set after [expr {$pos + $needle_length}] + return [string range $haystack 0 $before][string range $haystack $after end] + } + return $haystack + } +} + + # Initialize the tcl sim array variable (if not already set) # setting up simulator / wave viewer commands proc set_sim_defaults {{reset {}}} { @@ -4934,7 +4967,7 @@ proc get_list_of_dirs_with_files {{paths {}} {levels -1} {ext {\.(sch|sym)$}} global pathlist set dir_with_symbols {} if {$level == -1} { set level 0} - if {$levels >=0 && $level + 1 > $levels} {return {}} + if {$levels >=0 && $level > $levels} {return {}} if {$paths eq {}} {set paths $pathlist} foreach i $paths { set filelist [glob -nocomplain -directory $i -type f *] @@ -4949,7 +4982,7 @@ proc get_list_of_dirs_with_files {{paths {}} {levels -1} {ext {\.(sch|sym)$}} if {$there_are_symbols} { lappend dir_with_symbols $i } - set dirlist [glob -nocomplain -directory $i -type d *] + set dirlist [lsort -dictionary [glob -nocomplain -directory $i -type d *]] if {$level < $levels} { foreach d $dirlist { set dirs [get_list_of_dirs_with_files $d $levels $ext [expr {$level + 1} ]] @@ -4967,32 +5000,36 @@ proc get_list_of_dirs_with_files {{paths {}} {levels -1} {ext {\.(sch|sym)$}} } ####################################################################### -##### new alternate insert_symbol browser +##### new alternate file_chooser browser ####################################################################### #### Display preview of selected symbol and start sym placement -proc insert_symbol_draw_preview {f} { - global insert_symbol - # puts "insert_symbol_draw_preview" +proc file_chooser_draw_preview {f} { + global file_chooser + # puts "file_chooser_draw_preview" if {[winfo exists .ins]} { .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]" - if {$insert_symbol(action) eq {symbol}} { - insert_symbol_place symbol + xschem preview_window draw .ins.center.right "$f" + bind .ins.center.right "xschem preview_window draw .ins.center.right {$f}" + bind .ins.center.right "xschem preview_window draw .ins.center.right {$f}" + if {$file_chooser(action) eq {symbol}} { + file_chooser_place symbol + } + if {$file_chooser(action) eq {symbol1}} { + set file_chooser(action) {load} + file_chooser_place symbol } } } -proc insert_symbol_select_preview {} { - # puts "insert_symbol_select_preview" - global insert_symbol - if {[info exists insert_symbol(f)]} { +proc file_chooser_select_preview {} { + # puts "file_chooser_select_preview" + global file_chooser + if {[info exists file_chooser(f)]} { after cancel ".ins.center.right configure -bg white" - after cancel "insert_symbol_draw_preview $insert_symbol(f)" - unset insert_symbol(f) + after cancel "file_chooser_draw_preview {$file_chooser(f)}" + unset file_chooser(f) } xschem preview_window close .ins.center.right {} bind .ins.center.right {} @@ -5002,13 +5039,14 @@ proc insert_symbol_select_preview {} { set sel [.ins.center.left.l index active] .ins.center.left.l selection set active } - if {$sel ne {} && [info exists insert_symbol(fullpathlist)]} { - set insert_symbol(fileindex) $sel + if {$sel ne {} && [info exists file_chooser(fullpathlist)]} { + set file_chooser(fileindex) $sel # puts "set fileindex=$sel" .ins.center.left.l see $sel - set f [lindex $insert_symbol(fullpathlist) $sel] + set f [lindex $file_chooser(fullpathlist) $sel] + # puts "file_chooser_select_preview: f=$f" if {$f ne {}} { - set insert_symbol(f) $f + set file_chooser(f) $f set type [is_xschem_file $f] if {$type ne {0}} { set dir [rel_sym_path $f] @@ -5022,7 +5060,7 @@ proc insert_symbol_select_preview {} { .ins.top2.dir_e insert 0 $f .ins.top2.dir_e configure -state readonly # global used to cancel delayed script - after 200 "insert_symbol_draw_preview $f" + after 200 "file_chooser_draw_preview {$f}" } else { after 200 {.ins.center.right configure -bg white} } @@ -5030,104 +5068,105 @@ proc insert_symbol_select_preview {} { } } -proc insert_symbol_dirlist {} { - # puts insert_symbol_dirlist - global insert_symbol +proc file_chooser_dirlist {} { + # puts file_chooser_dirlist + global file_chooser pathlist dark_gui_colorscheme + if {$dark_gui_colorscheme} { set col {cyan} } else { set col {blue} } # regenerate list of dirs - set insert_symbol(dirs) [ - get_list_of_dirs_with_files $insert_symbol(paths) $insert_symbol(maxdepth) $insert_symbol(ext) + set file_chooser(dirs) [ + get_list_of_dirs_with_files $file_chooser(paths) $file_chooser(maxdepth) $file_chooser(ext) ] - set insert_symbol(dirtails) {} - foreach i $insert_symbol(dirs) { - lappend insert_symbol(dirtails) [file tail $i] - } - ## sort dirs using dirtails as key - #set files {} - #foreach f $insert_symbol(dirtails) ff $insert_symbol(dirs) { - # lappend files [list $f $ff] - #} - #set files [lsort -dictionary -index 0 $files] - #set insert_symbol(dirtails) {} - #set insert_symbol(dirs) {} - # - #foreach f $files { - # lassign $f ff fff - # lappend insert_symbol(dirtails) $ff - # lappend insert_symbol(dirs) $fff - #} + set file_chooser(dirtails) {} + set path_l $file_chooser(paths) + if {$path_l eq {}} { set path_l $pathlist} + foreach i $file_chooser(dirs) { + set found 0 + foreach p $path_l { + ## p = /home/schippes/.xschem/xschem_library + ## i = /home/schippes/.xschem/xschem_library/matias_ota_5t + ## --> t = xschem_library/matias_ota_5t + if {[string first $p $i] == 0} { + set pp [file dirname $p]/ + set t [substring_remove $pp $i begin] + # puts "$p\n $pp\n $i\n $t" + if {$t ne $i} { + lappend file_chooser(dirtails) $t + set found 1 + break + } + } + } + if {$found == 0} {lappend file_chooser(dirtails) [file tail $i]} + } + set i 0 + foreach p $file_chooser(dirs) { + # puts "--> $p" + if {[lsearch -exact $path_l $p] != -1} { + .ins.center.leftdir.l itemconfigure $i -foreground $col -selectforeground $col + } + incr i + } } #### fill list of files matching pattern -proc insert_symbol_filelist {} { - global insert_symbol +proc file_chooser_filelist {} { + global file_chooser set sel [.ins.center.leftdir.l curselection] - if {![info exists insert_symbol(dirs)]} {return} + if {![info exists file_chooser(dirs)]} {return} if {$sel eq {}} { set sel [.ins.center.leftdir.l index active] .ins.center.leftdir.l selection set active } - set insert_symbol(dirindex) $sel - set path [lindex $insert_symbol(dirs) $sel] + set file_chooser(dirindex) $sel + set path [lindex $file_chooser(dirs) $sel] .ins.top2.dir_e configure -state normal .ins.top2.dir_e delete 0 end .ins.top2.dir_e insert 0 $path .ins.top2.dir_e configure -state readonly # check if regex is valid - set err [catch {regexp $insert_symbol(regex) {12345}} res] + set err [catch {regexp $file_chooser(regex) {12345}} res] if {$err} {return} set f {} if {$path ne {} } { - set f [match_file $insert_symbol(regex) $path 0] + set f [match_file $file_chooser(regex) [list $path] 0 $file_chooser(fullpath)] } set filelist {} - set insert_symbol(fullpathlist) {} + set file_chooser(fullpathlist) {} set sel [.ins.center.left.l curselection] if {$sel ne {}} { - set insert_symbol(fileindex) $sel + set file_chooser(fileindex) $sel # puts "set fileindex=$sel" } if {$sel eq {}} { set sel 0} .ins.center.left.l activate $sel foreach i $f { - set err [catch {regexp $insert_symbol(ext) $i} type] + set err [catch {regexp $file_chooser(ext) $i} type] if {!$err && $type} { set fname [file tail $i] lappend filelist $fname - lappend insert_symbol(fullpathlist) $i + lappend file_chooser(fullpathlist) $i } } - # sort lists using filelist as key - set files {} - foreach f $filelist ff $insert_symbol(fullpathlist) { - lappend files [list $f $ff] - } - set files [lsort -dictionary -index 0 $files] - set filelist {} - set insert_symbol(fullpathlist) {} - foreach f $files { - lassign $f ff fff - lappend filelist $ff - lappend insert_symbol(fullpathlist) $fff - } - set insert_symbol(nitems) [llength $filelist] + set file_chooser(nitems) [llength $filelist] # assign listbox variable all at the end, it is faster... - set insert_symbol(files) $filelist + set file_chooser(files) $filelist } -proc insert_symbol_place {action} { - # puts insert_symbol_place - global insert_symbol open_in_new_window +proc file_chooser_place {action} { + # puts file_chooser_place + global file_chooser open_in_new_window 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] + set f [lindex $file_chooser(fullpathlist) $sel] if {$f ne {}} { set type [is_xschem_file $f] + # puts "file_chooser_place: file=$f, type=$type" if {$type ne {0}} { if { [xschem get ui_state] & 8192 } { xschem abort_operation @@ -5140,32 +5179,163 @@ proc insert_symbol_place {action} { } else { xschem load -gui $f } + } elseif {$action eq {load_new_win}} { + xschem load_new_window $f } } } } } +proc file_chooser_search {} { + global file_chooser + # check if regex is valid + set err [catch {regexp $file_chooser(regex) {12345}} res] + if {$err} {return} + set nth 0 + set f {} + if {$file_chooser(dirs) ne {} } { + set allfiles [ + match_file $file_chooser(regex) $file_chooser(paths) $file_chooser(maxdepth) $file_chooser(fullpath) + ] + foreach i $allfiles { + set err [catch {regexp $file_chooser(ext) $i} type] + if {!$err && $type} { + incr nth + if {$nth == $file_chooser(nth)} { + set f $i + break + } + } + } + } + if {$f ne {}} { + set dir [file dirname $f] + set file [file tail $f] + set dirtail [file tail $dir] + # puts "file=$file" + # puts " dirtail=$dirtail" + # puts " dir=$dir" + set dirindex [lsearch -exact $file_chooser(dirs) $dir] + if {$dirindex != -1} { + # puts "dirindex=$dirindex" + .ins.center.leftdir.l selection clear 0 end + .ins.center.leftdir.l selection set $dirindex + .ins.center.leftdir.l see $dirindex + file_chooser_filelist + set fileindex [lsearch -exact $file_chooser(files) $file] + if {$fileindex != -1} { + # puts "fileindex=$fileindex" + .ins.center.left.l selection clear 0 end + .ins.center.left.l selection set $fileindex + .ins.center.left.l see $fileindex + file_chooser_select_preview + } + } + } else { + if {$file_chooser(nth) > 0} { + incr file_chooser(nth) -1 + } else { + set file_chooser(nth) 1 + } + } +} +proc file_chooser_browsedir {} { + set pos [.editpaths.center.paths index insert] + set row [regsub {\..*} $pos {}] + set initialdir [.editpaths.center.paths get ${row}.0 "${row}.0 + 1 lines - 1 chars"] + # puts $initialdir + if {$row > 1} { + incr row -1 + } + # puts $row + + set dir [tk_chooseDirectory -initialdir $initialdir -parent .editpaths \ + -title {Directory to add to search paths}] + # puts $dir + + if {$dir ne {}} { + .editpaths.center.paths insert ${row}.0 ${dir}\n + } +} + +proc file_chooser_edit_paths {} { + global pathlist XSCHEM_LIBRARY_PATH dark_gui_colorscheme + if {$dark_gui_colorscheme} { set col {cyan} } else { set col {blue} } + set tctx::rcode 0 + toplevel .editpaths + frame .editpaths.top + frame .editpaths.top2 + frame .editpaths.center + frame .editpaths.bottom + + pack .editpaths.top -side top -fill x + pack .editpaths.top2 -side top -fill x + pack .editpaths.center -side top -expand 1 -fill both + pack .editpaths.bottom -side top -fill x + text .editpaths.center.paths -height 30 -width 80 -foreground $col + pack .editpaths.center.paths + + button .editpaths.bottom.ok -text OK -command { + set tctx::rcode 1 + set tctx::retval [.editpaths.center.paths get 1.0 {end - 1 chars}] + destroy .editpaths + } + button .editpaths.bottom.dismiss -text Dismiss -command { + destroy .editpaths + } + button .editpaths.bottom.browse -text {Browse directory} -command { + file_chooser_browsedir + } + + wm protocol .editpaths WM_DELETE_WINDOW {.editpaths.bottom.dismiss invoke} + bind .editpaths {.editpaths.bottom.dismiss invoke} + pack .editpaths.bottom.ok .editpaths.bottom.dismiss .editpaths.bottom.browse -side left + + set paths $XSCHEM_LIBRARY_PATH + regsub {^[ :]+} $paths {} paths ;# remove leading : if present + regsub {[ :]+$} $paths {} paths ;# remove trailing : if present + regsub -all {:} $paths \n paths + .editpaths.center.paths delete 1.0 end + .editpaths.center.paths insert 1.0 $paths + tkwait window .editpaths + if {$tctx::rcode == 1} { + set paths $tctx::retval + regsub -all -line {^[ \t]*\n} $paths {} paths ;# remove blank lines + regsub -all \n $paths : paths + set XSCHEM_LIBRARY_PATH $paths + } +} + #### maxdepth: how many levels to descend for each $paths directory (-1: no limit) -proc insert_symbol {{paths {}} {maxdepth -1} {ext {.*}} {action {symbol}}} { - global insert_symbol - set insert_symbol(action) $action - - set insert_symbol(maxdepth) $maxdepth - set insert_symbol(paths) [cleanup_paths $paths] ;# remove ~ and other strange path combinations +proc file_chooser {{paths {}} {maxdepth -1} {ext {.*}} } { + global file_chooser + set file_chooser(action) load + set_ne file_chooser(fullpath) 0 + set_ne file_chooser(ontop) 1 + set file_chooser(maxdepth) $maxdepth + set file_chooser(paths) [cleanup_paths $paths] ;# remove ~ and other strange path combinations # xschem set semaphore [expr {[xschem get semaphore] +1}] - set insert_symbol(ext) $ext + set file_chooser(ext) $ext if {[winfo exists .ins]} { raise .ins return } - if {![info exists insert_symbol(regex)]} { set insert_symbol(regex) {}} + set_ne file_chooser(regex) {} + set_ne file_chooser(nth) 1 toplevel .ins + wm title .ins "File Browser" + if {$file_chooser(ontop)} { + wm transient .ins [xschem get topwindow] + } else { + wm transient .ins {} + } frame .ins.top -takefocus 0 + frame .ins.top3 -takefocus 0 frame .ins.top2 -takefocus 0 panedwindow .ins.center -orient horizontal - frame .ins.center.leftdir -takefocus 0 -height 40 - frame .ins.center.left -takefocus 0 -height 40 + frame .ins.center.leftdir -takefocus 0 + frame .ins.center.left -takefocus 0 frame .ins.center.right -width 50 -height 40 -bg white -takefocus 0 .ins.center add .ins.center.leftdir .ins.center add .ins.center.left @@ -5173,15 +5343,26 @@ proc insert_symbol {{paths {}} {maxdepth -1} {ext {.*}} {action {symbol}}} { frame .ins.bottom -takefocus 0 pack .ins.top -side top -fill x pack .ins.top2 -side top -fill x + pack .ins.top3 -side top -fill x pack .ins.center -side top -expand 1 -fill both pack .ins.bottom -side top -fill x - listbox .ins.center.leftdir.l -listvariable insert_symbol(dirtails) -width 20 -height 4 \ + listbox .ins.center.leftdir.l -listvariable file_chooser(dirtails) -width 40 -height 15 \ -yscrollcommand ".ins.center.leftdir.s set" -highlightcolor red -highlightthickness 2 \ -activestyle underline -highlightbackground [option get . background {}] \ -exportselection 0 - listbox .ins.center.left.l -listvariable insert_symbol(files) -width 20 -height 4 \ + balloon .ins.center.leftdir.l [string cat \ + "The list of search paths is shown here\n" \ + "The directories provided in the\n" \ + "XSCHEM_LIBRARY_PATH are shown with a\n" \ + "different background.\n" \ + "Subdirectories as deep as specified in the\n" \ + "\"Levels down\" entry are shown after the\n" \ + "primary directory.\n" \ + "Only directories containing xschem files\n" \ + "matching the \"Ext\" pattern are shown."] 0 1 + listbox .ins.center.left.l -listvariable file_chooser(files) -width 20 -height 15 \ -yscrollcommand ".ins.center.left.s set" -highlightcolor red -highlightthickness 2 \ -activestyle underline -highlightbackground [option get . background {}] \ -exportselection 0 @@ -5198,36 +5379,93 @@ proc insert_symbol {{paths {}} {maxdepth -1} {ext {.*}} {action {symbol}}} { label .ins.top2.dir_l -text {Full path:} entry .ins.top2.dir_e -width 20 -state readonly \ -readonlybackground [option get . background {}] -takefocus 0 - label .ins.top.pat_l -text Pattern: - entry .ins.top.pat_e -width 15 -highlightcolor red -highlightthickness 2 \ - -textvariable insert_symbol(regex) -highlightbackground [option get . background {}] - label .ins.top.dir_l -text { Sch/Sym ref: } - entry .ins.top.dir_e -width 20 -state readonly \ + label .ins.top3.pat_l -text Pattern: + balloon .ins.top3.pat_l {Show files matching regular expression} + entry .ins.top3.pat_e -width 15 -highlightcolor red -highlightthickness 2 \ + -textvariable file_chooser(regex) -highlightbackground [option get . background {}] + balloon .ins.top3.pat_e {Show files matching regular expression} + label .ins.top.dir_l -text { Symbol Reference in schematic: } + balloon .ins.top.dir_l "This is the relative path of the symbol\nwhen instantiated in the schematic" + entry .ins.top.dir_e -width 25 -state readonly -relief flat \ -readonlybackground [option get . background {}] -takefocus 0 - label .ins.top.ext_l -text Ext: - entry .ins.top.ext_e -width 15 -takefocus 0 -state normal -textvariable insert_symbol(ext) - button .ins.top.upd -takefocus 0 -text Update -command { - insert_symbol_dirlist - insert_symbol_filelist + balloon .ins.top.dir_e "This is the relative path of the symbol\nwhen instantiated in the schematic" + button .ins.top.editpaths -takefocus 0 -text {Edit library paths} -command { + file_chooser_edit_paths + file_chooser_dirlist + file_chooser_filelist } - bind .ins {.ins.bottom.dismiss invoke} - bind .ins " - if {{%K} eq {Tab} && {%W} eq {.ins.center.left.l}} { - insert_symbol_filelist - insert_symbol_select_preview - } elseif {{%K} eq {Tab} && {%W} eq {.ins.center.leftdir.l}} { - insert_symbol_filelist + balloon .ins.top.editpaths [string cat \ + "allows to edit XSCHEM_LIBRARY_PATH.\n" \ + "A hash before a line will comment out the path\n" \ + "so it will not be used. You can enable it\n" \ + "later by removing the hash comment character"] + checkbutton .ins.top.ontop -takefocus 0 -text {Ontop } -variable file_chooser(ontop) \ + -command { + if { $file_chooser(ontop) } { + wm transient .ins [xschem get topwindow] + } else { + wm transient .ins {} + } } - " - bind .ins.center.leftdir.l <> "insert_symbol_filelist" + balloon .ins.top.ontop "Make the file browser window always\nshow above current xschem window" + label .ins.top.lev_l -text {Levels down:} + entry .ins.top.lev_e -width 3 -takefocus 0 -textvariable file_chooser(maxdepth) + label .ins.top3.ext_l -text Ext: + balloon .ins.top3.ext_l "show only files matching the\nextension regular expression" + entry .ins.top3.ext_e -width 15 -takefocus 0 -state normal -textvariable file_chooser(ext) + balloon .ins.top3.ext_e "show only files matching the\nextension regular expression" + button .ins.top3.upd -takefocus 0 -text Update -command { + file_chooser_dirlist + file_chooser_filelist + } + balloon .ins.top3.upd {Update list of files matching pattern} + button .ins.top3.search -takefocus 0 -text {Search first} -activebackground red -command { + set file_chooser(nth) 1 + file_chooser_search + } + balloon .ins.top3.search {show and select first match} + button .ins.top3.prev -takefocus 0 -text Prev -command { + incr file_chooser(nth) -1 + file_chooser_search + } + balloon .ins.top3.prev {show and select previous match} + button .ins.top3.next -takefocus 0 -text Next -command { + incr file_chooser(nth) + file_chooser_search + } + balloon .ins.top3.next {show and select next match} + checkbutton .ins.top3.fullpath -takefocus 0 -variable file_chooser(fullpath) -text {match full path } + balloon .ins.top3.fullpath "perform regular expression matching on\nfull path instead of only file name" + button .ins.top3.clear -takefocus 0 -text Clear -command { + .ins.top3.pat_e delete 0 end + file_chooser_filelist + file_chooser_select_preview + } + balloon .ins.top3.clear {Clear pattern entry box} + # -command { + # file_chooser_search + # file_chooser_filelist + # file_chooser_select_preview + # } + bind .ins {.ins.bottom.dismiss invoke} + + # bind .ins.top3.pat_e { + # file_chooser_search + # file_chooser_filelist + # file_chooser_select_preview + # } + bind .ins.center.leftdir.l <> { + file_chooser_filelist + file_chooser_select_preview + } bind .ins.center.left.l <> { if { [xschem get ui_state] & 8192 } { xschem abort_operation } - insert_symbol_select_preview + file_chooser_select_preview } bind .ins.center.left.l { - if {$insert_symbol(action) eq {load}} { + if {$file_chooser(action) eq {load}} { .ins.bottom.load invoke } xschem preview_window close .ins.center.right {} @@ -5238,69 +5476,101 @@ proc insert_symbol {{paths {}} {maxdepth -1} {ext {.*}} {action {symbol}}} { # xschem abort_operation # } " + bind .ins.top.lev_e { + file_chooser_dirlist + file_chooser_filelist + } label .ins.bottom.n -text { N. of items:} - label .ins.bottom.nitems -textvariable insert_symbol(nitems) + label .ins.bottom.nitems -textvariable file_chooser(nitems) button .ins.bottom.dismiss -takefocus 0 -text Dismiss -command { - if { [xschem get ui_state] & 8192 } { - xschem abort_operation - } else { - xschem preview_window close .ins.center.right {} - destroy .ins + if {![winfo exists .editpaths]} { + if { [xschem get ui_state] & 8192 } { + xschem abort_operation + } else { + xschem preview_window close .ins.center.right {} ;# check if regex is valid + destroy .ins + } } } - button .ins.bottom.load -takefocus 0 -text {Load file} -command { - insert_symbol_place load + button .ins.bottom.load -takefocus 0 -text {Load file in active Window / Tab} -command { + file_chooser_place load + } + + button .ins.bottom.load_new_win -takefocus 0 -text {Load in new Window / Tab} -command { + file_chooser_place load_new_win } - checkbutton .ins.bottom.sym -text {Place symbol} -onvalue symbol -offvalue load -takefocus 0 \ - -variable insert_symbol(action) \ + button .ins.bottom.sym -text {Place symbol} -takefocus 0 \ -command { - if {$insert_symbol(action) eq {symbol}} { - insert_symbol_select_preview + set file_chooser(action) {symbol1} ;# only one time insert symbol + file_chooser_select_preview + } + balloon .ins.bottom.sym {insert the currently selected symbol} + + checkbutton .ins.bottom.stickysym -text {Place symbol} -onvalue symbol -offvalue load -takefocus 0 \ + -variable file_chooser(action) \ + -command { + if {$file_chooser(action) eq {symbol}} { ;# persistent insert symbol + file_chooser_select_preview } } + balloon .ins.bottom.stickysym {persistent insert symbol mode} + + wm protocol .ins WM_DELETE_WINDOW {.ins.bottom.dismiss invoke} + bind .ins {.ins.bottom.dismiss invoke} pack .ins.bottom.dismiss -side left pack .ins.bottom.load -side left + pack .ins.bottom.load_new_win -side left pack .ins.bottom.sym -side left + pack .ins.bottom.stickysym -side left pack .ins.bottom.n -side left pack .ins.bottom.nitems -side left pack .ins.top2.dir_l -side left pack .ins.top2.dir_e -side left -fill x -expand 1 - pack .ins.top.pat_l -side left - pack .ins.top.pat_e -side left + pack .ins.top3.upd -side left + pack .ins.top3.pat_l -side left + pack .ins.top3.pat_e -side left + pack .ins.top3.clear -side left + pack .ins.top3.search -side left + pack .ins.top3.prev -side left + pack .ins.top3.next -side left + pack .ins.top3.fullpath -side left pack .ins.top.dir_l -side left pack .ins.top.dir_e -side left -fill x -expand 1 - pack .ins.top.upd -side left - pack .ins.top.ext_l -side left - pack .ins.top.ext_e -side left - if { [info exists insert_symbol(geometry)]} { - wm geometry .ins "${insert_symbol(geometry)}" + pack .ins.top.ontop -side left + pack .ins.top.lev_l -side left + pack .ins.top.lev_e -side left + pack .ins.top.editpaths -side left + pack .ins.top3.ext_l -side left + pack .ins.top3.ext_e -side left + if { [info exists file_chooser(geometry)]} { + wm geometry .ins "${file_chooser(geometry)}" } else { - wm geometry .ins 800x300 + # wm geometry .ins 800x300 } update - if { [info exists insert_symbol(sp0)]} { - .ins.center sash place 0 $insert_symbol(sp0) 1 + if { [info exists file_chooser(sp0)]} { + .ins.center sash place 0 $file_chooser(sp0) 1 } - if { [info exists insert_symbol(sp1)]} { - .ins.center sash place 1 $insert_symbol(sp1) 1 + if { [info exists file_chooser(sp1)]} { + .ins.center sash place 1 $file_chooser(sp1) 1 } bind .ins { - set insert_symbol(geometry) [wm geometry .ins] - set insert_symbol(sp0) [lindex [.ins.center sash coord 0] 0] - set insert_symbol(sp1) [lindex [.ins.center sash coord 1] 0] + set file_chooser(geometry) [wm geometry .ins] + set file_chooser(sp0) [lindex [.ins.center sash coord 0] 0] + set file_chooser(sp1) [lindex [.ins.center sash coord 1] 0] } - insert_symbol_dirlist - if {[info exists insert_symbol(dirindex)]} {.ins.center.leftdir.l selection set $insert_symbol(dirindex)} - if {[info exists insert_symbol(fileindex)]} { - .ins.center.left.l selection set $insert_symbol(fileindex) - .ins.center.left.l see $insert_symbol(fileindex) + file_chooser_dirlist + if {[info exists file_chooser(dirindex)]} {.ins.center.leftdir.l selection set $file_chooser(dirindex)} + if {[info exists file_chooser(fileindex)]} { + .ins.center.left.l selection set $file_chooser(fileindex) + .ins.center.left.l see $file_chooser(fileindex) } - insert_symbol_filelist + file_chooser_filelist return {} } ####################################################################### -##### /new alternate insert_symbol browser +##### /new alternate file_chooser browser ####################################################################### # get last n path components: example , n=1 --> /aaa/bbb/ccc/ddd.sch -> ccc/ddd.sch @@ -7246,12 +7516,16 @@ proc viewdata {data {ro {}} {win .view}} { return $tctx::rcode } -proc sub_match_file { f {paths {}} {maxdepth -1} } { +proc sub_match_file { f {paths {}} {maxdepth -1} {first 0} {fullpath 1}} { global pathlist match_file_dir_arr match_file_level nolist_libs set res {} + if {$maxdepth eq {}} {set maxdepth 0} if {$paths eq {}} {set paths $pathlist} foreach i $paths { - foreach j [glob -nocomplain -directory $i *] { + foreach j [concat \ + [lsort -dictionary [glob -nocomplain -type f -directory $i *]] \ + [lsort -dictionary [glob -nocomplain -type d -directory $i *]] \ + ] { set skip 0 foreach k $nolist_libs { if {[regexp $k $j]} { @@ -7268,16 +7542,21 @@ proc sub_match_file { f {paths {}} {maxdepth -1} } { 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 + set sub_res [sub_match_file $f $j $maxdepth $first $fullpath] ;# recursive call incr match_file_level -1 - if {$sub_res != {} } {set res [concat $res $sub_res]} + if {$sub_res != {} } { + set res [concat $res $sub_res] + if {$first} {return $res} + } } } } else { if {![info exists match_file_dir_arr($j)]} { set match_file_dir_arr($j) 1 - if {[regexp $f $j]} { + if {$fullpath} { set file $j } else { set file [file tail $j]} + if {[regexp $f $file]} { lappend res $j + if {$first} {return $res} } } } @@ -7289,18 +7568,35 @@ proc sub_match_file { f {paths {}} {maxdepth -1} } { # find files into $paths directories matching $f # use $pathlist global search path if $paths empty # recursively descend directories -proc match_file { f {paths {}} {maxdepth -1} } { +proc match_file { f {paths {}} {maxdepth -1} {fullpath 1} } { global match_file_dir_arr match_file_level set err [catch {regexp $f {12345}} res] if {$err} {return {}} set match_file_level 0 catch {unset match_file_dir_arr} - set res [sub_match_file $f $paths $maxdepth] + set res [sub_match_file $f $paths $maxdepth 0 $fullpath] + catch {unset match_file_dir_arr} + # return [join $res \n] + return $res +} + +# find files into $paths directories matching $f +# use $pathlist global search path if $paths empty +# recursively descend directories +# only return FIRST FOUND +proc match_file_first { f {paths {}} {maxdepth -1} {fullpath 1} } { + global match_file_dir_arr match_file_level + set err [catch {regexp $f {12345}} res] + if {$err} {return {}} + set match_file_level 0 + catch {unset match_file_dir_arr} + set res [sub_match_file $f $paths $maxdepth 1 $fullpath] catch {unset match_file_dir_arr} return $res } -proc sub_find_file { f {paths {}} {first 0} {maxdepth -1}} { + +proc sub_find_file { f {paths {}} {maxdepth -1} {first 0}} { global pathlist match_file_dir_arr match_file_level nolist_libs set res {} if {$paths eq {}} {set paths $pathlist} @@ -7323,7 +7619,7 @@ proc sub_find_file { f {paths {}} {first 0} {maxdepth -1}} { 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 + set sub_res [sub_find_file $f $j $maxdepth $first] ;# recursive call incr match_file_level -1 if {$sub_res != {} } { set res [concat $res $sub_res] @@ -7353,8 +7649,9 @@ 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 $maxdepth] + set res [sub_find_file $f $paths $maxdepth 0] catch {unset match_file_dir_arr} + return $res } @@ -7366,7 +7663,7 @@ 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 $maxdepth] + set res [sub_find_file $f $paths $maxdepth 1] catch {unset match_file_dir_arr} return $res } @@ -7732,9 +8029,15 @@ proc get_file_path {ff} { # # Balloon help system, from https://wiki.tcl-lang.org/page/balloon+help # -proc balloon {w help {pos 1}} { - bind $w "after 1000 [list balloon_show %W [list $help] $pos]" - bind $w "after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon" +proc balloon {w help {pos 1} {motion_kill 0}} { + bind $w "after 1000 [list balloon_show %W [list $help] $pos]" + bind $w "after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon" + if {$motion_kill} { + bind $w " + if {\[winfo exists %W.balloon\]} { + after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon + }" + } bind $w "after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon" } @@ -7745,12 +8048,14 @@ proc balloon_show {w arg pos} { if {[eval winfo containing [winfo pointerxy .]]!=$w} {return} set top $w.balloon catch {destroy $top} - toplevel $top -bd 1 -background black + toplevel $top -bd 1 -background black -takefocus 0 wm overrideredirect $top 1 if {[string equal [tk windowingsystem] aqua]} { ::tk::unsupported::MacWindowStyle style $top help none } - pack [message $top.txt -aspect 10000 -fg black -background lightyellow \ + # pack [message $top.txt -aspect 10000 -takefocus 0 -fg black -background lightyellow \ + # -font fixed -text $arg] + pack [label $top.txt -justify left -takefocus 0 -fg black -background lightyellow \ -font fixed -text $arg] if { $pos } { set wmx [winfo rootx $w] @@ -8544,11 +8849,15 @@ proc store_geom {win filename} { set geom_data {} foreach i [array names geom_array] { - append geom_data $i { } $geom_array($i) \n + append geom_data "{" $i "}" { } $geom_array($i) \n } # puts $geom_data + # puts [llength $geom_data] # puts --- set geom_data2 [lsort -stride 3 -decreasing -index 2 -integer $geom_data] + # puts $geom_data2 + # puts [llength $geom_data2] + # puts --- set geom_data3 {} set j 0 foreach i $geom_data2 { @@ -8559,11 +8868,12 @@ proc store_geom {win filename} { append geom_data3 { } } } - append geom_data3 $i + append geom_data3 "{" $i "}" incr j } # puts $geom_data3 + # puts [llength $geom_data3] # puts === set geom_data $geom_data3 write_data $geom_data\n $geom_file @@ -8737,8 +9047,8 @@ proc no_open_dialogs {} { ## "xschem_server_getdata" only one tcp listener per process ## "bespice_server_getdata" only one tcp listener per process ## "file_dialog_*" only one load_file_dialog window is allowed -## new_symbol_browser_* ## new_file_browser_* +## file_chooser set tctx::global_list { INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR PDK PDK_ROOT SKYWATER_MODELS @@ -9277,8 +9587,8 @@ proc build_widgets { {topwin {} } } { } $topwin.menubar.file add command -label "Component browser" -accelerator {Shift-Ins, Ctrl-I} \ -command { - if {$new_symbol_browser} { - insert_symbol $new_symbol_browser_paths $new_symbol_browser_depth $new_symbol_browser_ext + if {$new_file_browser} { + file_chooser $new_file_browser_paths $new_file_browser_depth $new_file_browser_ext } else { load_file_dialog {Insert symbol} *.sym INITIALINSTDIR 2 } @@ -9890,12 +10200,16 @@ tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get label $topwin.statusbar.1 -text "STATUS BAR 1" label $topwin.statusbar.2 -text "SNAP:" entry $topwin.statusbar.3 -width 7 -foreground black -takefocus 0 + balloon $topwin.statusbar.2 "Mouse coordinates are snapped\nat multiples of this number" entry_replace_selection $topwin.statusbar.3 label $topwin.statusbar.4 -text "GRID:" entry $topwin.statusbar.5 -width 7 -foreground black -takefocus 0 + balloon $topwin.statusbar.4 "Grid points are shown \nat multiples of this number" entry_replace_selection $topwin.statusbar.5 label $topwin.statusbar.6 -text "MODE:" label $topwin.statusbar.7 -width 7 ;# netlisting mode + balloon $topwin.statusbar.6 {This is the current netlisting mode} + balloon $topwin.statusbar.7 {This is the current netlisting mode} label $topwin.statusbar.11 -text {Stretch:} label $topwin.statusbar.12 -fg red -text {} ;# xschem is ready or busy doing something @@ -9933,11 +10247,14 @@ proc cleanup_paths {paths} { foreach i $paths { regsub {^~$} $i ${env(HOME)} i regsub {^~/} $i ${env(HOME)}/ i - if { ![string compare $i .] } { - lappend pathlist $i - } elseif { [ regexp {\.\.\/} $i] } { - lappend pathlist [file normalize $i] - } elseif { [ file exists $i] } { + if {![string compare $i .]} { + # ... + } elseif { [regexp {^#} $i] } { + continue + } elseif { [regexp {\.\.\/} $i] } { + set i [file normalize $i] + } + if { [file exists $i] } { lappend pathlist $i } } @@ -10442,16 +10759,10 @@ set_ne open_in_new_window 0 ## case insensitive symbol lookup (on case insensitive filesystems only!) set_ne case_insensitive 0 -## New alternate symbol placement browser (default: not enabled). -set_ne new_symbol_browser 0 -set_ne new_symbol_browser_paths {} ;# if empty use xschem search paths -set_ne new_symbol_browser_depth 2 ;# depth to descend into each dir of the search paths -set_ne new_symbol_browser_ext {\.(sch|sym|tcl)$} ;# file extensions (a regex) to look for - ## New alternate load file browser (default: not enabled). set_ne new_file_browser 0 set_ne new_file_browser_paths {} ;# if empty use xschem search paths -set_ne new_file_browser_depth 2 ;# depth to descend into each dir of the search paths +set_ne new_file_browser_depth 0 ;# depth to descend into each dir of the search paths set_ne new_file_browser_ext {\.(sch|sym|tcl)$} ;# file extensions (a regex) to look for set_ne file_dialog_ext {*} diff --git a/src/xschemrc b/src/xschemrc index b6ce0fbe..e033a5b1 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -624,19 +624,6 @@ #### default: disabled (0) # set open_in_new_window 1 -########################################################################### -#### ALTERNATE SYMBOL PLACEMENT BROWSER -########################################################################### -#### uses a new symbol placement widget. Default: not enabled (0) -# set new_symbol_browser 1 -#### defines a list of paths to search for. If empty uses all xschem -#### XSCHEM_LIBRARY_PATH paths. Default: empty -# set new_symbol_browser_paths {... ... ...} -#### defines the depth to descend into each path. default: 2 -# set new_symbol_browser_depth 3 -#### defines the extensions to search for. Default: {\.(sch|sym|tcl)$} -# set new_symbol_browser_ext {\.(sch|sym|tcl)$} - ########################################################################### #### ALTERNATE LOAD FILE BROWSER ########################################################################### @@ -645,8 +632,8 @@ #### defines a list of paths to search for. If empty uses all xschem #### XSCHEM_LIBRARY_PATH paths. Default: empty # set new_file_browser_paths {... ... ...} -#### defines the depth to descend into each path. default: 2 -# set new_file_browser_depth 3 +#### defines the depth to descend into each path. default: 0 +# set new_file_browser_depth 1 #### defines the extensions to search for. Default: {\.(sch|sym|tcl)$} # set new_file_browser_ext {\.(sch|tcl)$}