11399 lines
406 KiB
Tcl
11399 lines
406 KiB
Tcl
#
|
|
# File: xschem.tcl
|
|
#
|
|
# This file is part of XSCHEM,
|
|
# a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
|
# simulation.
|
|
# Copyright (C) 1998-2024 Stefan Frederik Schippers
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
### INUTILE integration (spice stimuli generator from a higher level description language)
|
|
proc inutile_line {txtlabel} {
|
|
toplevel .inutile_line -class Dialog
|
|
set X [expr [winfo pointerx .inutile_line] - 60]
|
|
set Y [expr [winfo pointery .inutile_line] - 35]
|
|
wm geometry .inutile_line "+$X+$Y"
|
|
wm transient .inutile_line [xschem get topwindow]
|
|
label .inutile_line.l1 -text $txtlabel
|
|
entry .inutile_line.e1 -width 60
|
|
entry_replace_selection .inutile_line.e1
|
|
.inutile_line.e1 delete 0 end
|
|
.inutile_line.e1 insert 0 $tctx::retval
|
|
button .inutile_line.b1 -text "OK" -takefocus 0 -command \
|
|
{
|
|
set tctx::retval [.inutile_line.e1 get ]
|
|
destroy .inutile_line
|
|
}
|
|
bind .inutile_line <Return> {
|
|
set tctx::retval [.inutile_line.e1 get ]
|
|
destroy .inutile_line
|
|
}
|
|
pack .inutile_line.l1 -side top -fill x
|
|
pack .inutile_line.e1 -side top -fill both -expand yes
|
|
pack .inutile_line.b1 -side top -fill x
|
|
grab set .inutile_line
|
|
focus .inutile_line.e1
|
|
tkwait window .inutile_line
|
|
return $tctx::retval
|
|
}
|
|
|
|
proc inutile_write_data {w f} {
|
|
set fid [open $f w]
|
|
set t [$w get 0.0 {end - 1 chars}]
|
|
puts -nonewline $fid $t
|
|
close $fid
|
|
}
|
|
|
|
proc inutile_read_data {w f} {
|
|
set fid [open $f r]
|
|
set t [read $fid]
|
|
$w delete 0.0 end
|
|
$w insert 0.0 $t
|
|
close $fid
|
|
}
|
|
|
|
proc inutile_template {w f} {
|
|
set fid [open $f r]
|
|
set t [read $fid]
|
|
$w insert 0.0 $t
|
|
close $fid
|
|
}
|
|
|
|
proc inutile_get_time {} {
|
|
global netlist_dir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set fileid [open "$netlist_dir/inutile.simulationtime" "RDONLY"]
|
|
.inutile.buttons.time delete 0 end
|
|
.inutile.buttons.time insert 0 [read -nonewline $fileid]
|
|
close $fileid
|
|
file delete "$netlist_dir/inutile.simulationtime"
|
|
}
|
|
|
|
proc inutile_alias_window {w filename} {
|
|
catch {destroy $w}
|
|
toplevel $w -class Dialog
|
|
wm title $w "(IN)UTILE ALIAS FILE: $filename"
|
|
wm iconname $w "ALIAS"
|
|
# wm transient $w [xschem get topwindow]
|
|
|
|
set fileid [open $filename "RDONLY CREAT"]
|
|
set testo [read $fileid]
|
|
close $fileid
|
|
frame $w.buttons -takefocus 0
|
|
pack $w.buttons -side bottom -fill x -pady 2m
|
|
text $w.text -undo 1 -relief sunken -bd 2 -yscrollcommand "$w.scroll set" -setgrid 1 \
|
|
-height 30
|
|
scrollbar $w.scroll -command "$w.text yview"
|
|
button $w.buttons.dismiss -text Dismiss -command "destroy $w" -takefocus 0
|
|
button $w.buttons.save -text Save -command "inutile_write_data $w.text \"$filename\"" -takefocus 0
|
|
button $w.buttons.load -text Reload -command "inutile_read_data $w.text \"$filename\"" -takefocus 0
|
|
pack $w.buttons.dismiss $w.buttons.save $w.buttons.load -side left -expand 1
|
|
|
|
pack $w.scroll -side right -fill y
|
|
pack $w.text -expand yes -fill both
|
|
$w.text insert 0.0 $testo
|
|
}
|
|
|
|
proc inutile_help_window {w filename} {
|
|
catch {destroy $w}
|
|
toplevel $w -class Dialog
|
|
wm title $w "(IN)UTILE ALIAS FILE"
|
|
wm iconname $w "ALIAS"
|
|
# wm transient $w [xschem get topwindow]
|
|
|
|
frame $w.buttons -takefocus 0
|
|
pack $w.buttons -side bottom -fill x -pady 2m
|
|
button $w.buttons.dismiss -text Dismiss -command "destroy $w" -takefocus 0
|
|
button $w.buttons.save -text Save -command "inutile_write_data $w.text \"$filename\"" -takefocus 0
|
|
pack $w.buttons.dismiss $w.buttons.save -side left -expand 1
|
|
|
|
text $w.text -undo 1 -relief sunken -bd 2 -yscrollcommand "$w.scroll set" -setgrid 1 \
|
|
-height 30 -width 90
|
|
scrollbar $w.scroll -command "$w.text yview" -takefocus 0
|
|
pack $w.scroll -side right -fill y
|
|
pack $w.text -expand yes -fill both
|
|
set fileid [open $filename "RDONLY CREAT"]
|
|
$w.text insert 0.0 [read $fileid]
|
|
close $fileid
|
|
}
|
|
|
|
proc inutile_translate {f} {
|
|
global XSCHEM_SHAREDIR netlist_dir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set p $XSCHEM_SHAREDIR/utile
|
|
set savedir [pwd]
|
|
cd $netlist_dir
|
|
eval exec awk -f $p/preprocess.awk \"$f\" | awk -f $p/expand_alias.awk | awk -f $p/param.awk | awk -f $p/clock.awk | awk -f $p/stimuli.awk
|
|
cd $savedir
|
|
}
|
|
|
|
proc inutile { {filename {}} {wait {}} } {
|
|
global XSCHEM_SHAREDIR netlist_dir
|
|
|
|
if {$wait ne {}} {
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
}
|
|
if { ![string compare $filename ""] } then {
|
|
tk_messageBox -type ok -message "Please give a file name as argument"
|
|
return
|
|
}
|
|
toplevel .inutile -class Dialog
|
|
wm title .inutile "(IN)UTILE (Stefan Schippers, sschippe)"
|
|
wm iconname .inutile "(IN)UTILE"
|
|
# wm transient .inutile [xschem get topwindow]
|
|
set utile_path $XSCHEM_SHAREDIR/utile
|
|
set tctx::retval {}
|
|
frame .inutile.buttons -takefocus 0
|
|
pack .inutile.buttons -side bottom -fill x -pady 2m
|
|
button .inutile.buttons.translate -takefocus 0 -text Translate -command "
|
|
inutile_write_data .inutile.text \"$filename\"
|
|
inutile_translate \"$filename\"
|
|
inutile_get_time"
|
|
button .inutile.buttons.dismiss -takefocus 0 -text Dismiss -command "destroy .inutile"
|
|
button .inutile.buttons.code -takefocus 0 -text "Help" \
|
|
-command "inutile_help_window .inutile.help $utile_path/utile.txt"
|
|
text .inutile.text -undo 1 -relief sunken -bd 2 -yscrollcommand ".inutile.scroll set" -setgrid 1 -height 30
|
|
scrollbar .inutile.scroll -command {.inutile.text yview}
|
|
button .inutile.buttons.save -takefocus 0 -text Save -command "
|
|
set tctx::retval \"$filename\"
|
|
set filename \[inutile_line {Filename}\]
|
|
inutile_write_data .inutile.text \"$filename\""
|
|
button .inutile.buttons.load -takefocus 0 -text Reload -command "
|
|
set tctx::retval \"$filename\"
|
|
set filename \[inutile_line {Filename}\]
|
|
inutile_read_data .inutile.text \"$filename\""
|
|
button .inutile.buttons.send -takefocus 0 -text "Template" -command "
|
|
if { !\[string compare \[.inutile.text get 0.0 {end - 1 chars}\] {}\]} {
|
|
inutile_template .inutile.text $utile_path/template.stimuli}"
|
|
label .inutile.buttons.timelab -text "time:"
|
|
entry .inutile.buttons.time -width 11
|
|
entry_replace_selection .inutile.buttons.time
|
|
pack .inutile.buttons.dismiss .inutile.buttons.code \
|
|
.inutile.buttons.load .inutile.buttons.save .inutile.buttons.translate \
|
|
.inutile.buttons.send .inutile.buttons.timelab \
|
|
.inutile.buttons.time -side left -expand 1
|
|
pack .inutile.scroll -side right -fill y
|
|
pack .inutile.text -expand yes -fill both
|
|
if { [file exists $filename] } {
|
|
set fileid [open $filename "RDONLY"]
|
|
.inutile.text insert 0.0 [read $fileid]
|
|
close $fileid
|
|
}
|
|
set tmp [.inutile.text index end]
|
|
regsub {\..*$} $tmp {} lines
|
|
for {set i 1} {$i <= $lines} {incr i} {
|
|
set tmp [.inutile.text get $i.0 "$i.0 lineend"]
|
|
if [regexp {^(include)|(\.include)} $tmp ] {
|
|
inutile_alias_window .inutile.tw$i [lindex $tmp 1]
|
|
}
|
|
}
|
|
if {$wait ne {}} {
|
|
tkwait window .inutile
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
}
|
|
|
|
### End INUTILE integration
|
|
|
|
### for tclreadline: disable customcompleters
|
|
proc completer { text start end line } { return {}}
|
|
|
|
# set 'var' with '$val' if 'var' not existing
|
|
proc set_ne { var val } {
|
|
upvar #0 $var v
|
|
if { ![info exists v ] } {
|
|
set v $val
|
|
}
|
|
}
|
|
|
|
|
|
# $execute(id) is an integer identifying the last running pipeline
|
|
# set id $execute(id) to get the current subprocess id in variable 'id'
|
|
# $execute(status,$id) contains the status argument as given in proc execute
|
|
# $execute(pipe,$id) contains the channel descriptor to read or write as specified in status
|
|
# $execute(data,$id) contains the stdout of the pipeline (output data)
|
|
# $execute(cmd,$id) contains the pipeline command
|
|
# $execute(win_path,$id) contains the xctx->current_win_path that started the command
|
|
# $execute(exitcode,id) contains the exit code. This variable will not be deleted at the end
|
|
# when subprocess ends all execute(...,$id) data is cleared (except execute(exitcode,id)
|
|
#
|
|
# The following post-mortem data is available for last finished process:
|
|
# execute(cmd,last) : the command
|
|
# execute(win_path,last): the xctx->current_win_path that started the last command
|
|
# execute(data,last) : the data
|
|
# execute(error,last) : the errors (stderr)
|
|
# execute(status,last) : the status argument as was given when calling proc execute
|
|
# execute(exitcode,last): exit code of last finished process
|
|
#
|
|
# execute service function
|
|
proc execute_fileevent {id} {
|
|
global execute OS has_x errorCode
|
|
|
|
append execute(data,$id) [read $execute(pipe,$id) 1024]
|
|
if { $OS != {Windows} } {
|
|
set eof [eof $execute(pipe,$id)]
|
|
# handle processes that close stdout. Read pipe will go into eof condition
|
|
# but process is still running. Doing a close operation in blocking mode
|
|
# will block execution until process exits.
|
|
# In this situation we avoid setting pipe to blocking mode and do an
|
|
# asynchronous close. We lose exit status and stderr though, but
|
|
# avoid the program to freeze waiting for process to exit.
|
|
set lastproc [lindex [pid $execute(pipe,$id)] end]
|
|
set ps_status [exec ps -o state= -p $lastproc]
|
|
set finished [regexp Z $ps_status] ;# if zombie consider process to be finished.
|
|
if { $eof && !$finished} {
|
|
after 2000 "execute_fileevent $id"
|
|
fileevent $execute(pipe,$id) readable ""
|
|
# puts "rescheduling $id"
|
|
return
|
|
}
|
|
} else {
|
|
set eof [eof $execute(pipe,$id)]
|
|
set finished 1
|
|
}
|
|
if {$eof} {
|
|
set report [regexp {1} $execute(status,$id)]
|
|
fileevent $execute(pipe,$id) readable ""
|
|
# setting pipe to blocking before closing allows to get pipeline exit status
|
|
# do not ask status for processes that close stdout/stderr, as eof might
|
|
# occur before process ends and following close blocks until process terminates.
|
|
if {$finished} {fconfigure $execute(pipe,$id) -blocking 1}
|
|
set exit_status 0
|
|
set catch_return [eval catch [list {close $execute(pipe,$id)} err] ]
|
|
# puts "catch_return=$catch_return"
|
|
if {$catch_return} {
|
|
# puts "errorCode=$errorCode"
|
|
if {"NONE" == [lindex $errorCode 0]} {
|
|
set exit_status 0
|
|
} elseif {"CHILDSTATUS" == [lindex $errorCode 0]} {
|
|
set exit_status [lindex $errorCode 2]
|
|
# puts "exit_status=$exit_status"
|
|
} else {
|
|
set exit_status $catch_return
|
|
}
|
|
if {$exit_status != 0} {
|
|
if {$report} {viewdata "Failed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"}
|
|
} else {
|
|
if {$report} {viewdata "Completed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"}
|
|
}
|
|
} else {
|
|
if {$report} {viewdata "Completed: $execute(cmd,$id)\ndata:\n$execute(data,$id)"}
|
|
}
|
|
set execute(exitcode,last) $exit_status
|
|
set execute(exitcode,$id) $exit_status
|
|
set execute(cmd,last) $execute(cmd,$id)
|
|
set execute(win_path,last) $execute(win_path,$id)
|
|
set execute(data,last) $execute(data,$id)
|
|
if { ![info exists err] } { set err {} }
|
|
set execute(error,last) $err
|
|
set execute(status,last) $execute(status,$id)
|
|
|
|
if { [info exists tctx::$execute(win_path,$id)_simulate_id] } {
|
|
if { [set tctx::$execute(win_path,$id)_simulate_id] eq $id } {
|
|
unset tctx::$execute(win_path,$id)_simulate_id
|
|
}
|
|
}
|
|
|
|
if {[info exists execute(callback,$id)] && $execute(callback,$id) ne {}} {
|
|
# puts $execute(callback,$id)
|
|
# puts $execute(win_path,$id)
|
|
eval uplevel #0 [list $execute(callback,$id)]
|
|
}
|
|
catch {unset execute(callback,$id)}
|
|
|
|
if { ![info exists exit_status] } { set exit_status 0 }
|
|
unset execute(pipe,$id)
|
|
unset execute(data,$id)
|
|
unset execute(status,$id)
|
|
unset execute(cmd,$id)
|
|
unset execute(win_path,$id)
|
|
# apply a delay, process does not disappear immediately.
|
|
if {[info exists has_x] && [winfo exists .processlist]} { after 250 {insert_running_cmds .processlist.f2.lb}}
|
|
}
|
|
}
|
|
|
|
proc execute_wait {status args} {
|
|
global execute
|
|
set id [eval execute $status $args]
|
|
if {$id == -1} {
|
|
return -1
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
vwait execute(pipe,$id)
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $id
|
|
}
|
|
|
|
# equivalent to the 'exec' tcl function but keeps the event loop
|
|
# responding, so widgets get updated properly
|
|
# while waiting for process to end.
|
|
# status:
|
|
# rw open pipe in 'r+' (read write) mode instead of 'r'
|
|
# line set line buffering mode of channel
|
|
# none set no channel buffering.
|
|
# 1 get status report at process end
|
|
# 0 no status report
|
|
#
|
|
# These options can be combined as in '1rwline' of '1rnone'
|
|
#
|
|
proc execute {status args} {
|
|
global execute has_x
|
|
if {![info exists execute(id)]} {
|
|
set execute(id) 0
|
|
} else {
|
|
incr execute(id)
|
|
}
|
|
set id $execute(id)
|
|
if { [info exists execute(callback)] } {
|
|
set execute(callback,$id) $execute(callback)
|
|
unset execute(callback)
|
|
}
|
|
set mode r
|
|
if {[regexp {rw} $status]} {
|
|
set mode r+
|
|
}
|
|
if { [catch {open "|$args" $mode} err] } {
|
|
puts stderr "Proc execute error: $err"
|
|
if { [info exists has_x]} {
|
|
tk_messageBox -message \
|
|
"Can not execute '$args': ensure it is available on the system. Error: $err" \
|
|
-icon error -parent [xschem get topwindow] -type ok
|
|
}
|
|
return -1
|
|
} else {
|
|
set pipe $err
|
|
}
|
|
set execute(status,$id) $status
|
|
set execute(pipe,$id) $pipe
|
|
set execute(cmd,$id) $args
|
|
set execute(win_path,$id) [xschem get current_win_path]
|
|
set execute(data,$id) ""
|
|
|
|
# Apply a delay to catch the new process.
|
|
if {[info exists has_x] && [winfo exists .processlist]} { after 250 {insert_running_cmds .processlist.f2.lb}}
|
|
fconfigure $pipe -blocking 0
|
|
if {[regexp {line} $status]} {
|
|
fconfigure $pipe -buffering line
|
|
}
|
|
if {[regexp {none} $status]} {
|
|
fconfigure $pipe -buffering none
|
|
}
|
|
fileevent $pipe readable "execute_fileevent $id"
|
|
return $id
|
|
}
|
|
|
|
# kill selected sub-processes by looking up their command strings
|
|
# into all running sub-processes, killing the matching ones
|
|
# with the supplied 'sig'.
|
|
proc kill_running_cmds {{lb {}} sig} {
|
|
global execute
|
|
if { [regexp {^[0-9]+$} $lb] && $lb >= 0 } {
|
|
set id $lb
|
|
if { [info exists execute(pipe,$id)] } {
|
|
set pid [pid $execute(pipe,$id)]
|
|
exec kill $sig $pid
|
|
} else {
|
|
return 0
|
|
}
|
|
} else {
|
|
set selected [$lb curselection]
|
|
foreach idx $selected {
|
|
set cmd1 [$lb get $idx]
|
|
foreach {id pid cmd2} [get_running_cmds] {
|
|
# puts "$cmd1\n$cmd2 \n$pid"
|
|
if { $cmd1 eq $cmd2 } {
|
|
exec kill $sig $pid
|
|
break
|
|
}
|
|
}
|
|
}
|
|
after 250 insert_running_cmds $lb
|
|
}
|
|
# apply a delay, after a kill command process does not disappear
|
|
# immediately.
|
|
return 1
|
|
}
|
|
|
|
# refresh list of running commands in dialog box
|
|
proc insert_running_cmds {lb} {
|
|
$lb delete 0 end
|
|
foreach {id pid cmd} [get_running_cmds] {
|
|
# puts "inserting $cmd"
|
|
$lb insert end $cmd
|
|
}
|
|
}
|
|
|
|
# periodically update status
|
|
proc update_process_status {lb} {
|
|
global execute has_x
|
|
set exists 0
|
|
if { ![info exists has_x]} {return}
|
|
if {[winfo exists .processlist] && [winfo exists .pstat] } {
|
|
set selected [$lb curselection]
|
|
set pos [lindex [.pstat.text yview] 1]
|
|
if {$pos == 1} {
|
|
if { $selected ne {} && [llength $selected] == 1} {
|
|
.pstat.text delete 1.0 end
|
|
set idx $selected
|
|
set cmd1 [$lb get $idx]
|
|
foreach {id pid cmd2} [get_running_cmds] {
|
|
if { $cmd1 eq $cmd2 } {
|
|
if {[catch { set t $execute(data,$id) } err]} {
|
|
set t $err
|
|
}
|
|
.pstat.text insert 1.0 $t
|
|
.pstat.text yview moveto 1
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
after 1000 "update_process_status $lb"
|
|
} else {
|
|
after cancel "update_process_status $lb"
|
|
}
|
|
}
|
|
|
|
|
|
# display stdout of selected sub-process
|
|
proc view_process_status {lb} {
|
|
global execute has_x
|
|
set exists 0
|
|
if {![info exists has_x]} {return}
|
|
if {[winfo exists .pstat] } {
|
|
.pstat.text delete 1.0 end
|
|
set exists 1
|
|
}
|
|
set selected [$lb curselection]
|
|
if {$selected ne {} && [llength $selected] == 1} {
|
|
set idx $selected
|
|
set cmd1 [$lb get $idx]
|
|
foreach {id pid cmd2} [get_running_cmds] {
|
|
if { $cmd1 eq $cmd2 } {
|
|
if {[catch { set t $execute(data,$id) } err]} {
|
|
set t $err
|
|
}
|
|
if {$exists == 0} {
|
|
viewdata $t ro .pstat
|
|
} else {
|
|
.pstat.text insert 1.0 $t
|
|
}
|
|
.pstat.text yview moveto 1
|
|
break
|
|
}
|
|
}
|
|
}
|
|
after 1000 "update_process_status $lb"
|
|
}
|
|
|
|
proc list_running_cmds_title {} {
|
|
if {[winfo exists .processlist]} {
|
|
wm title .processlist "List of running commands - [xschem get current_name]"
|
|
after 1000 "list_running_cmds_title"
|
|
}
|
|
}
|
|
|
|
# top level dialog displaying running sub-processes
|
|
proc list_running_cmds {} {
|
|
global has_x
|
|
set top .processlist
|
|
if {![info exists has_x]} {return}
|
|
if {[winfo exists $top]} {raise $top; return}
|
|
toplevel $top -class Dialog
|
|
list_running_cmds_title
|
|
# wm transient $top [xschem get topwindow]
|
|
set frame1 $top.f1
|
|
set frame2 $top.f2
|
|
set frame3 $top.f3
|
|
frame $frame1 -takefocus 0
|
|
frame $frame2 -takefocus 0
|
|
frame $frame3 -takefocus 0
|
|
set lb $frame2.lb
|
|
listbox $lb -width 70 -height 8 -selectmode extended \
|
|
-yscrollcommand "$frame2.yscroll set" \
|
|
-xscrollcommand "$frame2.xscroll set"
|
|
scrollbar $frame2.yscroll -command "$lb yview"
|
|
scrollbar $frame2.xscroll -orient horiz -command "$lb xview"
|
|
pack $frame2.yscroll -side right -fill y
|
|
pack $frame2.xscroll -side bottom -fill x
|
|
pack $lb -side bottom -fill both -expand true
|
|
|
|
bind $lb <Double-Button-1> [list $frame3.b3 invoke]
|
|
button $frame3.b1 -width 16 -takefocus 0 -text {Terminate selected} -command "kill_running_cmds $lb -15" \
|
|
-fg black -background yellow
|
|
button $frame3.b2 -width 16 -takefocus 0 -text {Kill selected} -command "kill_running_cmds $lb -9" \
|
|
-fg black -background red
|
|
button $frame3.b3 -width 16 -takefocus 0 -text {View status} -command "view_process_status $lb" \
|
|
-fg black -background PaleGreen
|
|
button $frame3.b4 -width 16 -takefocus 0 -text {Dismiss} \
|
|
-fg black -background PaleGreen -command "
|
|
if {\[winfo exists .pstat\]} {
|
|
after cancel [list update_process_status $lb]
|
|
destroy .pstat
|
|
}
|
|
destroy $top
|
|
|
|
"
|
|
wm protocol $top WM_DELETE_WINDOW " $frame3.b4 invoke "
|
|
pack $frame3.b1 $frame3.b2 $frame3.b3 $frame3.b4 -side left -fill x -expand 1
|
|
pack $frame1 -fill x -expand 0
|
|
pack $frame2 -fill both -expand 1
|
|
pack $frame3 -fill x -expand 0
|
|
|
|
insert_running_cmds $lb
|
|
}
|
|
|
|
# for each running sub-process return a list of three elements per process:
|
|
# the integer id, the process PID, the command string.
|
|
proc get_running_cmds {} {
|
|
global execute
|
|
set ret {}
|
|
foreach i [array names execute *pipe*] {
|
|
set id [lindex [split $i ,] 1]
|
|
lappend ret $id [pid $execute($i)] $execute(cmd,$id)
|
|
}
|
|
return $ret
|
|
}
|
|
|
|
# pause for $del_ms milliseconds, keep event loop responsive
|
|
proc delay {del_ms} {
|
|
after $del_ms {set tctx::delay_flag 1}
|
|
vwait tctx::delay_flag
|
|
unset tctx::delay_flag
|
|
}
|
|
|
|
#### Scrollable frame
|
|
proc sframeyview {container args} {
|
|
global ${container}_vpos ;# global to remember scrollbar position
|
|
set_ne ${container}_vpos 0
|
|
if {[lindex $args 0] eq {place}} {
|
|
place ${container}.f.scrl -in $container.f -x 0 -y 0 -relwidth 1
|
|
update ;# without this vpos of scrollbar will not be remembered when reopening toplevel
|
|
}
|
|
set ht [winfo height $container.f]
|
|
set hs [winfo height $container.f.scrl]
|
|
set frac [expr {double($ht)/$hs}]
|
|
if { [lindex $args 0] eq {scroll}} { ;# mouse wheel
|
|
set ${container}_vpos [expr {[set ${container}_vpos] + [lindex $args 1] *(1.0/$frac)/5}]
|
|
} elseif { [lindex $args 0] eq {moveto}} { ;# scrollbar slider
|
|
set ${container}_vpos [lindex $args 1]
|
|
}
|
|
if { [set ${container}_vpos] < 0.0 } {set ${container}_vpos 0.0}
|
|
if { [set ${container}_vpos] > 1.0 - $frac } {set ${container}_vpos [expr {1.0 - $frac}]}
|
|
$container.vs set [set ${container}_vpos] [expr {[set ${container}_vpos] + $frac}]
|
|
place $container.f.scrl -in $container.f -x 0 -y [expr {-$hs * [set ${container}_vpos]}] -relwidth 1.0
|
|
}
|
|
|
|
# scrollable frame constructor
|
|
proc sframe {container} {
|
|
frame $container.f -takefocus 0
|
|
scrollbar $container.vs -command "sframeyview $container" ;# sframeyview moveto commands
|
|
frame $container.f.scrl -takefocus 0
|
|
pack $container.f -expand yes -fill both -side left
|
|
pack $container.vs -expand yes -fill y
|
|
return $container.f.scrl
|
|
}
|
|
#### /Scrollable frame
|
|
|
|
## convert engineering form to number
|
|
proc from_eng {i} {
|
|
set str {}
|
|
scan $i "%g%s" n str
|
|
set str [string tolower $str]
|
|
if { [regexp {^meg} $str] } { set suffix {meg} } else {
|
|
set suffix [string index $str 0]
|
|
}
|
|
set mult [switch $suffix {
|
|
a { expr {1e-18}}
|
|
f { expr {1e-15}}
|
|
p { expr {1e-12}}
|
|
n { expr { 1e-9}}
|
|
u { expr {1e-6}}
|
|
m { expr {1e-3}}
|
|
k { expr {1e3}}
|
|
x { expr {1e6}}
|
|
meg { expr {1e6}}
|
|
g { expr {1e9}}
|
|
t { expr {1e12}}
|
|
default { expr {1.0}}
|
|
}]
|
|
return [expr {$n * $mult}]
|
|
}
|
|
|
|
## convert number to engineering form
|
|
proc to_eng {args} {
|
|
set suffix {}
|
|
|
|
if {[ catch {uplevel #0 expr [join $args]} i]} {
|
|
return [join $args]
|
|
}
|
|
set i [uplevel #0 expr [join $args]]
|
|
set absi [expr {abs($i)}]
|
|
|
|
if {$absi == 0.0} { set mult 1 ; set suffix {}
|
|
} elseif {$absi >=1e12} { set mult 1e-12; set suffix T
|
|
} elseif {$absi >=1e9} { set mult 1e-9 ; set suffix G
|
|
} elseif {$absi >=1e6} { set mult 1e-6 ; set suffix M
|
|
} elseif {$absi >=1e3} { set mult 1e-3 ; set suffix k
|
|
} elseif {$absi >=0.1} { set mult 1 ; set suffix {}
|
|
} elseif {$absi >=1e-3} { set mult 1e3 ; set suffix m
|
|
} elseif {$absi >=1e-6} { set mult 1e6 ; set suffix u
|
|
} elseif {$absi >=1e-9} { set mult 1e9 ; set suffix n
|
|
} elseif {$absi >=1e-12} { set mult 1e12 ; set suffix p
|
|
} elseif {$absi >=1e-15} { set mult 1e15 ; set suffix f
|
|
} else { set mult 1e18 ; set suffix a}
|
|
if {$suffix ne {}} {
|
|
set i [expr {$i * $mult}]
|
|
set s [format {%.5g%s} $i $suffix]
|
|
} else {
|
|
set s [format {%.5g} $i]
|
|
}
|
|
return $s
|
|
}
|
|
|
|
proc = {args} {
|
|
set r [ev7 $args]
|
|
puts $r
|
|
}
|
|
|
|
## evaluate expression with 7 significant digits.
|
|
## if expression has errors or does not evaluate return expression as is
|
|
proc ev7 {args} {
|
|
set i [join $args]
|
|
if {![catch {uplevel #0 expr $i} res]} {
|
|
return [format %.7g $res]
|
|
} else {
|
|
# puts stderr "proc ev: $res"
|
|
return $args
|
|
}
|
|
}
|
|
|
|
## evaluate expression. if expression has errors or does not evaluate return expression as is
|
|
proc ev {args} {
|
|
set i [join $args]
|
|
if {![catch {uplevel #0 expr $i} res]} {
|
|
return [format %.4g $res]
|
|
} else {
|
|
# puts stderr "proc ev: $res"
|
|
return $args
|
|
}
|
|
}
|
|
|
|
## evaluate expression. if expression has errors or does not evaluate return 0
|
|
proc ev0 {args} {
|
|
set i [join $args]
|
|
if {![catch {uplevel #0 expr $i} res]} {
|
|
return [format %.4g $res]
|
|
} else {
|
|
# puts stderr "proc ev0: $res"
|
|
return 0
|
|
}
|
|
}
|
|
|
|
# create the 'lassign' command if tcl does not have it (pre 8.5)
|
|
if {[info commands lassign] eq {}} {
|
|
proc lassign { list args } {
|
|
set n 0
|
|
foreach i $args {
|
|
upvar $i v
|
|
set v [lindex $list $n]
|
|
incr n
|
|
}
|
|
return [lrange $list $n end]
|
|
}
|
|
}
|
|
|
|
# return "$n * $indent" spaces
|
|
proc spaces {n {indent 4} {char { }}} {
|
|
set n [expr {$n * $indent}]
|
|
# return [format %${n}s {}]
|
|
return [string repeat $char $n]
|
|
}
|
|
|
|
# complex number operators
|
|
# a + b
|
|
proc cadd {a b} {
|
|
lassign $a ra ia
|
|
lassign $b rb ib
|
|
set c [list [expr {$ra + $rb}] [expr {$ia + $ib}]]
|
|
return $c
|
|
}
|
|
|
|
# a - b
|
|
proc csub {a b} {
|
|
lassign $a ra ia
|
|
lassign $b rb ib
|
|
set c [list [expr {$ra - $rb}] [expr {$ia - $ib}]]
|
|
return $c
|
|
}
|
|
|
|
# a * b
|
|
proc cmul {a b} {
|
|
lassign $a ra ia
|
|
lassign $b rb ib
|
|
set c [list [expr {$ra * $rb - $ia * $ib}] [expr {$ra * $ib + $rb * $ia}]]
|
|
return $c
|
|
}
|
|
|
|
# a / b
|
|
proc cdiv {a b} {
|
|
lassign $a ra ia
|
|
lassign $b rb ib
|
|
set ra [expr {double($ra)}]
|
|
set ia [expr {double($ia)}]
|
|
set rb [expr {double($rb)}]
|
|
set ib [expr {double($ib)}]
|
|
set m [expr {$rb * $rb + $ib * $ib}]
|
|
set c [list [expr {($ra * $rb + $ia * $ib) / $m}] [expr {($rb * $ia - $ra * $ib) / $m}]]
|
|
return $c
|
|
}
|
|
|
|
# 1/b
|
|
proc cinv {b} {
|
|
|
|
lassign $b rb ib
|
|
set rb [expr {double($rb)}]
|
|
set ib [expr {double($ib)}]
|
|
set m [expr {$rb * $rb + $ib * $ib}]
|
|
set c [list [expr {$rb / $m}] [expr {-$ib / $m}]]
|
|
return $c
|
|
}
|
|
|
|
# return real component
|
|
proc creal {a} {
|
|
lassign $a ra ia
|
|
return $ra
|
|
}
|
|
|
|
# return imaginary component
|
|
proc cimag {a} {
|
|
lassign $a ra ia
|
|
return $ia
|
|
}
|
|
|
|
# return resulting impedance of parallel connected impedances a and b
|
|
proc cparallel {a b} {
|
|
return [cdiv [cmul $a $b] [cadd $a $b]]
|
|
}
|
|
|
|
# wraps provided table formatted text into a nice looking bordered table
|
|
# sep is the list of characters used as separators, default are { }, {,}, {\t}
|
|
# if you want to tabulate data with spaces use only {,} as separator or any other character.
|
|
proc tabulate {text {sep ",\t "}} {
|
|
# define table characters
|
|
set top {┌ ─ ┬ ┐}
|
|
set row {│ { } │ │}
|
|
set mid {├ ─ ┼ ┤}
|
|
set head {╞ ═ ╪ ╡}
|
|
set bot {└ ─ ┴ ┘}
|
|
|
|
# used_sep (first character of sep) will be used as separator after text cleanup
|
|
set used_sep [string range $sep 0 0]
|
|
set sep "\[$sep\]"
|
|
set maxcols 0 ;# max number of columns
|
|
set nlines 0 ;# number of data lines
|
|
set chopped_text {}
|
|
set found_data 0
|
|
foreach line [split $text \n] {
|
|
|
|
# skip completely empty lines
|
|
if {[regexp {^$} $line]} { continue}
|
|
# skip leading lines with no data (only separators)
|
|
if {!$found_data && [regexp ^${sep}*\$ $line]} {
|
|
continue
|
|
}
|
|
set found_data 1
|
|
|
|
# change separators to { }
|
|
regsub -all $sep $line $used_sep line
|
|
|
|
# transform resulting line into a proper list
|
|
set line [split $line $used_sep]
|
|
incr nlines
|
|
set ncols 0
|
|
# calculate max field width and number of columns
|
|
foreach field $line {
|
|
incr ncols
|
|
if {![info exists maxlen($ncols)]} {set maxlen($ncols) 0}
|
|
if {$ncols > $maxcols} {set maxcols $ncols}
|
|
set len [string length $field]
|
|
if {$len > $maxlen($ncols)} { set maxlen($ncols) $len}
|
|
}
|
|
if { $chopped_text ne {}} {append chopped_text \n}
|
|
append chopped_text $line
|
|
}
|
|
|
|
set table {}
|
|
set l 0
|
|
foreach line [split $chopped_text \n] {
|
|
incr l
|
|
|
|
# top table border
|
|
set rowsep {}
|
|
if {$l == 1} {
|
|
append rowsep [lindex $top 0]
|
|
set c 0
|
|
for {set i 0} {$i < $maxcols} { incr i} {
|
|
set field [lindex $line $i]
|
|
incr c
|
|
append rowsep [string repeat [lindex $top 1] $maxlen($c)]
|
|
if { $c == $ncols} {
|
|
append rowsep [lindex $top 3]
|
|
} else {
|
|
append rowsep [lindex $top 2]
|
|
}
|
|
}
|
|
append table $rowsep \n
|
|
} else {
|
|
append table \n
|
|
}
|
|
set rowsep {}
|
|
append table [lindex $row 0]
|
|
if { $l == $nlines} {
|
|
append rowsep [lindex $bot 0]
|
|
} elseif {$l == 1} {
|
|
append rowsep [lindex $head 0]
|
|
} else {
|
|
append rowsep [lindex $mid 0]
|
|
}
|
|
set c 0
|
|
for {set i 0} {$i < $maxcols} { incr i} {
|
|
set field [lindex $line $i]
|
|
incr c
|
|
set pad [expr {$maxlen($c) - [string length $field]}]
|
|
append table $field [string repeat { } $pad]
|
|
if { $l == $nlines} {
|
|
append rowsep [string repeat [lindex $bot 1] $maxlen($c)]
|
|
} elseif {$l == 1} {
|
|
append rowsep [string repeat [lindex $head 1] $maxlen($c)]
|
|
} else {
|
|
append rowsep [string repeat [lindex $mid 1] $maxlen($c)]
|
|
}
|
|
if { $c == $ncols} {
|
|
append table [lindex $row 3]
|
|
if { $l == $nlines} {
|
|
append rowsep [lindex $bot 3]
|
|
} elseif {$l == 1} {
|
|
append rowsep [lindex $head 3]
|
|
} else {
|
|
append rowsep [lindex $mid 3]
|
|
}
|
|
} else {
|
|
append table [lindex $row 2]
|
|
if { $l == $nlines} {
|
|
append rowsep [lindex $bot 2]
|
|
} elseif { $l == 1} {
|
|
append rowsep [lindex $head 2]
|
|
} else {
|
|
append rowsep [lindex $mid 2]
|
|
}
|
|
}
|
|
}
|
|
append table \n $rowsep
|
|
}
|
|
return $table
|
|
}
|
|
|
|
# get pin ordering from included subcircuit
|
|
# return empty string if not found.
|
|
proc has_included_subcircuit {symname spice_sym_def no_of_pins} {
|
|
global has_x
|
|
set include_found 0
|
|
regsub -all {\n\+} $spice_sym_def { } spice_sym_def
|
|
# puts "has_included_subcircuit: spice_sym_def=$spice_sym_def"
|
|
set pinlist {}
|
|
# .include? get the file ...
|
|
if {[regexp -nocase {^[ \t\n]*\.include +} $spice_sym_def]} {
|
|
regsub -nocase {^[ \t\n]*\.include +} $spice_sym_def {} filename
|
|
regsub -all {^"|"$} $filename {} filename ;# remove double quotes at beginning and end
|
|
regsub -all {^\n*|\n*$} $filename {} filename ;# remove newlines at beginning and end
|
|
set filename [abs_sym_path $filename]
|
|
# puts "filename=$filename"
|
|
set res [catch {open $filename r} fd]
|
|
if { $res } {
|
|
puts "has_included_subcircuit: error opening file $filename: $fd"
|
|
if { [info exists has_x] } {alert_ "has_included_subcircuit: error opening file $filename: $fd"}
|
|
return $pinlist
|
|
}
|
|
set spice_sym_def [read -nonewline $fd]
|
|
close $fd
|
|
regsub -all {\n\+} $spice_sym_def { } spice_sym_def
|
|
}
|
|
# ... or use the attribute value as *the* subcircuit
|
|
|
|
# split lines
|
|
set spice_sym_def [split $spice_sym_def \n]
|
|
foreach line $spice_sym_def {
|
|
# get 1st line with a matching .subckt. This is our subcircuit definition, get the pin order
|
|
if {[string tolower [lindex $line 0]] eq {.subckt} &&
|
|
[string tolower [lindex $line 1]] eq $symname} {
|
|
set include_found 1
|
|
regsub -all { *= *} $line {=} line
|
|
# pin list ends where parameter assignment begins (param=value)
|
|
set last [lsearch -regexp [string tolower $line] {=|param:}]
|
|
if {$last == -1} {
|
|
set last [expr {[llength $line] -1}]
|
|
} else {
|
|
set last [expr {$last -1}]
|
|
}
|
|
# if spice_sym_def has more ports than symbol (no_of_pins) assume these are extra ports
|
|
# assigned via attributes ('extra' symbol attribute, usually power rails), these extra
|
|
# ports are not returned as @pinlist and correspondence with symbol format string
|
|
# is not checked. user must ensure these additional ports are in the right order.
|
|
if { $last >= $no_of_pins + 1 } {
|
|
set last [expr {$no_of_pins + 1}]
|
|
}
|
|
set pinlist [lrange $line 2 $last]
|
|
break
|
|
}
|
|
}
|
|
# return pinlist as found in the .subckt line or empty string if not found
|
|
if {!$include_found} {
|
|
puts "has_included_subcircuit: $symname: no matching .subckt found in spice_sym_def. Ignore"
|
|
if { [info exists has_x] } {
|
|
alert_ "has_included_subcircuit: $symname: no matching .subckt found in spice_sym_def. Ignore"
|
|
}
|
|
}
|
|
# puts $pinlist
|
|
return [string tolower [join $pinlist]]
|
|
}
|
|
|
|
# should not be called directly by user
|
|
# does netlist post processing, called from global_(spice|vhdl|verilog)_netlist()
|
|
proc netlist {source_file show netlist_file} {
|
|
global XSCHEM_SHAREDIR flat_netlist netlist_dir simulate_bg
|
|
global verilog_2001 debug_var OS has_x verilog_bitblast
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
# if waves are loaded turn Waves button to orange to indicate old waves are shown
|
|
set win_path [xschem get current_win_path]
|
|
set top_path [xschem get top_path]
|
|
set waves_var tctx::${win_path}_waves
|
|
if {[info exists has_x] && $waves_var ne $simulate_bg} {
|
|
set $waves_var orange
|
|
catch {$top_path.menubar entryconfigure Waves -background orange}
|
|
}
|
|
|
|
set netlist_type [xschem get netlist_type]
|
|
if {$debug_var <= -1} { puts "netlist: source_file=$source_file, netlist_type=$netlist_type" }
|
|
set dest $netlist_dir/$netlist_file
|
|
if {$netlist_type eq {spice}} {
|
|
if { [sim_is_xyce] } {
|
|
set xyce {-xyce}
|
|
} else {
|
|
set xyce {}
|
|
}
|
|
set cmd ${XSCHEM_SHAREDIR}/spice.awk
|
|
set brk ${XSCHEM_SHAREDIR}/break.awk
|
|
set flatten ${XSCHEM_SHAREDIR}/flatten.awk
|
|
if {$flat_netlist==0} {
|
|
eval exec {awk -f $cmd -- $xyce $source_file | awk -f $brk > $dest}
|
|
} else {
|
|
eval exec {awk -f $cmd -- $xyce $source_file | awk -f $flatten | awk -f $brk > $dest}
|
|
}
|
|
if ![string compare $show "show"] {
|
|
textwindow $dest
|
|
}
|
|
}
|
|
|
|
if {$netlist_type eq {spectre}} {
|
|
set cmd ${XSCHEM_SHAREDIR}/spectre.awk
|
|
eval exec {awk -f $cmd -- $source_file > $dest}
|
|
if ![string compare $show "show"] {
|
|
textwindow $dest
|
|
}
|
|
}
|
|
|
|
if {$netlist_type eq {vhdl}} {
|
|
set cmd $XSCHEM_SHAREDIR/vhdl.awk
|
|
eval exec {awk -f $cmd $source_file > $dest}
|
|
if ![string compare $show "show"] {
|
|
textwindow $dest
|
|
}
|
|
}
|
|
if {$netlist_type eq {tedax}} {
|
|
set cmd1 $XSCHEM_SHAREDIR/tedax.awk
|
|
set cmd2 $XSCHEM_SHAREDIR/flatten_tedax.awk
|
|
if {[catch {eval exec {awk -f $cmd1 $source_file | awk -f $cmd2 > $dest} } err] } {
|
|
puts stderr "tEDAx errors: $err"
|
|
}
|
|
if ![string compare $show "show"] {
|
|
textwindow $dest
|
|
}
|
|
}
|
|
if {$netlist_type eq {verilog}} {
|
|
set cmd ${XSCHEM_SHAREDIR}/verilog.awk
|
|
if { $verilog_bitblast == 1 } {
|
|
eval exec {awk -f $cmd -- -bitblast $source_file > $dest}
|
|
} else {
|
|
eval exec {awk -f $cmd $source_file > $dest}
|
|
}
|
|
if { $verilog_2001==1 } {
|
|
set cmd ${XSCHEM_SHAREDIR}/convert_to_verilog2001.awk
|
|
set interm ${dest}[pid]
|
|
eval exec {awk -f $cmd $dest > $interm}
|
|
file rename -force $interm $dest
|
|
}
|
|
if ![string compare $show "show"] {
|
|
textwindow "$dest"
|
|
}
|
|
}
|
|
return {}
|
|
}
|
|
|
|
# 20161121
|
|
proc convert_to_pdf {filename dest} {
|
|
global to_pdf OS execute
|
|
if { [regexp -nocase {\.pdf$} $dest] } {
|
|
set pdffile [file rootname $filename].pdf
|
|
# puts "---> cmd=$to_pdf filename=$filename pdffile=$pdffile dest=$dest"
|
|
if {$OS == "Windows"} {
|
|
set cmd "exec $to_pdf \$pdffile \$filename"
|
|
if { ![catch {eval $cmd} msg] } {
|
|
file rename -force $pdffile $dest
|
|
# ps2pdf succeeded, so remove original .ps file
|
|
if { ![xschem get debug_var] } {
|
|
file delete $filename
|
|
}
|
|
} else {
|
|
puts stderr "problems converting postscript to pdf: $msg"
|
|
}
|
|
} else { ;# OS == unix
|
|
eval execute_wait 0 $to_pdf [list $filename $pdffile]
|
|
if {$execute(status,last) == 0} {
|
|
file rename -force $pdffile $dest
|
|
if { ![xschem get debug_var] } {
|
|
file delete $filename
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
# puts "rename $filename $dest"
|
|
file rename -force $filename $dest
|
|
}
|
|
}
|
|
|
|
# 20161121
|
|
proc convert_to_png {filename dest} {
|
|
global to_png debug_var OS
|
|
# puts "---> $to_png $filename $dest"
|
|
set cmd "exec $to_png \$filename png:\$dest"
|
|
if {$OS == "Windows"} {
|
|
set cmd "exec $to_png \$dest \$filename"
|
|
}
|
|
if { ![catch {eval $cmd} msg] } {
|
|
# conversion succeeded, so remove original .xpm file
|
|
if { ![xschem get debug_var] } {
|
|
file delete $filename
|
|
}
|
|
} else {
|
|
puts stderr "problems converting xpm to png: $msg"
|
|
}
|
|
}
|
|
|
|
# always specify Shift- modifier for capital letters
|
|
# see tk 'man keysyms' for key names
|
|
# example format for s, d: Control-Alt-Key-asterisk
|
|
# Control-Shift-Key-A
|
|
# Alt-Key-c
|
|
# ButtonPress-4
|
|
#
|
|
proc key_binding { s d { win_path {.drw} } } {
|
|
regsub {.*-} $d {} key
|
|
|
|
|
|
switch $key {
|
|
Insert { set keysym 65379 }
|
|
Escape { set keysym 65307 }
|
|
Return { set keysym 65293 }
|
|
Delete { set keysym 65535 }
|
|
F1 { set keysym 65470 }
|
|
F2 { set keysym 65471 }
|
|
F3 { set keysym 65472 }
|
|
F4 { set keysym 65473 }
|
|
F5 { set keysym 65474 }
|
|
F6 { set keysym 65475 }
|
|
F7 { set keysym 65476 }
|
|
F8 { set keysym 65477 }
|
|
F9 { set keysym 65478 }
|
|
F10 { set keysym 65479 }
|
|
F11 { set keysym 65480 }
|
|
F12 { set keysym 65481 }
|
|
BackSpace { set keysym 65288 }
|
|
default { set keysym [scan "$key" %c] }
|
|
}
|
|
set state 0
|
|
# not found any portable way to get modifier constants ...
|
|
if { [regexp {(Mod1|Alt)-} $d] } { set state [expr {$state +8}] }
|
|
if { [regexp Control- $d] } { set state [expr {$state +4}] }
|
|
if { [regexp Shift- $d] } { set state [expr {$state +1}] }
|
|
if { [regexp ButtonPress-1 $d] } { set state [expr {$state +0x100}] }
|
|
if { [regexp ButtonPress-2 $d] } { set state [expr {$state +0x200}] }
|
|
if { [regexp ButtonPress-3 $d] } { set state [expr {$state +0x400}] }
|
|
# puts "$state $key <${s}>"
|
|
if {[regexp ButtonPress- $d]} {
|
|
bind $win_path "<${s}>" "xschem callback %W %T %x %y 0 $key 0 $state"
|
|
} else {
|
|
if {![string compare $d {} ] } {
|
|
# puts "bind .drw <${s}> {}"
|
|
bind $win_path "<${s}>" {}
|
|
} else {
|
|
# puts "bind .drw <${s}> xschem callback %W %T %x %y $keysym 0 0 $state"
|
|
bind $win_path "<${s}>" "xschem callback %W %T %x %y $keysym 0 0 $state"
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
proc edit_file {filename} {
|
|
|
|
global editor
|
|
# since $editor can be an executable with options (gvim -f) I *need* to use eval
|
|
eval execute 0 $editor $filename
|
|
return {}
|
|
}
|
|
|
|
# ============================================================
|
|
# SIMULATION CONTROL
|
|
# ============================================================
|
|
|
|
# ============================================================
|
|
# SIMCONF
|
|
# ============================================================
|
|
|
|
## $N : netlist file full path (/home/schippes/simulations/opamp.spice)
|
|
## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp)
|
|
## $s : schematic name (opamp)
|
|
## $d : netlist directory
|
|
##
|
|
## Other global vars:
|
|
## netlist_dir
|
|
## terminal
|
|
## netlist_type can be obtained with [xschem get netlist_type]
|
|
proc save_sim_defaults {f} {
|
|
global sim netlist_dir terminal
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set a [catch {open $f w} fd]
|
|
if { $a } {
|
|
puts "save_sim_defaults: error opening file $f: $fd"
|
|
return
|
|
}
|
|
puts $fd {# set the list of tools known to xschem}
|
|
puts $fd {# Note that no spaces are allowed around commas in array keys}
|
|
puts $fd "set sim(tool_list) {$sim(tool_list)}"
|
|
puts $fd {}
|
|
foreach tool $sim(tool_list) {
|
|
puts $fd "#Specify the number of configured $tool tools."
|
|
puts $fd "set sim($tool,n) $sim($tool,n) ;# number of configured $tool tools"
|
|
puts $fd "# Specify the default $tool tool to use (first=0)"
|
|
puts $fd "set sim($tool,default) $sim($tool,default) ;# default $tool tool to launch"
|
|
puts $fd {}
|
|
for {set i 0} {$i < $sim($tool,n)} { incr i} {
|
|
puts $fd "# specify tool command (cmd), name (name), if tool must run\
|
|
in foreground and if exit status must be reported"
|
|
puts $fd "set sim($tool,$i,cmd) {$sim($tool,$i,cmd)}"
|
|
puts $fd "set sim($tool,$i,name) {$sim($tool,$i,name)}"
|
|
puts $fd "set sim($tool,$i,fg) $sim($tool,$i,fg)"
|
|
puts $fd "set sim($tool,$i,st) $sim($tool,$i,st)"
|
|
puts $fd {}
|
|
}
|
|
puts $fd {}
|
|
}
|
|
close $fd
|
|
}
|
|
|
|
proc load_recent_file {} {
|
|
global USER_CONF_DIR has_x
|
|
# recent files
|
|
set tctx::recentfile {}
|
|
if { [file exists $USER_CONF_DIR/recent_files] } {
|
|
if {[catch { source $USER_CONF_DIR/recent_files } err] } {
|
|
puts "Problems opening recent_files: $err"
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -message "Problems opening recent_files: $err" \
|
|
-icon warning -parent . -type ok
|
|
}
|
|
}
|
|
foreach i [info vars c_toolbar::c_t_*] {
|
|
if {[set ${i}(w)] != $c_toolbar::c_t(w) ||
|
|
[set ${i}(n)] != $c_toolbar::c_t(n)} {
|
|
array unset $i
|
|
}
|
|
}
|
|
set hash $c_toolbar::c_t(hash)
|
|
if { [info exists c_toolbar::c_t_$hash]} {
|
|
array set c_toolbar::c_t [array get c_toolbar::c_t_$hash]
|
|
}
|
|
}
|
|
}
|
|
|
|
proc update_recent_file {f {topwin {} } } {
|
|
global has_x
|
|
# puts "update recent file, f=$f, topwin=$topwin"
|
|
set old $tctx::recentfile
|
|
set tctx::recentfile {}
|
|
lappend tctx::recentfile $f
|
|
foreach i $old {
|
|
if {[abs_sym_path $i] ne [abs_sym_path $f]} {
|
|
lappend tctx::recentfile [abs_sym_path $i]
|
|
}
|
|
}
|
|
# tcl8.4 errors if using lreplace past the last element
|
|
if { [llength $tctx::recentfile] > 10 } {
|
|
set tctx::recentfile [lreplace $tctx::recentfile 10 end]
|
|
}
|
|
write_recent_file
|
|
if { [info exists has_x] } {setup_recent_menu $topwin}
|
|
}
|
|
|
|
proc write_recent_file {} {
|
|
global USER_CONF_DIR
|
|
|
|
# puts "write recent file tctx::recentfile=$tctx::recentfile"
|
|
set a [catch {open $USER_CONF_DIR/recent_files w} fd]
|
|
if { $a } {
|
|
puts "write_recent_file: error opening file $f: $fd"
|
|
return
|
|
}
|
|
puts $fd "set tctx::recentfile {$tctx::recentfile}"
|
|
|
|
if {[info exists c_toolbar::c_t]} {
|
|
set hash $c_toolbar::c_t(hash)
|
|
set c_toolbar::c_t(time) [clock seconds]
|
|
array set c_toolbar::c_t_$hash [array get c_toolbar::c_t]
|
|
foreach i [info vars c_toolbar::c_t_*] {
|
|
## old (~3 months) recent components will expire
|
|
if { [info exists [subst $i](time)]} {
|
|
if { [clock seconds] - [set [subst $i](time)] < 7500000} {
|
|
puts $fd "array set $i {[array get $i]}"
|
|
}
|
|
# puts "Age: [expr {[clock seconds] - [set [subst $i](time)]}]"
|
|
}
|
|
}
|
|
}
|
|
close $fd
|
|
}
|
|
|
|
proc setup_recent_menu { { topwin {} } } {
|
|
$topwin.menubar.file.recent delete 0 9
|
|
set i 0
|
|
if { [info exists tctx::recentfile] } {
|
|
foreach i $tctx::recentfile {
|
|
$topwin.menubar.file.recent add command \
|
|
-command "xschem load -gui {$i}" \
|
|
-label [file tail $i]
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
## ngspice:: raw file access functions
|
|
namespace eval ngspice {
|
|
# Create a variable inside the namespace
|
|
variable ngspice_data
|
|
variable op_point_read
|
|
}
|
|
|
|
proc ngspice::get_current {n} {
|
|
set raw_level [xschem get raw_level]
|
|
set path [string range [xschem get sch_path] 1 end]
|
|
# skip hierarchy components above the level where raw file has been loaded.
|
|
# node path names to look up in raw file begin from there.
|
|
if { [xschem get currsch] < $raw_level} { return {}}
|
|
set skip 0
|
|
while { $skip < $raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
set n [string tolower $n]
|
|
set prefix $n
|
|
# if xm1.rd is given get prefix (r) by removing path components (xm1.)
|
|
regsub {.*\.} $prefix {} prefix
|
|
set prefix [string range $prefix 0 0]
|
|
# puts "ngspice::get_current: path=$path n=$n prefix=$prefix"
|
|
set n $path$n
|
|
set currname i
|
|
if { ![sim_is_xyce] } { ;# ngspice
|
|
if {$path ne {} } {
|
|
set n $prefix.$n
|
|
}
|
|
if { ![regexp $prefix {[ve]}] } {
|
|
set n @$n
|
|
}
|
|
set n i($n)
|
|
} else { ;# xyce
|
|
if { [regexp {\[i[bcedgsb]\]$} $n] } {
|
|
regexp {\[(i[bcesdgb])\]$} $n curr1 currname
|
|
if { $prefix == {d} } {set currname i}
|
|
regsub {\[(i[bcesdgb])\]$} $n {} n
|
|
}
|
|
regsub {\[i\]} $n {} n
|
|
set n $currname\($n\)
|
|
}
|
|
# puts "ngspice::get_current --> $n"
|
|
set err [catch {set ngspice::ngspice_data($n)} res]
|
|
if { $err } {
|
|
set res {?}
|
|
}
|
|
# puts "$n --> $res"
|
|
return $res
|
|
}
|
|
|
|
proc ngspice::get_diff_voltage {n m} {
|
|
set raw_level [xschem get raw_level]
|
|
set path [string range [xschem get sch_path] 1 end]
|
|
if { [xschem get currsch] < $raw_level} { return {}}
|
|
# skip hierarchy components above the level where raw file has been loaded.
|
|
# node path names to look up in raw file begin from there.
|
|
set skip 0
|
|
while { $skip < $raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
set n [string tolower $n]
|
|
set m [string tolower $m]
|
|
set nn $path$n
|
|
set mm $path$m
|
|
set errn [catch {set ngspice::ngspice_data($nn)} resn]
|
|
if {$errn} {
|
|
set nn v(${path}${n})
|
|
set errn [catch {set ngspice::ngspice_data($nn)} resn]
|
|
}
|
|
set errm [catch {set ngspice::ngspice_data($mm)} resm]
|
|
if {$errm} {
|
|
set mm v(${path}${m})
|
|
set errm [catch {set ngspice::ngspice_data($mm)} resm]
|
|
}
|
|
if { $errn || $errm} {
|
|
set res {?}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
|
|
proc ngspice::get_voltage {n} {
|
|
set raw_level [xschem get raw_level]
|
|
set path [string range [xschem get sch_path] 1 end]
|
|
if { [xschem get currsch] < $raw_level} { return {}}
|
|
# skip hierarchy components above the level where raw file has been loaded.
|
|
# node path names to look up in raw file begin from there.
|
|
set skip 0
|
|
while { $skip < $raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
set n [string tolower $n]
|
|
# puts "ngspice::get_voltage: path=$path n=$n"
|
|
set node $path$n
|
|
# puts "ngspice::get_voltage: trying $node"
|
|
set err [catch {set ngspice::ngspice_data($node)} res]
|
|
if {$err} {
|
|
set node v(${path}${n})
|
|
# puts "ngspice::get_voltage: trying $node"
|
|
set err [catch {set ngspice::ngspice_data($node)} res]
|
|
}
|
|
if { $err } {
|
|
set res {?}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
proc update_schematic_header {} {
|
|
set tctx::retval [xschem get header_text]
|
|
text_line {Header/License text:} 0 header
|
|
if { $tctx::rcode ne {}} {
|
|
xschem set header_text $tctx::retval
|
|
}
|
|
}
|
|
|
|
proc ngspice::get_node {n} {
|
|
set raw_level [xschem get raw_level]
|
|
set path [string range [xschem get sch_path] 1 end]
|
|
if { [xschem get currsch] < $raw_level} { return {}}
|
|
# skip hierarchy components above the level where raw file has been loaded.
|
|
# node path names to look up in raw file begin from there.
|
|
set skip 0
|
|
while { $skip < $raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
set n [string tolower $n]
|
|
# n may contain $path, so substitute its value
|
|
set n [ subst -nocommand $n ]
|
|
set err [catch {set ngspice::ngspice_data($n)} res]
|
|
if { $err } {
|
|
set res {?}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
## end ngspice:: functions
|
|
|
|
# test if currently set simulator is ngspice
|
|
proc sim_is_ngspice {} {
|
|
global sim netlist_type
|
|
|
|
set_sim_defaults
|
|
|
|
if {$netlist_type eq {spice} && [info exists sim(spice,default)] } {
|
|
set idx $sim(spice,default)
|
|
if { [regexp {ngspice} $sim(spice,$idx,cmd)] } {
|
|
return 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
# test if currently set simulator is Xyce
|
|
proc sim_is_Xyce {} {
|
|
return [sim_is_xyce]
|
|
}
|
|
|
|
proc sim_is_xyce {} {
|
|
global sim netlist_type
|
|
|
|
set_sim_defaults
|
|
|
|
if {$netlist_type eq {spice} && [info exists sim(spice,default)] } {
|
|
set idx $sim(spice,default)
|
|
if { [regexp {[xX]yce} $sim(spice,$idx,cmd)] } {
|
|
return 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
proc sim_is_vacask {} {
|
|
global sim netlist_type
|
|
|
|
set_sim_defaults
|
|
|
|
if {$netlist_type eq {spectre} && [info exists sim(spectre,default)] } {
|
|
set idx $sim(spectre,default)
|
|
if { [regexp {vacask} $sim(spectre,$idx,cmd)] } {
|
|
return 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
# tests if file f exists. One level of global scope 'subst' is done on f
|
|
# to expand global variables / commands catching errors.
|
|
# example:
|
|
# % set b {$env(HOME)/.bashrc}
|
|
# $env(HOME)/.bashrc
|
|
# % file_exists $b
|
|
# 1
|
|
# %
|
|
# %
|
|
# % set b {$env(HOMExx)/.bashrc}
|
|
# $env(HOMExx)/.bashrc
|
|
# % file_exists $b
|
|
# 0
|
|
# %
|
|
proc file_exists {f} {
|
|
set ret 0
|
|
set r [catch "uplevel #0 {subst $f}" res]
|
|
if {$r == 0} {
|
|
if {[file exists $res]} { set ret 1}
|
|
}
|
|
return $ret
|
|
}
|
|
|
|
# wrapper to "xschem list_tokens" comand to handle non list results
|
|
# usually as a result of malformed input strings
|
|
proc list_tokens {s} {
|
|
set res [xschem list_tokens $s 0]
|
|
|
|
|
|
if { [info tclversion] > 8.4 } {
|
|
if { [string is list $res]} {
|
|
return $res
|
|
} else {
|
|
return [split $res]
|
|
}
|
|
} else {
|
|
if {![catch {llength $res}]} {
|
|
return $res
|
|
} else {
|
|
return [split $res]
|
|
}
|
|
}
|
|
}
|
|
|
|
# generates a proper list, trimming multiple separators
|
|
proc tolist {s} {
|
|
set s [string trim $s]
|
|
regsub -all {[\t\n ]+} $s { } s
|
|
|
|
|
|
if { [info tclversion] > 8.4 } {
|
|
if { [string is list $s]} {
|
|
return $s
|
|
} else {
|
|
return [split $s]
|
|
}
|
|
} else {
|
|
if {![catch {llength $s}]} {
|
|
return $s
|
|
} else {
|
|
return [split $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 {}}} {
|
|
global sim terminal USER_CONF_DIR has_x bespice_listen_port env OS
|
|
if {$reset eq {reset} } { file delete ${USER_CONF_DIR}/simrc }
|
|
if { $reset eq {} } {
|
|
set failure 0
|
|
if { [info exists has_x] && [winfo exists .sim] } {
|
|
foreach tool $sim(tool_list) {
|
|
for {set i 0} {$i < $sim($tool,n)} { incr i} {
|
|
set sim($tool,$i,cmd) [.sim.topf.f.scrl.center.$tool.r.$i.cmd get 1.0 {end - 1 chars}]
|
|
}
|
|
}
|
|
}
|
|
if { ![info exists sim] } {
|
|
if { [file exists ${USER_CONF_DIR}/simrc] } {
|
|
# get conf from simrc
|
|
if { [catch {source ${USER_CONF_DIR}/simrc} err]} {
|
|
puts "Problems opening simrc file: $err"
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -message "Problems opening simrc file: $err" -icon warning \
|
|
-parent [xschem get topwindow] -type ok
|
|
}
|
|
set failure 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if {( $reset eq {reset} ) || ![info exists sim] || $failure} {
|
|
if {[info exists sim]} {unset sim}
|
|
# no simrc, set a reasonable default
|
|
set sim(tool_list) {spice spicewave spectre verilog verilogwave vhdl vhdlwave}
|
|
if {$OS == "Windows"} {
|
|
set_ne sim(spice,0,cmd) {ngspice -i "$N" -a}
|
|
} else {
|
|
set_ne sim(spice,0,cmd) {$terminal -e {ngspice -i "$N" -a || sh}}
|
|
}
|
|
# can not use set_ne as variables bound to entry widgets always exist if widget exists
|
|
set sim(spice,0,name) {Ngspice interactive}
|
|
set_ne sim(spice,0,fg) 0
|
|
set_ne sim(spice,0,st) 0
|
|
|
|
|
|
set_ne sim(spice,1,cmd) {ngspice "$N" -a}
|
|
set sim(spice,1,name) {Ngspice Control mode}
|
|
set_ne sim(spice,1,fg) 0
|
|
set_ne sim(spice,1,st) 1
|
|
|
|
|
|
set_ne sim(spice,2,cmd) {ngspice -b -r "$n.raw" "$N"}
|
|
set sim(spice,2,name) {Ngspice batch}
|
|
set_ne sim(spice,2,fg) 0
|
|
set_ne sim(spice,2,st) 1
|
|
|
|
set_ne sim(spice,3,cmd) {Xyce "$N"}
|
|
set sim(spice,3,name) {Xyce batch}
|
|
set_ne sim(spice,3,fg) 0
|
|
set_ne sim(spice,3,st) 1
|
|
|
|
set_ne sim(spice,4,cmd) {mpirun /path/to/parallel/Xyce "$N"}
|
|
set sim(spice,4,name) {Xyce parallel batch}
|
|
set_ne sim(spice,4,fg) 0
|
|
set_ne sim(spice,4,st) 1
|
|
|
|
# number of configured spice simulators, and default one
|
|
set_ne sim(spice,n) 5
|
|
set_ne sim(spice,default) 0
|
|
|
|
### spice wave view
|
|
set_ne sim(spicewave,0,cmd) {gaw "$n.raw" }
|
|
set sim(spicewave,0,name) {Gaw viewer}
|
|
set_ne sim(spicewave,0,fg) 0
|
|
set_ne sim(spicewave,0,st) 0
|
|
|
|
set_ne sim(spicewave,1,cmd) {$terminal -e ngspice}
|
|
set sim(spicewave,1,name) {Ngspice Viewer}
|
|
set_ne sim(spicewave,1,fg) 0
|
|
set_ne sim(spicewave,1,st) 0
|
|
|
|
set_ne sim(spicewave,2,cmd) {rawtovcd -v 1.5 "$n.raw" > "$n.vcd" && gtkwave "$n.vcd" "$n.sav" 2>/dev/null}
|
|
set sim(spicewave,2,name) {Rawtovcd}
|
|
set_ne sim(spicewave,2,fg) 0
|
|
set_ne sim(spicewave,2,st) 0
|
|
|
|
# A server communicating with bespice wave was set up in the function setup_tcp_bespice().
|
|
# This server is listening on port $bespice_listen_port.
|
|
set_ne sim(spicewave,3,cmd) {$env(HOME)/analog_flavor_eval/bin/bspwave --socket localhost $bespice_listen_port "$n.raw" }
|
|
set sim(spicewave,3,name) {Bespice wave}
|
|
set_ne sim(spicewave,3,fg) 0
|
|
set_ne sim(spicewave,3,st) 0
|
|
# number of configured spice wave viewers, and default one
|
|
set_ne sim(spicewave,n) 4
|
|
set_ne sim(spicewave,default) 0
|
|
|
|
### spectre (vacask simulator)
|
|
set_ne sim(spectre,0,cmd) {vacask "$N"}
|
|
set sim(spectre,0,name) {Vacask}
|
|
set_ne sim(spectre,0,fg) 0
|
|
set_ne sim(spectre,0,st) 1
|
|
|
|
# number of configured spectre simulators, and default one
|
|
set_ne sim(spectre,n) 1
|
|
set_ne sim(spectre,default) 0
|
|
|
|
### icarus verilog
|
|
set_ne sim(verilog,0,cmd) {sh -c "iverilog -o .verilog_object -g2012 '$N' && vvp .verilog_object"}
|
|
set sim(verilog,0,name) {Icarus verilog}
|
|
set_ne sim(verilog,0,fg) 0
|
|
set_ne sim(verilog,0,st) 1
|
|
|
|
### verilator
|
|
set_ne sim(verilog,1,cmd) {sh -c "verilator -Wno-fatal --binary --timing --cc --Mdir obj_$s -o $s '$N' --trace \
|
|
&& ./obj_$s/$s"}
|
|
set sim(verilog,1,name) {Verilator}
|
|
set_ne sim(verilog,1,fg) 0
|
|
set_ne sim(verilog,1,st) 1
|
|
|
|
# number of configured verilog simulators, and default one
|
|
set_ne sim(verilog,n) 2
|
|
set_ne sim(verilog,default) 0
|
|
|
|
### verilog wave view
|
|
set_ne sim(verilogwave,0,cmd) {gtkwave dumpfile.vcd "$N.sav" 2>/dev/null}
|
|
set sim(verilogwave,0,name) {Gtkwave}
|
|
set_ne sim(verilogwave,0,fg) 0
|
|
set_ne sim(verilogwave,0,st) 0
|
|
# number of configured verilog wave viewers, and default one
|
|
set_ne sim(verilogwave,n) 1
|
|
set_ne sim(verilogwave,default) 0
|
|
|
|
### vhdl
|
|
set_ne sim(vhdl,0,cmd) {ghdl -c --ieee=synopsys -fexplicit "$N" -r "$s" "--wave=$n.ghw"}
|
|
set sim(vhdl,0,name) {Ghdl}
|
|
set_ne sim(vhdl,0,fg) 0
|
|
set_ne sim(vhdl,0,st) 1
|
|
# number of configured vhdl simulators, and default one
|
|
set_ne sim(vhdl,n) 1
|
|
set_ne sim(vhdl,default) 0
|
|
|
|
### vhdl wave view
|
|
set_ne sim(vhdlwave,0,cmd) {gtkwave "$n.ghw" "$N.sav" 2>/dev/null}
|
|
set sim(vhdlwave,0,name) {Gtkwave}
|
|
set_ne sim(vhdlwave,0,fg) 0
|
|
set_ne sim(vhdlwave,0,st) 0
|
|
# number of configured vhdl wave viewers, and default one
|
|
set_ne sim(vhdlwave,n) 1
|
|
set_ne sim(vhdlwave,default) 0
|
|
}
|
|
}
|
|
|
|
proc simconf_reset {} {
|
|
global sim
|
|
|
|
set answer [tk_messageBox -message "Warning: delete simulation configuration file and reset to default?" \
|
|
-icon warning -parent .sim -type okcancel]
|
|
if { $answer eq {ok}} {
|
|
set_sim_defaults reset
|
|
foreach tool $sim(tool_list) {
|
|
for {set i 0} { $i < $sim($tool,n)} {incr i} {
|
|
.sim.topf.f.scrl.center.$tool.r.$i.cmd delete 1.0 end
|
|
.sim.topf.f.scrl.center.$tool.r.$i.cmd insert 1.0 $sim($tool,$i,cmd)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc simconf_saveconf {scrollframe} {
|
|
global sim USER_CONF_DIR
|
|
foreach tool $sim(tool_list) {
|
|
for {set i 0} { $i < $sim($tool,n)} {incr i} {
|
|
set sim($tool,$i,cmd) [${scrollframe}.center.$tool.r.$i.cmd get 1.0 {end - 1 chars}]
|
|
}
|
|
}
|
|
# destroy .sim
|
|
# xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
save_sim_defaults ${USER_CONF_DIR}/simrc
|
|
# puts "saving simrc"
|
|
}
|
|
|
|
proc simconf {} {
|
|
global sim USER_CONF_DIR simconf_default_geometry
|
|
|
|
if {[winfo exists .sim]} {
|
|
destroy .sim
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
set_sim_defaults
|
|
toplevel .sim -class Dialog
|
|
wm title .sim {Simulation Configuration}
|
|
wm geometry .sim 790x370
|
|
# wm transient .sim [xschem get topwindow]
|
|
frame .sim.topf
|
|
set scrollframe [sframe .sim.topf]
|
|
frame ${scrollframe}.center
|
|
frame .sim.bottom
|
|
pack ${scrollframe}.center -fill both -expand yes
|
|
set bg(0) {#dddddd}
|
|
set bg(1) {#aaaaaa}
|
|
set toggle 0
|
|
foreach tool $sim(tool_list) {
|
|
frame ${scrollframe}.center.$tool
|
|
label ${scrollframe}.center.$tool.l -width 12 -text $tool -background $bg($toggle) -fg black
|
|
frame ${scrollframe}.center.$tool.r
|
|
pack ${scrollframe}.center.$tool -fill both -expand yes
|
|
pack ${scrollframe}.center.$tool.l -fill y -side left
|
|
pack ${scrollframe}.center.$tool.r -fill both -expand yes
|
|
for {set i 0} { $i < $sim($tool,n)} {incr i} {
|
|
frame ${scrollframe}.center.$tool.r.$i
|
|
pack ${scrollframe}.center.$tool.r.$i -fill x -expand yes
|
|
entry ${scrollframe}.center.$tool.r.$i.lab -textvariable sim($tool,$i,name) -width 18 \
|
|
-background $bg($toggle) -fg black
|
|
entry_replace_selection ${scrollframe}.center.$tool.r.$i.lab
|
|
radiobutton ${scrollframe}.center.$tool.r.$i.radio -background $bg($toggle) -fg black \
|
|
-selectcolor white -variable sim($tool,default) -value $i
|
|
text ${scrollframe}.center.$tool.r.$i.cmd -undo 1 -width 20 -height 3 -wrap none -background $bg($toggle) -fg black
|
|
${scrollframe}.center.$tool.r.$i.cmd insert 1.0 $sim($tool,$i,cmd)
|
|
checkbutton ${scrollframe}.center.$tool.r.$i.fg -text Fg -variable sim($tool,$i,fg) \
|
|
-selectcolor white -background $bg($toggle) -fg black
|
|
checkbutton ${scrollframe}.center.$tool.r.$i.st -text Status -variable sim($tool,$i,st) \
|
|
-selectcolor white -background $bg($toggle) -fg black
|
|
pack ${scrollframe}.center.$tool.r.$i.lab -side left -fill y
|
|
pack ${scrollframe}.center.$tool.r.$i.radio -side left -fill y
|
|
pack ${scrollframe}.center.$tool.r.$i.cmd -side left -fill x -expand yes
|
|
pack ${scrollframe}.center.$tool.r.$i.fg -side left -fill y
|
|
pack ${scrollframe}.center.$tool.r.$i.st -side left -fill y
|
|
}
|
|
incr toggle
|
|
set toggle [expr {$toggle %2}]
|
|
}
|
|
button .sim.bottom.cancel -text Cancel -command {
|
|
destroy .sim
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
button .sim.bottom.help -text Help -command {
|
|
viewdata {In this dialog box you set the commands xschem uses to launch the
|
|
various external tools. The commands go through a tcl 'subst' round
|
|
to do TCL variable and command substitution, so you may use the TCL
|
|
'{' and '}' characters for grouping arguments with spaces.
|
|
Xschem has 3 main netlisting modes (spice, verilog, vhdl) and for each
|
|
netlisting mode some simulators and some viewers can be defined.
|
|
The following variables are defined and will get substituted by
|
|
XSCHEM before sending commands to the shell:
|
|
|
|
- N: complete filename of netlist for current netlisting mode
|
|
(example: /home/schippes/.xschem/simulations/opamp.spice for spice)
|
|
(example: /home/schippes/.xschem/simulations/opamp.v for verilog)
|
|
- n: complete filename of netlist as above but without extension
|
|
(example: /home/schippes/.xschem/simulations/opamp)
|
|
- S: full pathname of schematic being used (example:
|
|
/home/schippes/.xschem/xschem_library/opamp.sch)
|
|
- s: name of schematic being used (example: opamp)
|
|
- d: simulation directory (example: /home/schippes/.xschem/simulations)
|
|
- terminal: terminal to be used for applications that need to be
|
|
executed in terminal (example: $terminal -e ngspice -i "$N" -a)
|
|
|
|
If for a given tool there are multiple rows then the radiobutton
|
|
tells which one will be called by xschem.
|
|
Variables should be used with the usual substitution character $: $n, $N, etc.
|
|
Foreground (Fg) checkbutton tells xschem to wait for child process to finish.
|
|
Status checkbutton tells xschem to report a status dialog (stdout, stderr,
|
|
exit status) when process finishes.
|
|
|
|
If 'Accept, Save and Close' is pressed then changes made in the dialog box
|
|
entries will be saved in ~/.xschem/simrc, changes will be persistent.
|
|
|
|
If 'Accept, no Save and Close' is pressed then the changes are kept in
|
|
memory and dialog is closed without writing to a file,
|
|
if xschem is restarted changes will be lost.
|
|
|
|
If no ~/.xschem/simrc is present then a minimal default setup is presented.
|
|
To reset to default use the corresponding button or just delete the
|
|
~/.xschem/simrc file manually.
|
|
} ro
|
|
}
|
|
button .sim.bottom.ok -text {Accept, Save and Close} -command "
|
|
set_sim_defaults
|
|
simconf_saveconf $scrollframe
|
|
destroy .sim
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
"
|
|
button .sim.bottom.reset -text {Reset to default} -command {
|
|
simconf_reset
|
|
}
|
|
button .sim.bottom.close -text {Accept, no Save and Close} -command {
|
|
set_sim_defaults
|
|
destroy .sim
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
wm protocol .sim WM_DELETE_WINDOW {
|
|
set_sim_defaults
|
|
destroy .sim
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
pack .sim.bottom.cancel -side left -anchor w
|
|
pack .sim.bottom.help -side left
|
|
#foreach tool $sim(tool_list) {
|
|
# button .sim.bottom.add${tool} -text +${tool} -command "
|
|
# simconf_add $tool
|
|
# destroy .sim
|
|
# xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
# save_sim_defaults ${USER_CONF_DIR}/simrc
|
|
## simconf
|
|
# "
|
|
# pack .sim.bottom.add${tool} -side left
|
|
#}
|
|
pack .sim.bottom.ok -side right -anchor e
|
|
pack .sim.bottom.close -side right
|
|
pack .sim.bottom.reset -side right
|
|
pack .sim.topf -fill both -expand yes
|
|
pack .sim.bottom -fill x
|
|
if { [info exists simconf_default_geometry]} {
|
|
wm geometry .sim "${simconf_default_geometry}"
|
|
}
|
|
|
|
bind .sim.topf.f <Configure> {sframeyview .sim.topf}
|
|
bind .sim <Configure> {
|
|
set simconf_default_geometry [wm geometry .sim]
|
|
}
|
|
bind .sim <ButtonPress-4> { sframeyview .sim.topf scroll -0.2}
|
|
bind .sim <ButtonPress-5> { sframeyview .sim.topf scroll 0.2}
|
|
sframeyview .sim.topf place
|
|
set maxsize [expr {[winfo height ${scrollframe}] + [winfo height .sim.bottom]}]
|
|
wm maxsize .sim 9999 $maxsize
|
|
# tkwait window .sim
|
|
}
|
|
|
|
proc simconf_add {tool} {
|
|
global sim
|
|
set n $sim($tool,n)
|
|
set sim($tool,$n,cmd) {}
|
|
set sim($tool,$n,name) {}
|
|
set sim($tool,$n,fg) 0
|
|
set sim($tool,$n,st) 0
|
|
incr sim($tool,n)
|
|
}
|
|
|
|
|
|
############ cellview
|
|
# proc cellview prints symbol bindings (default binding or "schematic" attr in symbol)
|
|
# of all symbols used in current and sub schematics.
|
|
# the derived_symbols parameter of cellview should be either empty or 'derived_symbols'
|
|
proc cellview_setlabels {w symbol derived_symbol} {
|
|
global dark_gui_colorscheme netlist_type
|
|
if {$dark_gui_colorscheme} {
|
|
set instfg orange1
|
|
set symfg SeaGreen1
|
|
set symbg SeaGreen4
|
|
set missingbg IndianRed4
|
|
} else {
|
|
set instfg orange4
|
|
set symfg SeaGreen4
|
|
set symbg SeaGreen1
|
|
set missingbg IndianRed1
|
|
}
|
|
set save_netlist_type [xschem get netlist_type]
|
|
set current [xschem get current_name]
|
|
set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2]
|
|
set abs_sch [xschem get_sch_from_sym -1 $symbol]
|
|
set sym_sch [rel_sym_path $abs_sch]
|
|
set default_sch [add_ext $symbol .sch]
|
|
set new_sch [$w get]
|
|
$w configure -fg [option get . foreground {}]
|
|
$w configure -bg [option get . background {}]
|
|
if { $derived_symbol} {
|
|
$w configure -fg $instfg
|
|
} elseif {$sym_spice_sym_def ne {} } {
|
|
$w configure -fg $symfg
|
|
}
|
|
if { $sym_spice_sym_def eq {}} {
|
|
if { ![file exists [abs_sym_path [$w get]]] } {
|
|
$w configure -bg $missingbg
|
|
} elseif {$new_sch ne $default_sch } {
|
|
$w configure -bg $symbg
|
|
}
|
|
}
|
|
puts ===============
|
|
if {$sym_sch ne $new_sch && $sym_spice_sym_def eq {}} {
|
|
puts "Changing schematic attribute in symbol"
|
|
xschem load -keep_symbols -nodraw -noundoreset $symbol
|
|
set oldprop [xschem get schsymbolprop]
|
|
if { $new_sch eq $default_sch } {
|
|
set newprop [xschem subst_tok $oldprop schematic {}] ;# delete schematic attr in symbol
|
|
} else {
|
|
set newprop [xschem subst_tok $oldprop schematic $new_sch]
|
|
}
|
|
xschem set schsymbolprop $newprop
|
|
xschem set_modify 3 ;# set only modified flag to force a save, do not update window/tab titles
|
|
xschem save fast
|
|
# no! cellview_setlabels called from cellview inside a "foreach {i symbol} $syms {...}"
|
|
# xschem remove_symbols ;# purge all symbols to force a reload from disk
|
|
xschem load -keep_symbols -nodraw -noundoreset $current
|
|
set netlist_type $save_netlist_type
|
|
xschem set netlist_type $netlist_type
|
|
xschem netlist -keep_symbols -noalert;# traverse the hierarchy and retain all encountered symbols
|
|
puts "get netlist"
|
|
}
|
|
puts sym_sch=$sym_sch
|
|
puts default_sch=$default_sch
|
|
puts new_sch=$new_sch
|
|
puts symbol=$symbol
|
|
}
|
|
|
|
proc cellview_edit_item {symbol w} {
|
|
global netlist_type
|
|
set save_netlist_type [xschem get netlist_type]
|
|
set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2]
|
|
if {[xschem is_generator [$w get]]} {
|
|
set f [$w get]
|
|
regsub {\(.*} $f {} f
|
|
textwindow [abs_sym_path $f]
|
|
} elseif { $sym_spice_sym_def eq {}} {
|
|
xschem load_new_window [$w get]
|
|
} else {
|
|
set current [xschem get current_name]
|
|
set old_sym_def [xschem getprop symbol $symbol spice_sym_def 2]
|
|
set new_sym_def [editdata $sym_spice_sym_def {Symbol spice_sym_def attribute}]
|
|
if {$new_sym_def ne $old_sym_def} {
|
|
xschem load -keep_symbols -nodraw -noundoreset $symbol
|
|
set oldprop [xschem get schsymbolprop]
|
|
set newprop [xschem subst_tok $oldprop spice_sym_def $new_sym_def]
|
|
xschem set schsymbolprop $newprop
|
|
xschem set_modify 3 ;# set only modified flag to force a save, do not update window/tab titles
|
|
xschem save fast
|
|
puts "$symbol: updated spice_sym_def attribute"
|
|
xschem load -keep_symbols -nodraw -noundoreset $current
|
|
set netlist_type $save_netlist_type
|
|
xschem set netlist_type $netlist_type
|
|
xschem reload_symbols ;# update in-memory symbol data
|
|
}
|
|
}
|
|
}
|
|
|
|
proc cellview_edit_sym {w} {
|
|
set sym [$w cget -text]
|
|
set res [catch {xschem symbol_base_name $sym} base_name]
|
|
if {$res == 0} {
|
|
if {$base_name ne {}} {
|
|
set sym $base_name
|
|
}
|
|
}
|
|
xschem load_new_window $sym
|
|
}
|
|
|
|
# derived_symbols: empty or 'derived_symbols'
|
|
# upd: never set by caller (used iinternally to update)
|
|
proc cellview { {derived_symbols {}} {upd 0}} {
|
|
global nolist_libs dark_gui_colorscheme netlist_type
|
|
|
|
set save_netlist_type [xschem get netlist_type]
|
|
|
|
if {$dark_gui_colorscheme} {
|
|
set instfg orange1
|
|
set symfg SeaGreen1
|
|
set symbg SeaGreen4
|
|
set missingbg IndianRed4
|
|
} else {
|
|
set instfg orange4
|
|
set symfg SeaGreen4
|
|
set symbg SeaGreen1
|
|
set missingbg IndianRed1
|
|
}
|
|
if {[info tclversion] >= 8.5} {
|
|
set font {TkDefaultFont 10 bold} ;# Monospace
|
|
} else {
|
|
set font fixed
|
|
}
|
|
|
|
set netlist_type $save_netlist_type
|
|
xschem set netlist_type $netlist_type
|
|
xschem reload_symbols ;# purge unused symbols
|
|
xschem netlist -keep_symbols -noalert;# traverse the hierarchy and retain all encountered symbols
|
|
if {!$upd} {
|
|
catch {destroy .cv}
|
|
toplevel .cv
|
|
wm geometry .cv 800x200
|
|
update
|
|
raise .cv
|
|
frame .cv.top
|
|
label .cv.top.sym -text { SYMBOL} -width 30 -bg grey60 -anchor w -padx 4 -font $font
|
|
label .cv.top.sch -text SCHEMATIC -width 45 -bg grey60 -anchor w -padx 4 -font $font
|
|
label .cv.top.pad -text { } -width 4 -bg grey60 -font $font
|
|
pack .cv.top.sym .cv.top.sch -side left -fill x -expand 1
|
|
pack .cv.top.pad -side left -fill x
|
|
frame .cv.center
|
|
set sf [sframe .cv.center]
|
|
} else {
|
|
set sf .cv.center.f.scrl
|
|
}
|
|
|
|
set syms [join [lsort -index 1 [xschem symbols $derived_symbols]]]
|
|
# puts "syms=$syms"
|
|
foreach {i symbol} $syms {
|
|
if { [catch {set base_name [xschem symbol_base_name $symbol]}] } {
|
|
set base_name $symbol
|
|
}
|
|
# puts "i=$i, symbol=$symbol"
|
|
set derived_symbol 0
|
|
if {$base_name ne {}} {
|
|
set derived_symbol 1
|
|
}
|
|
if { [catch {xschem get_sch_from_sym -1 $symbol} abs_sch ]} {
|
|
set abs_sch [abs_sym_path [add_ext $symbol .sch]]
|
|
}
|
|
if {$derived_symbol} {
|
|
set abs_sym [abs_sym_path $base_name]
|
|
} else {
|
|
set abs_sym [abs_sym_path $symbol]
|
|
}
|
|
set skip 0
|
|
foreach j $nolist_libs {
|
|
if {[regexp $j $abs_sym]} {
|
|
set skip 1
|
|
break
|
|
}
|
|
}
|
|
if {$skip} { continue }
|
|
set sym_sch [rel_sym_path $abs_sch]
|
|
if {[catch {xschem getprop symbol $symbol type} type]} {
|
|
puts "error: $symbol not found: $type"
|
|
}
|
|
set type [xschem getprop symbol $symbol type]
|
|
set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2]
|
|
if {$type eq {subcircuit}} {
|
|
|
|
if {!$upd} {
|
|
frame $sf.f$i
|
|
pack $sf.f$i -side top -fill x
|
|
label $sf.f$i.l -text $symbol -width 30 -anchor w -padx 4 -borderwidth 1 \
|
|
-relief sunken -pady 1 -font $font
|
|
if {$derived_symbol} {
|
|
$sf.f$i.l configure -fg $instfg
|
|
}
|
|
# puts $sf.f$i.s
|
|
entry $sf.f$i.s -width 45 -borderwidth 1 -relief sunken -font $font
|
|
button $sf.f$i.sym -text Sym -padx 4 -borderwidth 1 -pady 0 -font $font \
|
|
-command "cellview_edit_sym $sf.f$i.l"
|
|
button $sf.f$i.sch -text Sch -padx 4 -borderwidth 1 -pady 0 -font $font \
|
|
-command "cellview_edit_item $symbol $sf.f$i.s"
|
|
if {$sym_spice_sym_def eq {}} {
|
|
$sf.f$i.s insert 0 $sym_sch
|
|
} else {
|
|
if {$derived_symbol} {
|
|
$sf.f$i.s insert 0 {defined in instance spice_sym_def}
|
|
} else {
|
|
$sf.f$i.s insert 0 {defined in symbol spice_sym_def}
|
|
}
|
|
}
|
|
}
|
|
|
|
if {[xschem is_generator [ $sf.f$i.s get]]} {
|
|
set f [ $sf.f$i.s get]
|
|
regsub {\(.*} $f {} f
|
|
} elseif { $sym_spice_sym_def eq {}} {
|
|
set f [abs_sym_path [$sf.f$i.s get]]
|
|
} else {
|
|
set ff [split $sym_spice_sym_def \n]
|
|
if {[llength $ff] > 5} {
|
|
set ff [lrange $ff 0 4]
|
|
lappend ff ...
|
|
}
|
|
set f [join $ff \n]
|
|
}
|
|
balloon $sf.f$i.s $f
|
|
|
|
cellview_setlabels $sf.f$i.s $symbol $derived_symbol
|
|
if {!$upd} {
|
|
pack $sf.f$i.l $sf.f$i.s -side left -fill x -expand 1
|
|
pack $sf.f$i.sch $sf.f$i.sym -side left
|
|
}
|
|
}
|
|
}
|
|
|
|
if {$upd} {return}
|
|
|
|
frame .cv.bottom
|
|
button .cv.bottom.update -text Update -command "cellview [list $derived_symbols] 1; xschem reload_symbols"
|
|
pack .cv.bottom.update -side left
|
|
label .cv.bottom.status -text {STATUS LINE}
|
|
pack .cv.bottom.status -fill x -expand yes
|
|
pack .cv.top -side top -fill x -expand no
|
|
pack .cv.center -side top -fill both -expand yes
|
|
pack .cv.bottom -side top -fill x -expand no
|
|
sframeyview .cv.center place
|
|
set maxsize [expr {[winfo height ${sf}] + [winfo height .cv.top] + [winfo height .cv.bottom]}]
|
|
wm maxsize .cv 9999 $maxsize
|
|
bind .cv.center.f <Configure> {sframeyview .cv.center}
|
|
bind .cv <ButtonPress-4> { sframeyview .cv.center scroll -0.1}
|
|
bind .cv <ButtonPress-5> { sframeyview .cv.center scroll 0.1}
|
|
bind .cv <Escape> {destroy .cv}
|
|
}
|
|
############ /cellview
|
|
|
|
############ traversal
|
|
proc traversal_setlabels {w parent_sch instname inst_sch sym_sch default_sch
|
|
inst_spice_sym_def sym_spice_sym_def} {
|
|
global traversal dark_gui_colorscheme netlist_type
|
|
set sf .trav.center.f.scrl
|
|
|
|
set save_netlist_type [xschem get netlist_type]
|
|
# puts "traversal_setlabels: $w parent: |$parent_sch| inst: $instname def: $sym_sch $inst_sch --> [$w get]"
|
|
# update schematic
|
|
if {$parent_sch ne {} && $sym_spice_sym_def eq {} && $inst_spice_sym_def eq {} } {
|
|
set current [xschem get current_name]
|
|
if { $inst_sch ne [$w get] } {
|
|
xschem load -undoreset -nodraw $parent_sch
|
|
if { [$w get] eq $sym_sch} {
|
|
xschem setprop -fast instance $instname schematic ;# remove schematic attr on instance
|
|
} else {
|
|
xschem setprop -fast instance $instname schematic [$w get] ;# set schematic attr on instance
|
|
}
|
|
xschem set_modify 3 ;# set only modified flag to force a save, do not update window/tab titles
|
|
xschem save fast
|
|
set inst_sch [$w get]
|
|
# puts "inst_sch set to: $inst_sch"
|
|
xschem load -undoreset -nodraw $current
|
|
set netlist_type $save_netlist_type
|
|
xschem set netlist_type $netlist_type
|
|
}
|
|
}
|
|
# /update schematic
|
|
if {$dark_gui_colorscheme} {
|
|
set instfg orange1
|
|
set symfg SeaGreen1
|
|
set instbg orange4
|
|
set symbg SeaGreen4
|
|
set missingbg IndianRed4
|
|
} else {
|
|
set instfg orange4
|
|
set symfg SeaGreen4
|
|
set instbg Orange1
|
|
set symbg SeaGreen1
|
|
set missingbg IndianRed1
|
|
}
|
|
$w configure -fg [option get . foreground {}]
|
|
$w configure -bg [option get . background {}]
|
|
if { $sym_spice_sym_def ne {}} {
|
|
$w configure -fg $symfg
|
|
} elseif {$inst_spice_sym_def ne {}} {
|
|
$w configure -fg $instfg
|
|
} elseif { ![file exists [abs_sym_path [$w get]]] } {
|
|
$w configure -bg $missingbg
|
|
} else {
|
|
if {[$w get] eq $default_sch} {
|
|
# ....
|
|
} elseif {[$w get] eq $sym_sch} {
|
|
$w configure -bg $symbg
|
|
} elseif {[$w get] eq $inst_sch} {
|
|
$w configure -bg $instbg
|
|
}
|
|
}
|
|
}
|
|
|
|
# This proc traverses the hierarchy and prints all instances in design.
|
|
proc traversal {{only_subckts 1} {all_hierarchy 1}} {
|
|
global traversal keep_symbols
|
|
set traversal(only_subckts) $only_subckts
|
|
set traversal(all_hierarchy) $all_hierarchy
|
|
set traversal(cnt) 0
|
|
set save_keep $keep_symbols
|
|
set keep_symbols 1
|
|
xschem unselect_all
|
|
xschem set no_draw 1 ;# disable screen update
|
|
xschem set no_undo 1 ;# disable undo
|
|
|
|
if {[info tclversion] >= 8.5} {
|
|
set font {TkDefaultFont 10 bold} ;# Monospace
|
|
} else {
|
|
set font fixed
|
|
}
|
|
|
|
toplevel .trav
|
|
frame .trav.top
|
|
label .trav.top.inst -text {INSTANCE} -width 25 -bg grey60 -anchor w -padx 4 -font $font
|
|
label .trav.top.sym -text {SYMBOL} -width 30 -bg grey60 -anchor w -padx 4 -font $font
|
|
label .trav.top.sch -text SCHEMATIC -width 45 -bg grey60 -anchor w -padx 4 -font $font
|
|
label .trav.top.pad -text { } -bg grey60 -font $font
|
|
pack .trav.top.inst -side left -fill x -expand 1
|
|
pack .trav.top.sym .trav.top.sch -side left -fill x
|
|
pack .trav.top.pad -side left -fill x
|
|
frame .trav.center
|
|
set sf [sframe .trav.center]
|
|
hier_traversal 0 $only_subckts $all_hierarchy
|
|
xschem set no_draw 0
|
|
xschem set no_undo 0
|
|
set keep_symbols $save_keep
|
|
|
|
frame .trav.bottom
|
|
label .trav.bottom.status -text {STATUS LINE}
|
|
pack .trav.bottom.status -fill x -expand yes
|
|
pack .trav.top -side top -fill x -expand no
|
|
pack .trav.center -side top -fill both -expand yes
|
|
pack .trav.bottom -side top -fill x -expand no
|
|
sframeyview .trav.center place
|
|
set maxsize [expr {[winfo height ${sf}] + [winfo height .trav.top] + [winfo height .trav.bottom]}]
|
|
wm maxsize .trav 9999 $maxsize
|
|
bind .trav.center.f <Configure> {sframeyview .trav.center}
|
|
bind .trav <ButtonPress-4> { sframeyview .trav.center scroll -0.1}
|
|
bind .trav <ButtonPress-5> { sframeyview .trav.center scroll 0.1}
|
|
bind .trav <Escape> "
|
|
set traversal(geom) \[winfo geometry .trav\]
|
|
destroy .trav
|
|
"
|
|
if {[info exists traversal(geom)]} {
|
|
wm geometry .trav $traversal(geom)
|
|
} else {
|
|
wm geometry .trav 1200x400
|
|
}
|
|
update
|
|
set traversal(geom) [winfo geometry .trav]
|
|
return {}
|
|
}
|
|
|
|
# recursive procedure
|
|
proc hier_traversal {{level 0} {only_subckts 0} {all_hierarchy 1}} {
|
|
global nolist_libs traversal
|
|
|
|
if {[info tclversion] >= 8.5} {
|
|
set font {TkDefaultFont 10 bold} ;# Monospace
|
|
} else {
|
|
set font fixed
|
|
}
|
|
set parent_sch [xschem get current_name]
|
|
# puts $parent_sch
|
|
set sf .trav.center.f.scrl
|
|
set done_print 0
|
|
set schpath [xschem get sch_path]
|
|
set instances [xschem get instances]
|
|
set current_level [xschem get currsch]
|
|
for {set i 0} { $i < $instances} { incr i} {
|
|
# puts "hier_traversal: i=$i, current_level=$current_level, parent_sch=$parent_sch"
|
|
set instname [xschem getprop instance $i name]
|
|
set symbol [xschem getprop instance $i cell::name]
|
|
set default_sch [add_ext $symbol .sch]
|
|
set sym_sch [rel_sym_path [xschem get_sch_from_sym -1 $symbol]]
|
|
set abs_symbol [abs_sym_path $symbol]
|
|
set type [xschem getprop symbol $symbol type]
|
|
set schematic [xschem get_sch_from_sym $i]
|
|
set sch_exists [expr {[file exists $schematic] ? {} : {**missing**}}]
|
|
set inst_sch [rel_sym_path $schematic]
|
|
set sch_rootname [file tail [file rootname $inst_sch]]
|
|
set inst_spice_sym_def [xschem getprop instance $i spice_sym_def]
|
|
set sym_spice_sym_def [xschem getprop instance $i cell::spice_sym_def]
|
|
if {$only_subckts && ($type ne {subcircuit})} { continue }
|
|
|
|
set skip 0
|
|
foreach j $nolist_libs {
|
|
if {[regexp $j $abs_symbol]} {
|
|
set skip 1
|
|
break
|
|
}
|
|
}
|
|
if {$skip} { continue }
|
|
incr traversal(cnt)
|
|
set cnt $traversal(cnt)
|
|
|
|
# puts "building frame $sf.f$cnt"
|
|
frame $sf.f$cnt
|
|
pack $sf.f$cnt -side top -fill x
|
|
label $sf.f$cnt.i -text "[spaces $level 1 {* }]$instname" \
|
|
-width 25 -anchor w -padx 4 -borderwidth 1 \
|
|
-relief sunken -pady 1 -font $font
|
|
label $sf.f$cnt.l -text $symbol -width 30 -anchor w -padx 4 -borderwidth 1 \
|
|
-relief sunken -pady 1 -font $font
|
|
entry $sf.f$cnt.s -width 45 -borderwidth 1 -relief sunken -font $font
|
|
if {$type eq {subcircuit}} {
|
|
if {$inst_spice_sym_def ne {}} {
|
|
$sf.f$cnt.s insert 0 "$sch_rootname defined in instance spice_sym_def"
|
|
} elseif {$sym_spice_sym_def ne {}} {
|
|
$sf.f$cnt.s insert 0 "$sch_rootname defined in symbol spice_sym_def"
|
|
} else {
|
|
$sf.f$cnt.s insert 0 "$inst_sch"
|
|
}
|
|
}
|
|
button $sf.f$cnt.bsym -text {Sym} -padx 4 -borderwidth 1 -pady 0 -font $font \
|
|
-command "
|
|
xschem load_new_window \[$sf.f$cnt.l cget -text\]
|
|
"
|
|
button $sf.f$cnt.bsch -text {Sch} -padx 4 -borderwidth 1 -pady 0 -font $font \
|
|
-command "
|
|
if { [list $sym_spice_sym_def] eq {} && [list $inst_spice_sym_def] eq {}} {
|
|
xschem load_new_window \[$sf.f$cnt.s get\]
|
|
} elseif {[list $sym_spice_sym_def] ne {}} {
|
|
editdata [list $sym_spice_sym_def] {Symbol spice_sym_def attribute}
|
|
} else {
|
|
editdata [list $inst_spice_sym_def] {Instance spice_sym_def attribute}
|
|
}"
|
|
button $sf.f$cnt.upd -text Upd -padx 4 -borderwidth 1 -pady 0 -font $font \
|
|
-command "
|
|
traversal_setlabels $sf.f$cnt.s [list $parent_sch] [list $instname] [list $inst_sch] \
|
|
[list $sym_sch] [list $default_sch] [list $inst_spice_sym_def] [list $sym_spice_sym_def]
|
|
set traversal(geom) \[winfo geometry .trav\]
|
|
destroy .trav
|
|
traversal $traversal(only_subckts) $traversal(all_hierarchy)
|
|
"
|
|
|
|
traversal_setlabels $sf.f$cnt.s $parent_sch $instname $inst_sch $sym_sch \
|
|
$default_sch $inst_spice_sym_def $sym_spice_sym_def
|
|
pack $sf.f$cnt.i -side left -fill x -expand 1
|
|
pack $sf.f$cnt.l $sf.f$cnt.s -side left -fill x
|
|
pack $sf.f$cnt.bsym $sf.f$cnt.bsch $sf.f$cnt.upd -side left
|
|
set done_print 1
|
|
if {$type eq {subcircuit} && $all_hierarchy} {
|
|
xschem select instance $i fast nodraw
|
|
set descended [xschem descend 1 6]
|
|
if {$descended} {
|
|
incr level
|
|
set dp [hier_traversal $level $only_subckts 1]
|
|
xschem go_back 2
|
|
incr level -1
|
|
} else { ;# descended into a blank schematic. Go back.
|
|
xschem go_back 2
|
|
}
|
|
}
|
|
}
|
|
return $done_print
|
|
}
|
|
############ /traversal
|
|
|
|
proc bespice_getdata {sock} {
|
|
global bespice_server_getdata
|
|
if {[eof $sock] || [catch {gets $sock bespice_server_getdata(line,$sock)}]} {
|
|
puts "Closing connection $sock to bespice : $bespice_server_getdata(addr,$sock)"
|
|
unset bespice_server_getdata(addr,$sock)
|
|
unset bespice_server_getdata(line,$sock)
|
|
# we remove the closing socket from the list of clients
|
|
set search_index [ lsearch $bespice_server_getdata(clients) $sock]
|
|
# puts " search_index for $sock in $bespice_server_getdata(clients) ==> $search_index"
|
|
if { $search_index >= 0 } {
|
|
set bespice_server_getdata(clients) [ lreplace $bespice_server_getdata(clients) $search_index $search_index ]
|
|
}
|
|
set nb [ llength $bespice_server_getdata(clients) ]
|
|
if { $nb == 0 } {
|
|
# no more clients left => communication closed
|
|
unset bespice_server_getdata(sock)
|
|
} else {
|
|
# we have another client connection => use this one
|
|
set new_sock [lindex $bespice_server_getdata(clients) 0]
|
|
puts "Communicating to bespice over socket $new_sock"
|
|
set bespice_server_getdata(sock) [list $new_sock ]
|
|
}
|
|
close $sock
|
|
|
|
# puts "Clients = $bespice_server_getdata(clients)"
|
|
# set nb [ llength $bespice_server_getdata(clients) ]
|
|
# puts "number of Clients = $nb"
|
|
|
|
} else {
|
|
puts "bespice --> $bespice_server_getdata(line,$sock)"
|
|
set bespice_server_getdata(last) $bespice_server_getdata(line,$sock)
|
|
}
|
|
}
|
|
|
|
proc xschem_getdata {sock} {
|
|
global xschem_server_getdata tclcmd_puts debug_var
|
|
|
|
while {1} {
|
|
if {[gets $sock line] < 0} {
|
|
break
|
|
} else {
|
|
append xschem_server_getdata(line,$sock) $line \n
|
|
}
|
|
}
|
|
if {$debug_var<=-1} {puts "tcp<-- $xschem_server_getdata(line,$sock)"}
|
|
# xschem command must be executed at global scope...
|
|
redef_puts
|
|
uplevel #0 [list catch $xschem_server_getdata(line,$sock) tclcmd_puts]
|
|
rename puts {}
|
|
rename ::tcl::puts puts
|
|
if {$debug_var<=-1} {puts "tcp--> $tclcmd_puts"}
|
|
set xschem_server_getdata(res,$sock) "$tclcmd_puts"
|
|
puts -nonewline $sock "$xschem_server_getdata(res,$sock)"
|
|
flush $sock
|
|
close $sock ;# server closes
|
|
if {$debug_var<=-1} {puts "Close $xschem_server_getdata(addr,$sock)"}
|
|
unset xschem_server_getdata(addr,$sock)
|
|
unset xschem_server_getdata(line,$sock)
|
|
unset xschem_server_getdata(res,$sock)
|
|
}
|
|
|
|
# this function is called as soon as bespice wave connects to the communication server listening on $bespice_listen_port
|
|
# it makes sure the communication over the socket connection is possible
|
|
proc bespice_server {sock addr port} {
|
|
global bespice_server_getdata
|
|
if { ![info exists bespice_server_getdata(sock)] } {
|
|
puts "Accepting bespice connection $sock from $addr port $port"
|
|
set bespice_server_getdata(clients) [list $sock]
|
|
} else {
|
|
# we can' t handle more tha one socket at once
|
|
# however we put this socket to a list in case the 1st socket is closed.
|
|
# we can then use the 2nd socket
|
|
puts "Can't handle bespice connection $sock from $addr port $port"
|
|
lappend bespice_server_getdata(clients) [list $sock]
|
|
}
|
|
|
|
fconfigure $sock -buffering line
|
|
set bespice_server_getdata(addr,$sock) [list $addr $port]
|
|
set bespice_server_getdata(sock) [list $sock]
|
|
fileevent $sock readable [list bespice_getdata $sock]
|
|
# this informs bespice wave that it receives it's instructions from xschem. Some features will be adjusted for that.
|
|
puts $bespice_server_getdata(sock) "set_customer_specialization xschem"
|
|
|
|
# puts "Clients = $bespice_server_getdata(clients)"
|
|
# set nb [ llength $bespice_server_getdata(clients) ]
|
|
# puts "number of Clients = $nb"
|
|
}
|
|
|
|
proc xschem_server {sock addr port} {
|
|
global xschem_server_getdata debug_var
|
|
if {$debug_var<=-1} {puts "Accept $sock from $addr port $port"}
|
|
fconfigure $sock -buffering line -blocking 0
|
|
set xschem_server_getdata(addr,$sock) [list $addr $port]
|
|
set xschem_server_getdata(line,$sock) {}
|
|
fileevent $sock readable [list xschem_getdata $sock]
|
|
}
|
|
|
|
proc list_hierarchy {} {
|
|
set s [xschem list_hierarchy]
|
|
set r {}
|
|
foreach {a b} [lsort -decreasing -dictionary -index 0 -stride 2 $s] {
|
|
append r $a { } $b \n
|
|
}
|
|
return $r
|
|
}
|
|
|
|
## given a path (x1.x2.m4) descend into x1.x2 and return m4 whether m4 found or not
|
|
proc descend_hierarchy {path {redraw 1}} {
|
|
xschem set no_draw 1
|
|
# return to top level if not already there
|
|
while { [xschem get currsch] } { xschem go_back }
|
|
# recursively descend into sub-schematics
|
|
while { [regexp {\.} $path] } {
|
|
xschem unselect_all
|
|
set inst $path
|
|
regsub {\..*} $inst {} inst ;# take 1st path component: xlev1[3].xlev2.m3 -> xlev1[3]
|
|
regsub {[^.]+\.} $path {} path ;# take remaining path: xlev1[3].xlev2.m3 -> xlev2.m3
|
|
xschem search exact 1 name $inst 1
|
|
# handle vector instances: xlev1[3:0] -> xlev1[3],xlev1[2],xlev1[1],xlev1[0]
|
|
# descend into the right one
|
|
set inst_list [split [lindex [xschem expandlabel [lindex [xschem selected_set] 0 ] ] 0] {,}]
|
|
set instnum [expr {[lsearch -exact $inst_list $inst] + 1}]
|
|
xschem descend $instnum
|
|
}
|
|
xschem set no_draw 0
|
|
if {$redraw} {xschem redraw}
|
|
return $path
|
|
}
|
|
|
|
## given a hierarchical instname name (x1.xamp.m1) go down in the hierarchy and
|
|
## select the specified instance (m1).
|
|
## this search assumes it is given from the top of hierarchy
|
|
proc select_inst {fullinst {redraw 1 } } {
|
|
xschem set no_draw 1
|
|
set inst [descend_hierarchy $fullinst 0]
|
|
set res [xschem select instance $inst]
|
|
# if nothing found return to top
|
|
if {!$res} {
|
|
while { [xschem get currsch] } { xschem go_back }
|
|
}
|
|
xschem set no_draw 0
|
|
if {$redraw} {xschem redraw}
|
|
if {$res} {return $inst} else { return {} }
|
|
}
|
|
|
|
proc pin_label {} {
|
|
return [rel_sym_path [find_file_first lab_pin.sym]]
|
|
}
|
|
|
|
## given a hierarchical net name x1.xamp.netname go down in the hierarchy and
|
|
## highlight the specified net.
|
|
## this search assumes it is given from the top of hierarchy
|
|
proc probe_net {fullnet {redraw 1} } {
|
|
xschem set no_draw 1
|
|
set net [descend_hierarchy $fullnet 0]
|
|
set res [xschem hilight_netname $net]
|
|
if {$res==0 && [regexp {^net[0-9]+$} $net]} {
|
|
set net \#$net
|
|
set res [xschem hilight_netname $net]
|
|
}
|
|
if {!$res} {
|
|
while { [xschem get currsch] } { xschem go_back }
|
|
}
|
|
xschem set no_draw 0
|
|
if {$redraw} {xschem redraw}
|
|
if {$res} {return $net} else { return {} }
|
|
}
|
|
|
|
# backannotate newnet to be connected to specified hierarchical instance name and pin.
|
|
# places a label close to the instance pin to be re-routed.
|
|
# actual reconnect is human assisted!
|
|
proc reroute_inst {fullinst pinattr pinval newnet} {
|
|
if { [regexp {\.} $fullinst] } { set hier 1 } else { set hier 0 }
|
|
set res [descend_hierarchy $fullinst 0]
|
|
if {$res ne {} } {
|
|
set coord [xschem instance_pin_coord $res $pinattr $pinval]
|
|
if { $coord eq {} } {
|
|
while { [xschem get currsch] } { xschem go_back }
|
|
return 0
|
|
}
|
|
set pinname [lindex $coord 0]
|
|
set x [expr {[lindex $coord 1] - 10} ]
|
|
set y [expr {[lindex $coord 2] - 10} ]
|
|
set oldnet [xschem instance_net $res $pinname]
|
|
|
|
regsub {.*\.} $newnet {} newnet
|
|
if { $oldnet eq $newnet } {
|
|
while { [xschem get currsch] } { xschem go_back }
|
|
puts "Warning: netlist patch already done? "
|
|
return 0
|
|
}
|
|
|
|
xschem instance [pin_label] $x $y 0 0 [list name=l1 lab=$newnet]
|
|
xschem hilight_netname $newnet
|
|
xschem select instance $res
|
|
xschem hilight_netname $oldnet
|
|
if {$hier} { xschem save} ;# save so we can process other reroute_inst without beink asked to save.
|
|
xschem redraw
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
## put $new net labels close to pins on all elements connected to $old
|
|
proc reroute_net {old new} {
|
|
xschem push_undo
|
|
xschem set no_undo 1
|
|
xschem unhilight
|
|
probe_net $old
|
|
set old_nopath [regsub {.*\.} $old {}]
|
|
set new_nopath [regsub {.*\.} $new {}]
|
|
set devlist [xschem instances_to_net $old_nopath]
|
|
foreach i $devlist {
|
|
set instname [lindex $i 0]
|
|
set x [expr {[lindex $i 2] - 10}]
|
|
set y [expr {[lindex $i 3] - 10}]
|
|
xschem instance [pin_label] $x $y 0 0 [list name=l1 lab=$new_nopath]
|
|
xschem select instance $instname
|
|
}
|
|
xschem hilight_netname $new_nopath
|
|
xschem set no_undo 0
|
|
}
|
|
|
|
## $N : netlist file full path (/home/schippes/simulations/opamp.spice)
|
|
## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp)
|
|
## $s : schematic name (opamp) or netlist_name if given
|
|
## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch)
|
|
## $d : netlist directory
|
|
proc sim_cmd {cmd} {
|
|
global netlist_dir terminal
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set tool [xschem get netlist_type]
|
|
set d ${netlist_dir}
|
|
set S [xschem get schname]
|
|
|
|
set custom_netlist_file [xschem get netlist_name]
|
|
if {$custom_netlist_file ne {}} {
|
|
set s [file rootname $custom_netlist_file]
|
|
} else {
|
|
set s [file tail [file rootname $S]]
|
|
}
|
|
set n ${netlist_dir}/${s}
|
|
if {$tool eq {verilog}} {
|
|
set N ${n}.v
|
|
} else {
|
|
set N ${n}.${tool}
|
|
}
|
|
# puts "N=$N\nn=$n\ns=$s\nS=$S\nd=$d"
|
|
return [subst $cmd]
|
|
}
|
|
|
|
# wrapper to proc simulate, if called from button.
|
|
proc simulate_from_button {{callback {}}} {
|
|
global simulate_bg
|
|
set simvar tctx::[xschem get current_win_path]_simulate
|
|
if {![info exists $simvar] || [set $simvar] ne {orange}} {
|
|
simulate $callback
|
|
} elseif {[info exists $simvar] && [set $simvar] eq {orange}} {
|
|
set simulate_id tctx::[xschem get current_win_path]_simulate_id
|
|
if { [info exists $simulate_id] } {
|
|
set id [set $simulate_id]
|
|
set res [kill_running_cmds $id -15]
|
|
if { $res == 0} {
|
|
# something went wrong. Forget about the process
|
|
unset tctx::[xschem get current_win_path]_simulate_id
|
|
set tctx::[xschem get current_win_path]_simulate $simulate_bg
|
|
catch {[xschem get top_path].menubar entryconfigure Simulate -background $simulate_bg}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
## $N : netlist file full path (/home/schippes/simulations/opamp.spice)
|
|
## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp)
|
|
## $s : schematic name (opamp) or netlist_name if given
|
|
## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch)
|
|
## $d : netlist directory
|
|
proc simulate {{callback {}}} {
|
|
|
|
global netlist_dir terminal sim env
|
|
global execute XSCHEM_SHAREDIR has_x OS
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set_sim_defaults
|
|
set netlist_type [xschem get netlist_type]
|
|
if { [set_netlist_dir 0] ne {}} {
|
|
set d ${netlist_dir}
|
|
set tool $netlist_type
|
|
set S [xschem get schname]
|
|
set custom_netlist_file [xschem get netlist_name]
|
|
if {$custom_netlist_file ne {}} {
|
|
set s [file rootname $custom_netlist_file]
|
|
} else {
|
|
set s [file tail [file rootname $S]]
|
|
}
|
|
set n ${netlist_dir}/${s}
|
|
if {$tool eq {verilog}} {
|
|
set N ${n}.v
|
|
} else {
|
|
set N ${n}.${tool}
|
|
}
|
|
if { ![info exists sim($tool,default)] } {
|
|
if { [info exists has_x] } {alert_ "Warning: simulator for $tool is not configured"}
|
|
puts "Warning: simulator for $tool is not configured"
|
|
return -1
|
|
}
|
|
set def $sim($tool,default)
|
|
set fg $sim($tool,$def,fg)
|
|
set st $sim($tool,$def,st)
|
|
if {$fg} {
|
|
set fg {execute_wait}
|
|
} else {
|
|
set fg {execute}
|
|
}
|
|
set cmd [subst -nobackslashes $sim($tool,$def,cmd)]
|
|
|
|
# window interface tabbed interface
|
|
# -----------------------------------------
|
|
# top_path win_path top_path win_path
|
|
# {} .drw {} .drw
|
|
# .x1 .x1.drw {} .x1.drw
|
|
# .x2 .x2.drw {} .x2.drw
|
|
set execute(callback) "
|
|
set_simulate_button [list [xschem get top_path] [xschem get current_win_path]]
|
|
$callback
|
|
"
|
|
if {$fg eq {execute_wait}} {xschem set semaphore [expr {[xschem get semaphore] +1}]}
|
|
|
|
set save [pwd]
|
|
cd $netlist_dir
|
|
# Note: Windows $cmd cannot be surrounded by {} as exec will change forward slash to backward slash
|
|
set id [eval execute $st $cmd] ;# Start simulation process
|
|
cd $save
|
|
|
|
if {[info exists has_x] && $id >= 0 } {
|
|
set tctx::[xschem get current_win_path]_simulate_id $id
|
|
set button_path [xschem get top_path].menubar
|
|
catch {$button_path entryconfigure Simulate -background orange}
|
|
set tctx::[xschem get current_win_path]_simulate orange
|
|
}
|
|
|
|
puts "Simulation started: execution ID: $id"
|
|
|
|
if {$fg eq {execute_wait}} {
|
|
if {$id >= 0} {
|
|
vwait execute(pipe,$id)
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
return $id
|
|
} else {
|
|
return -1
|
|
}
|
|
}
|
|
|
|
proc gaw_echoline {} {
|
|
global gaw_fd
|
|
gets $gaw_fd line
|
|
if {[eof $gaw_fd]} {
|
|
puts "finishing connection from gaw"
|
|
close $gaw_fd
|
|
unset gaw_fd
|
|
} else {
|
|
# generate a variable event we can vwait for
|
|
set gaw_fd $gaw_fd
|
|
}
|
|
puts "gaw -> $line"
|
|
}
|
|
|
|
proc setup_tcp_gaw {} {
|
|
global gaw_fd gaw_tcp_address netlist_dir has_x
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
if { [info exists gaw_fd] } { return 1; }
|
|
set custom_netlist_file [xschem get netlist_name]
|
|
if {$custom_netlist_file ne {}} {
|
|
set s [file rootname $custom_netlist_file]
|
|
} else {
|
|
set s [file tail [file rootname [xschem get schname 0]]]
|
|
}
|
|
if { ![info exists gaw_fd] && [catch {eval socket $gaw_tcp_address} gaw_fd] } {
|
|
puts "Problems opening socket to gaw on address $gaw_tcp_address"
|
|
unset gaw_fd
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -type ok -title {Tcp socket error} \
|
|
-message [concat "Problems opening socket to gaw on address $gaw_tcp_address. " \
|
|
"Ensure the following line is present uncommented in ~/.gaw/gawrc: up_listenPort = 2020." \
|
|
"If you recently closed gaw the port may be in a TIME_WAIT state for a minute or so ." \
|
|
"Close gaw, Wait a minute or two, then send waves to gaw again."]
|
|
}
|
|
return 0
|
|
}
|
|
fconfigure $gaw_fd -blocking 1 -buffering line -encoding binary -translation binary
|
|
fileevent $gaw_fd readable gaw_echoline
|
|
puts $gaw_fd "table_set $s.raw"
|
|
return 1
|
|
}
|
|
|
|
proc gaw_cmd {cmd} {
|
|
global gaw_fd gaw_tcp_address netlist_dir has_x
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
if { ![info exists gaw_fd] && [catch {eval socket $gaw_tcp_address} gaw_fd] } {
|
|
puts "Problems opening socket to gaw on address $gaw_tcp_address"
|
|
unset gaw_fd
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -type ok -title {Tcp socket error} \
|
|
-message [concat "Problems opening socket to gaw on address $gaw_tcp_address. " \
|
|
"If you recently closed gaw the port may be in a TIME_WAIT state for a minute or so ." \
|
|
"Close gaw, Wait a minute or two, then send waves to gaw again."]
|
|
}
|
|
return
|
|
}
|
|
fconfigure $gaw_fd -blocking 0 -buffering line -encoding binary -translation binary
|
|
puts $gaw_fd "$cmd"
|
|
set n [regexp -all \n $cmd]
|
|
incr n
|
|
puts "gaw command lines: $n"
|
|
fileevent $gaw_fd readable gaw_echoline
|
|
while { $n} {
|
|
#timeout for abnormal deadlocks
|
|
set wd [after 10000 set gaw_fd stalled]
|
|
vwait gaw_fd
|
|
if { $gaw_fd ne {stalled} } {
|
|
after cancel $wd
|
|
} else {
|
|
puts "timeout waiting for gaw response.."
|
|
break
|
|
}
|
|
incr n -1
|
|
}
|
|
close $gaw_fd
|
|
unset gaw_fd
|
|
}
|
|
|
|
proc waves {{type {}}} {
|
|
## $N : netlist file full path (/home/schippes/simulations/opamp.spice)
|
|
## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp)
|
|
## $s : schematic name (opamp) or netlist_name if given
|
|
## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch)
|
|
## $d : netlist directory
|
|
|
|
global netlist_dir terminal sim XSCHEM_SHAREDIR has_x
|
|
global bespice_listen_port env simulate_bg execute
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
if {$type ne {external} } {
|
|
load_raw $type
|
|
return
|
|
}
|
|
set netlist_type [xschem get netlist_type]
|
|
set_sim_defaults
|
|
if { [set_netlist_dir 0] ne {}} {
|
|
set d ${netlist_dir}
|
|
set tool ${netlist_type}
|
|
set S [xschem get schname]
|
|
|
|
set custom_netlist_file [xschem get netlist_name]
|
|
if {$custom_netlist_file ne {}} {
|
|
set s [file rootname $custom_netlist_file]
|
|
} else {
|
|
set s [file tail [file rootname $S]]
|
|
}
|
|
set n ${netlist_dir}/${s}
|
|
if {$tool eq {verilog}} {
|
|
set N ${n}.v
|
|
} else {
|
|
set N ${n}.${tool}
|
|
}
|
|
set tool ${tool}wave
|
|
if {![info exists sim($tool,default)] } {
|
|
if { [info exists has_x] } {alert_ "Warning: viewer for $tool is not configured"}
|
|
puts "Warning: viewer for $tool is not configured"
|
|
return
|
|
}
|
|
set def $sim($tool,default)
|
|
set fg $sim($tool,$def,fg)
|
|
set st $sim($tool,$def,st)
|
|
if {$fg} {
|
|
set fg {execute_wait}
|
|
} else {
|
|
set fg {execute}
|
|
}
|
|
set cmd [subst -nobackslashes $sim($tool,$def,cmd)]
|
|
|
|
set save [pwd]
|
|
cd $netlist_dir
|
|
set id [eval execute $st $cmd]
|
|
cd $save
|
|
|
|
if {$fg eq {execute_wait}} {
|
|
if {$id >= 0} {
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
vwait execute(pipe,$id)
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# ============================================================
|
|
|
|
|
|
proc graph_push_undo {} {
|
|
global graph_change_done
|
|
|
|
if {$graph_change_done == 0} {
|
|
xschem push_undo
|
|
set graph_change_done 1
|
|
}
|
|
}
|
|
|
|
# allow change color (via graph_change_wave_color) of double clicked wave
|
|
proc graph_edit_wave {n n_wave} {
|
|
global graph_sel_color graph_selected graph_sel_wave
|
|
global graph_schname cadlayers
|
|
if {[winfo exists .graphdialog]} {return}
|
|
set graph_schname [xschem get schname]
|
|
set_ne graph_sel_color 4
|
|
set graph_selected $n
|
|
set graph_sel_wave $n_wave
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set node [xschem my_strtok_r [xschem getprop rect 2 $graph_selected node] \n \" 0]
|
|
# add default colors if unspecified in col
|
|
set i 0
|
|
foreach graph_node $node {
|
|
if {[lindex $col $i] eq {}} { lappend col $graph_sel_color}
|
|
incr i
|
|
}
|
|
# remove excess colors
|
|
set col [lrange $col 0 [expr {$i - 1}]]
|
|
set graph_sel_color [lindex $col $graph_sel_wave]
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
xschem draw_graph $graph_selected
|
|
toplevel .graphdialog -class Dialog
|
|
wm transient .graphdialog [xschem get topwindow]
|
|
frame .graphdialog.f
|
|
button .graphdialog.ok -text OK -command {
|
|
destroy .graphdialog
|
|
}
|
|
button .graphdialog.cancel -text Cancel -command {destroy .graphdialog}
|
|
for {set i 0} {$i < $cadlayers} {incr i} {
|
|
radiobutton .graphdialog.f.r$i -value $i -background [lindex $tctx::colors $i] \
|
|
-variable graph_sel_color -command {graph_change_wave_color $graph_sel_wave } \
|
|
-selectcolor white -foreground black
|
|
pack .graphdialog.f.r$i -side left -fill both -expand yes
|
|
}
|
|
grid .graphdialog.f - -sticky nsew
|
|
grid .graphdialog.ok .graphdialog.cancel -sticky ew
|
|
grid rowconfig .graphdialog 0 -weight 1
|
|
grid column .graphdialog 0 -weight 1
|
|
grid column .graphdialog 1 -weight 1
|
|
tkwait window .graphdialog
|
|
set graph_schname {}
|
|
}
|
|
|
|
|
|
# get selected text from a text widget:
|
|
#
|
|
# .graphdialog.center.right.text1 get sel.first sel.last
|
|
#
|
|
# see if a selection is present:
|
|
# .graphdialog.center.right.text1 tag ranges sel
|
|
#
|
|
# replace selected text:
|
|
# .graphdialog.center.right.text1 replace sel.first sel.last BUS
|
|
#
|
|
# programmatically select text:
|
|
# .graphdialog.center.right.text1 tag add sel 1.0 {end - 1 chars}
|
|
# clear selection
|
|
# .graphdialog.center.right.text1 tag remove sel 1.0 end
|
|
# get position of cursor:
|
|
# .graphdialog.center.right.text1 index insert
|
|
# set cursor position:
|
|
# .graphdialog.center.right.text1 mark set insert 2.18
|
|
|
|
|
|
# add nodes from provided list of {node color} ....
|
|
# used in hilight_net()
|
|
proc graph_add_nodes_from_list {nodelist} {
|
|
global graph_bus graph_selected graph_schname has_x
|
|
if {$graph_bus} {
|
|
set sep ,
|
|
} else {
|
|
set sep \n
|
|
}
|
|
if { [info exists has_x] && [winfo exists .graphdialog] } {
|
|
set sel {}
|
|
set current_node_list [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}]
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
if {[string length $current_node_list] > 0 && ![regexp "\n$" $current_node_list]} {
|
|
.graphdialog.center.right.text1 insert end \n
|
|
}
|
|
set change_done 0
|
|
set first 0
|
|
foreach {i c} $nodelist {
|
|
if {$sel ne {}} {append sel $sep}
|
|
if {!$first || !$graph_bus } {
|
|
regsub {\[.*} $i {} busname
|
|
lappend col $c
|
|
}
|
|
append sel $i
|
|
set change_done 1
|
|
set first 1
|
|
}
|
|
if {$change_done && $graph_bus} {
|
|
set sel "[string toupper $busname];${sel}\n"
|
|
} else {
|
|
set sel "${sel}\n"
|
|
}
|
|
if {$change_done} {
|
|
.graphdialog.center.right.text1 insert end $sel
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
set node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
xschem setprop -fastundo rect 2 $graph_selected color $col
|
|
graph_update_nodelist
|
|
regsub -all {[\\"]} $node {\\&} node_quoted
|
|
xschem setprop -fast rect 2 $graph_selected node $node_quoted
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
} else {
|
|
set sel {}
|
|
set change_done 0
|
|
set first 0
|
|
set col [xschem getprop rect 2 [xschem get graph_lastsel] color]
|
|
set nnn [xschem getprop rect 2 [xschem get graph_lastsel] node]
|
|
foreach {i c} $nodelist {
|
|
if {$sel ne {}} {append sel $sep}
|
|
if {!$first || !$graph_bus } {
|
|
regsub {\[.*} $i {} busname
|
|
lappend col $c
|
|
}
|
|
append sel $i
|
|
set change_done 1
|
|
set first 1
|
|
}
|
|
if {$change_done && $graph_bus} {
|
|
set sel "[string toupper $busname];${sel}\n"
|
|
} else {
|
|
set sel "${sel}\n"
|
|
}
|
|
|
|
if {$change_done} {
|
|
xschem setprop -fastundo rect 2 [xschem get graph_lastsel] color $col
|
|
if {[string length $nnn] > 0 && ![regexp "\n$" $nnn]} {
|
|
append nnn "\n"
|
|
}
|
|
append nnn $sel
|
|
regsub -all {[\\"]} $nnn {\\&} node_quoted
|
|
xschem setprop -fast rect 2 [xschem get graph_lastsel] node $node_quoted
|
|
xschem draw_graph [xschem get graph_lastsel]
|
|
}
|
|
}
|
|
}
|
|
|
|
# add nodes from left listbox
|
|
proc graph_add_nodes {} {
|
|
global graph_bus graph_sel_color graph_selected
|
|
set sel_idx [.graphdialog.center.left.list1 curselection]
|
|
set sel {}
|
|
if {$graph_bus} {
|
|
set sep ,
|
|
} else {
|
|
set sep \n
|
|
}
|
|
set current_node_list [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}]
|
|
if {[string length $current_node_list] > 0 && ![regexp "\n$" $current_node_list]} {
|
|
.graphdialog.center.right.text1 insert end \n
|
|
}
|
|
set change_done 0
|
|
foreach i $sel_idx {
|
|
set c [.graphdialog.center.left.list1 get $i]
|
|
# escape [ and ] characters.
|
|
set c [regsub -all {([][])} $c {\\\1}]
|
|
if { ![regexp "(^|\[ \t\n\])${c}($|\[ \t\n\])" $current_node_list]} {
|
|
if {$sel ne {}} {append sel $sep}
|
|
append sel [.graphdialog.center.left.list1 get $i]
|
|
set change_done 1
|
|
}
|
|
}
|
|
if {$change_done && $graph_bus} {
|
|
set sel "BUS_NAME;${sel}\n"
|
|
} else {
|
|
set sel "${sel}\n"
|
|
}
|
|
if {$change_done} {
|
|
set tag [.graphdialog.center.right.text1 tag names insert]
|
|
if { $tag eq {}} {set tag [.graphdialog.center.right.text1 tag names {insert - 1 char}]}
|
|
.graphdialog.center.right.text1 insert {insert lineend + 1 char} $sel
|
|
# insert $graph_sel_color colors along with inserted nodes, so previous wave colors are preserved
|
|
if { [regexp {^t} $tag]} {
|
|
set index [string range $tag 1 end]
|
|
incr index
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set col [linsert $col $index $graph_sel_color]
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
}
|
|
}
|
|
}
|
|
|
|
proc graph_delete_nodes {} {
|
|
global graph_selected
|
|
set tag [.graphdialog.center.right.text1 tag names insert]
|
|
if { [regexp {^t} $tag]} {
|
|
set change_done 1
|
|
set index [string range $tag 1 end]
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set node [xschem my_strtok_r [xschem getprop rect 2 $graph_selected node] \n \" 1]
|
|
|
|
set col [lreplace $col $index $index]
|
|
set node [lreplace $node $index $index]
|
|
set node [join $node \n]
|
|
graph_push_undo
|
|
.graphdialog.center.right.text1 delete 1.0 end
|
|
.graphdialog.center.right.text1 insert 1.0 $node
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
}
|
|
}
|
|
|
|
proc graph_get_signal_list {siglist pattern } {
|
|
global graph_sort
|
|
set direction {-decreasing}
|
|
if {$graph_sort} {set direction {-increasing}}
|
|
set result {}
|
|
set siglist [join [lsort $direction -dictionary $siglist] \n]
|
|
# just check if pattern is a valid regexp
|
|
set err [catch {regexp $pattern {12345}} res]
|
|
if {$err} {set pattern {}}
|
|
foreach i $siglist {
|
|
regsub {^v\((.*)\)$} $i {\1} i
|
|
if {[regexp $pattern $i] } {
|
|
lappend result $i
|
|
}
|
|
}
|
|
return $result
|
|
}
|
|
|
|
proc touches {sel tag} {
|
|
set res 0
|
|
scan $sel {%d.%d %d.%d} sel_linestart sel_charstart sel_lineend sel_charend
|
|
scan $tag {%d.%d %d.%d} tag_linestart tag_charstart tag_lineend tag_charend
|
|
set selstart [expr {$sel_linestart * 1000000 + $sel_charstart}]
|
|
set selend [expr {$sel_lineend * 1000000 + $sel_charend}]
|
|
set tagstart [expr {$tag_linestart * 1000000 + $tag_charstart}]
|
|
set tagend [expr {$tag_lineend * 1000000 + $tag_charend}]
|
|
# puts "selstart: $selstart"
|
|
# puts "selend: $selend"
|
|
# puts "tagstart: $tagstart"
|
|
# puts "tagend: $tagend"
|
|
if { ($tagstart >= $selstart && $tagstart <= $selend) ||
|
|
($tagend >= $selstart && $tagend <= $selend) ||
|
|
($selstart >= $tagstart && $selstart <= $tagend) ||
|
|
($selend >= $tagstart && $selend <= $tagend)
|
|
} {
|
|
set res 1
|
|
}
|
|
# puts "touch: returning $res"
|
|
return $res
|
|
}
|
|
|
|
proc set_graph_default_colors {} {
|
|
global graph_selected graph_schname
|
|
if { [xschem get schname] ne $graph_schname } return
|
|
xschem setprop -fast rect 2 $graph_selected color "4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21"
|
|
graph_update_nodelist
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
# change color of selected wave in text widget and redraw graph
|
|
# OR
|
|
# change color attribute of wave given as parameter, redraw graph
|
|
proc graph_change_wave_color {{wave {}}} {
|
|
global graph_sel_color graph_selected graph_schname
|
|
|
|
if { [xschem get schname] ne $graph_schname } return
|
|
graph_push_undo
|
|
# get tag the cursor is on:
|
|
if { $wave eq {}} {
|
|
set sel_range [.graphdialog.center.right.text1 tag ranges sel]
|
|
if {$sel_range ne {}} {
|
|
# puts "sel_range --> $sel_range"
|
|
foreach tag [.graphdialog.center.right.text1 tag names] {
|
|
if {$tag eq {sel}} {continue}
|
|
set tag_range [.graphdialog.center.right.text1 tag ranges $tag]
|
|
# puts "$tag --> $tag_range"
|
|
|
|
if { [touches $sel_range $tag_range]} {
|
|
set index [string range $tag 1 end]
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set col [lreplace $col $index $index $graph_sel_color]
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
}
|
|
}
|
|
graph_update_nodelist
|
|
xschem draw_graph $graph_selected
|
|
} else {
|
|
set tag [.graphdialog.center.right.text1 tag names insert]
|
|
# if { $tag eq {}} {set tag [.graphdialog.center.right.text1 tag names {insert - 1 char}]}
|
|
if { [regexp {^t} $tag]} {
|
|
set index [string range $tag 1 end]
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set col [lreplace $col $index $index $graph_sel_color]
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
graph_update_nodelist
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
# wave to change provided as parameter
|
|
} else {
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set col [lreplace $col $wave $wave $graph_sel_color]
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
|
|
# set txt [xschem getprop rect 2 $n node 2]
|
|
# set txt [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}]
|
|
# return first and last indexes of nodes in txt
|
|
proc graph_tag_nodes {txt} {
|
|
global graph_selected graph_sel_color
|
|
# delete old tags
|
|
if { [winfo exists .graphdialog.center.right.text1] } {
|
|
eval .graphdialog.center.right.text1 tag delete [ .graphdialog.center.right.text1 tag names]
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set col [string trim $col " \n"]
|
|
}
|
|
|
|
|
|
set start 0
|
|
# transform escaped newlines into two spaces, so tagging of multiline nodes is simpler
|
|
regsub -all "\\\\\n" $txt { } txt
|
|
if {[regexp {^tcleval\(} $txt]} {
|
|
set start 8
|
|
regsub {\)[ \n]*$} $txt {} txt
|
|
}
|
|
set regx {("[^"]+")|([^\n]+)}
|
|
|
|
set tt {}
|
|
set cc {}
|
|
while {[regexp -indices -start $start $regx $txt idxall]} {
|
|
lappend tt [lindex $idxall 0]
|
|
set ccc [lindex $idxall 1]
|
|
lappend cc $ccc
|
|
set start [expr {$ccc + 1}]
|
|
}
|
|
if { [winfo exists .graphdialog.center.right.text1] } {
|
|
set n 0
|
|
if { $tt ne {} } {
|
|
foreach t $tt c $cc {
|
|
set col_idx [lindex $col $n]
|
|
# add missing colors
|
|
if {$col_idx eq {}} {
|
|
set col_idx $graph_sel_color
|
|
lappend col $graph_sel_color
|
|
}
|
|
set b [lindex $tctx::colors $col_idx]
|
|
.graphdialog.center.right.text1 tag add t$n "1.0 + $t chars" "1.1 + $c chars"
|
|
if { [info tclversion] > 8.4} {
|
|
.graphdialog.center.right.text1 tag configure t$n -background $b -selectbackground grey40
|
|
} else {
|
|
.graphdialog.center.right.text1 tag configure t$n -background $b
|
|
}
|
|
incr n
|
|
}
|
|
# remove excess colors
|
|
set col [lrange $col 0 [expr {$n - 1}]]
|
|
} else {
|
|
set col {}
|
|
}
|
|
xschem setprop -fast rect 2 $graph_selected color $col
|
|
}
|
|
return [list $tt $cc]
|
|
}
|
|
|
|
# tag nodes in text widget with assigned colors
|
|
proc graph_update_nodelist {} {
|
|
global graph_selected graph_sel_color graph_schname
|
|
if { [xschem get schname] ne $graph_schname } return
|
|
# tagging nodes in text widget:
|
|
set txt [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}]
|
|
graph_tag_nodes $txt
|
|
}
|
|
|
|
proc graph_fill_listbox {} {
|
|
global graph_selected
|
|
set pattern [.graphdialog.center.left.search get]
|
|
set retv {}
|
|
set autoload [uplevel #0 {subst [xschem getprop rect 2 $graph_selected autoload 2]}]
|
|
set rawfile [xschem getprop rect 2 $graph_selected rawfile]
|
|
if {$rawfile ne {}} {
|
|
if {![catch {eval uplevel #0 {subst $rawfile}} res]} {
|
|
set rawfile $res
|
|
}
|
|
}
|
|
set sim_type [uplevel #0 {subst [xschem getprop rect 2 $graph_selected sim_type 2]}]
|
|
if {$autoload ne {} && $autoload } { set autoload read} else {set autoload switch}
|
|
# puts "graph_fill_listbox: $rawfile $sim_type"
|
|
if {$rawfile ne {}} {
|
|
if {$sim_type eq {table}} {
|
|
set res [xschem raw table_read $rawfile $sim_type]
|
|
} else {
|
|
set res [xschem raw $autoload $rawfile $sim_type]
|
|
}
|
|
if {$res} {
|
|
set retv [graph_get_signal_list [xschem raw_query list] $pattern]
|
|
xschem raw switch_back
|
|
}
|
|
# puts "switch back"
|
|
} elseif {[xschem raw loaded] != -1} {
|
|
set retv [graph_get_signal_list [xschem raw_query list] $pattern]
|
|
}
|
|
.graphdialog.center.left.list1 delete 0 end
|
|
eval .graphdialog.center.left.list1 insert 0 $retv
|
|
|
|
}
|
|
|
|
# called from event handlers (OK, KeyRelease, DoubleClick) in graph_edit_properties
|
|
proc graph_update_node {node} {
|
|
global graph_selected
|
|
graph_update_nodelist
|
|
# add a backslash before " and \ characters
|
|
# note the double escaping for regsub replace string
|
|
regsub -all {[\\"]} $node {\\&} node_quoted
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected node $node_quoted
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
proc graph_update_div {graph_selected div} {
|
|
set divis [.graphdialog.top2.$div get]
|
|
if {[regexp {^[0-9]+$} $divis] && $divis < 1} {
|
|
set divis 1
|
|
.graphdialog.top2.$div delete 0 end
|
|
.graphdialog.top2.$div insert 0 $divis
|
|
}
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected $div $divis
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
proc graph_set_linewidth {graph_sel} {
|
|
global graph_linewidth_mult
|
|
set custom_lw [.graphdialog.top.lwe get]
|
|
if {[regexp {^[ \t]*$} $custom_lw]} {
|
|
set custom_lw $graph_linewidth_mult
|
|
}
|
|
graph_push_undo
|
|
if {$custom_lw != $graph_linewidth_mult} {
|
|
xschem setprop rect 2 $graph_sel linewidth_mult $custom_lw
|
|
} else {
|
|
xschem setprop rect 2 $graph_sel linewidth_mult ;# delete attribute since it is default
|
|
}
|
|
}
|
|
|
|
proc raw_is_loaded {rawfile type} {
|
|
set loaded 0
|
|
|
|
set r [catch "uplevel #0 {subst $rawfile}" res]
|
|
if {$r == 0} {
|
|
set rawfile $res
|
|
} else {
|
|
return $loaded
|
|
}
|
|
set rawlist [lrange [xschem raw info] 2 end]
|
|
foreach {n f t} $rawlist {
|
|
if {$rawfile eq $f && $type eq $t} {
|
|
set loaded 1
|
|
break
|
|
}
|
|
}
|
|
return $loaded
|
|
}
|
|
proc set_rect_flags {graph_selected} {
|
|
global graph_private_cursor graph_unlocked
|
|
|
|
if {$graph_private_cursor} {
|
|
set private_cursor {,private_cursor}
|
|
} else {
|
|
set private_cursor {}
|
|
}
|
|
if {$graph_unlocked} {
|
|
set unlocked {,unlocked}
|
|
} else {
|
|
set unlocked {}
|
|
}
|
|
xschem setprop -fast rect 2 $graph_selected flags "graph$unlocked$private_cursor"
|
|
}
|
|
|
|
proc graph_set_raw_props {} {
|
|
global graph_selected
|
|
xschem setprop -fast rect 2 $graph_selected rawfile [.graphdialog.center.right.rawentry get]
|
|
xschem setprop -fast rect 2 $graph_selected sim_type [.graphdialog.center.right.list get]
|
|
graph_fill_listbox
|
|
}
|
|
|
|
proc graph_edit_properties {n} {
|
|
global graph_bus graph_sort graph_digital graph_selected graph_sel_color graph_legend
|
|
global graph_unlocked graph_schname graph_logx graph_logy cadlayers graph_rainbow
|
|
global graph_linewidth_mult graph_change_done has_x graph_dialog_default_geometry
|
|
global graph_autoload graph_private_cursor
|
|
|
|
if { ![info exists has_x]} {return}
|
|
set graph_change_done 0
|
|
if { [winfo exists .graphdialog]} {
|
|
set graph_dialog_default_geometry [winfo geometry .graphdialog]
|
|
}
|
|
catch {destroy .graphdialog}
|
|
toplevel .graphdialog -class Dialog ;# -width 1 -height 1
|
|
wm withdraw .graphdialog
|
|
wm transient .graphdialog [xschem get topwindow]
|
|
update idletasks
|
|
|
|
set graph_selected $n
|
|
set graph_schname [xschem get schname]
|
|
set_ne graph_sel_color 4
|
|
set_ne graph_sort 0
|
|
set graph_rainbow 0
|
|
if {[xschem getprop rect 2 $n rainbow] == 1} {set graph_rainbow 1}
|
|
set graph_logx 0
|
|
if {[xschem getprop rect 2 $n logx] == 1} {set graph_logx 1}
|
|
set graph_logy 0
|
|
if {[xschem getprop rect 2 $n logy] == 1} {set graph_logy 1}
|
|
set graph_legend 1
|
|
if {[xschem getprop rect 2 $n legend] == 0} {set graph_legend 0}
|
|
set graph_digital 0
|
|
if {[xschem getprop rect 2 $n digital] == 1} {set graph_digital 1}
|
|
|
|
if {[regexp {private_cursor} [xschem getprop rect 2 $n flags]]} {
|
|
set graph_private_cursor 1
|
|
} else {
|
|
set graph_private_cursor 0
|
|
}
|
|
|
|
if {[regexp {unlocked} [xschem getprop rect 2 $n flags]]} {
|
|
set graph_unlocked 1
|
|
} else {
|
|
set graph_unlocked 0
|
|
}
|
|
|
|
set autoload [xschem getprop rect 2 $n autoload]
|
|
if {$autoload ne {} && $autoload} {
|
|
set graph_autoload 1
|
|
} else {
|
|
set graph_autoload 0
|
|
}
|
|
|
|
frame .graphdialog.top
|
|
# another row of buttons
|
|
frame .graphdialog.top2
|
|
frame .graphdialog.top3
|
|
frame .graphdialog.top4
|
|
panedwindow .graphdialog.center -orient horiz
|
|
frame .graphdialog.bottom
|
|
frame .graphdialog.center.left
|
|
frame .graphdialog.center.right
|
|
.graphdialog.center add .graphdialog.center.left .graphdialog.center.right
|
|
pack .graphdialog.top -side top -fill x
|
|
pack .graphdialog.top2 -side top -fill x
|
|
pack .graphdialog.top3 -side top -fill x
|
|
pack .graphdialog.top4 -side top -fill x
|
|
pack .graphdialog.center -side top -fill both -expand yes
|
|
pack .graphdialog.bottom -side top -fill x
|
|
# center-left frame
|
|
label .graphdialog.center.left.labsearch -text Search:
|
|
entry .graphdialog.center.left.search -width 10
|
|
entry_replace_selection .graphdialog.center.left.search
|
|
button .graphdialog.center.left.add -text Add -command {
|
|
graph_add_nodes
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
}
|
|
}
|
|
button .graphdialog.center.left.del -text Del -command {
|
|
graph_delete_nodes
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
}
|
|
}
|
|
listbox .graphdialog.center.left.list1 -width 20 -height 5 -selectmode extended \
|
|
-yscrollcommand {.graphdialog.center.left.yscroll set} \
|
|
-xscrollcommand {.graphdialog.center.left.xscroll set}
|
|
scrollbar .graphdialog.center.left.yscroll -command {.graphdialog.center.left.list1 yview}
|
|
scrollbar .graphdialog.center.left.xscroll -orient horiz -command {.graphdialog.center.left.list1 xview}
|
|
|
|
grid configure .graphdialog.center.left.labsearch -row 0 -column 0
|
|
grid configure .graphdialog.center.left.search -row 0 -column 1 -sticky ew
|
|
grid configure .graphdialog.center.left.add -row 0 -column 2
|
|
grid configure .graphdialog.center.left.del -row 0 -column 3
|
|
grid .graphdialog.center.left.list1 - - - .graphdialog.center.left.yscroll -sticky nsew
|
|
grid .graphdialog.center.left.xscroll - - - -sticky nsew
|
|
grid rowconfig .graphdialog.center.left 0 -weight 0
|
|
grid rowconfig .graphdialog.center.left 1 -weight 1 -minsize 2c
|
|
# grid columnconfig .graphdialog.center.left 0 -weight 1
|
|
grid columnconfig .graphdialog.center.left 1 -weight 1
|
|
|
|
# center right frame
|
|
checkbutton .graphdialog.center.right.autoload -text {Auto load} -variable graph_autoload \
|
|
-command {
|
|
if {$graph_autoload} {
|
|
xschem setprop -fast rect 2 $graph_selected autoload 1
|
|
} else {
|
|
xschem setprop -fast rect 2 $graph_selected autoload 0
|
|
}
|
|
}
|
|
label .graphdialog.center.right.lab2 -text { Sim type:}
|
|
if { [info tclversion] > 8.4} {
|
|
ttk::combobox .graphdialog.center.right.list \
|
|
-values {dc ac tran op sp spectrum noise constants table} -width 9
|
|
} else {
|
|
entry .graphdialog.center.right.list -width 4
|
|
entry_replace_selection .graphdialog.center.right.list
|
|
}
|
|
if { [info tclversion] > 8.4} {
|
|
bind .graphdialog.center.right.list <<ComboboxSelected>> {
|
|
xschem setprop -fast rect 2 $graph_selected sim_type [.graphdialog.center.right.list get]
|
|
graph_fill_listbox
|
|
}
|
|
if { [xschem getprop rect 2 $graph_selected sim_type 2] ne {}} {
|
|
.graphdialog.center.right.list set [xschem getprop rect 2 $graph_selected sim_type 2]
|
|
} else {
|
|
.graphdialog.center.right.list set {}
|
|
}
|
|
} else {
|
|
.graphdialog.center.right.list delete 0 end
|
|
if { [xschem getprop rect 2 $graph_selected sim_type 2] ne {}} {
|
|
.graphdialog.center.right.list insert 0 [xschem getprop rect 2 $graph_selected sim_type 2]
|
|
} else {
|
|
.graphdialog.center.right.list insert 0 {}
|
|
}
|
|
}
|
|
|
|
bind .graphdialog.center.right.list <KeyRelease> {
|
|
xschem setprop -fast rect 2 $graph_selected sim_type [.graphdialog.center.right.list get]
|
|
graph_fill_listbox
|
|
}
|
|
|
|
|
|
entry .graphdialog.center.right.rawentry -width 20
|
|
entry_replace_selection .graphdialog.center.right.rawentry
|
|
button .graphdialog.center.right.rawbut -text {Raw file:} -command {
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
.graphdialog.center.right.rawentry delete 0 end
|
|
.graphdialog.center.right.rawentry insert 0 \
|
|
[string map [list $netlist_dir {$netlist_dir}] [select_raw .graphdialog]]
|
|
graph_set_raw_props
|
|
}
|
|
|
|
bind .graphdialog.center.right.rawentry <KeyRelease> graph_set_raw_props
|
|
bind .graphdialog.center.right.rawentry <Leave> graph_set_raw_props
|
|
|
|
.graphdialog.center.right.rawentry insert 0 [xschem getprop rect 2 $graph_selected rawfile 2]
|
|
.graphdialog.center.right.rawentry xview moveto 1
|
|
text .graphdialog.center.right.text1 -undo 1 -wrap none -width 50 -height 5 -background grey90 -fg black \
|
|
-insertbackground grey40 -exportselection 1 \
|
|
-yscrollcommand {.graphdialog.center.right.yscroll set} \
|
|
-xscrollcommand {.graphdialog.center.right.xscroll set}
|
|
scrollbar .graphdialog.center.right.yscroll -command {.graphdialog.center.right.text1 yview}
|
|
scrollbar .graphdialog.center.right.xscroll -orient horiz -command {.graphdialog.center.right.text1 xview}
|
|
|
|
grid .graphdialog.center.right.autoload \
|
|
.graphdialog.center.right.lab2 .graphdialog.center.right.list \
|
|
.graphdialog.center.right.rawbut .graphdialog.center.right.rawentry -
|
|
grid configure .graphdialog.center.right.rawentry -sticky ew
|
|
grid .graphdialog.center.right.text1 - - - - .graphdialog.center.right.yscroll -sticky nsew
|
|
grid .graphdialog.center.right.xscroll - - - - - -sticky ew
|
|
grid rowconfig .graphdialog.center.right 0 -weight 0
|
|
grid rowconfig .graphdialog.center.right 1 -weight 1 -minsize 3c
|
|
grid rowconfig .graphdialog.center.right 2 -weight 0
|
|
grid columnconfig .graphdialog.center.right 0 -weight 0
|
|
grid columnconfig .graphdialog.center.right 1 -weight 0
|
|
grid columnconfig .graphdialog.center.right 2 -weight 0
|
|
grid columnconfig .graphdialog.center.right 3 -weight 0
|
|
grid columnconfig .graphdialog.center.right 4 -weight 1
|
|
grid columnconfig .graphdialog.center.right 5 -weight 0
|
|
|
|
# bottom frame
|
|
button .graphdialog.bottom.cancel -padx 1 -borderwidth 1 -pady 0 -text Cancel -command {
|
|
set graph_dialog_default_geometry [winfo geometry .graphdialog]
|
|
destroy .graphdialog
|
|
set graph_selected {}
|
|
set graph_schname {}
|
|
}
|
|
button .graphdialog.bottom.ok -padx 1 -borderwidth 1 -pady 0 -text OK -command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
xschem setprop -fast rect 2 $graph_selected x1 [.graphdialog.top3.xmin get]
|
|
xschem setprop -fast rect 2 $graph_selected x2 [.graphdialog.top3.xmax get]
|
|
xschem setprop -fast rect 2 $graph_selected y1 [.graphdialog.top3.ymin get]
|
|
xschem setprop -fast rect 2 $graph_selected y2 [.graphdialog.top3.ymax get]
|
|
set_rect_flags $graph_selected
|
|
}
|
|
set graph_dialog_default_geometry [winfo geometry .graphdialog]
|
|
destroy .graphdialog
|
|
set graph_selected {}
|
|
set graph_schname {}
|
|
}
|
|
button .graphdialog.bottom.apply -padx 1 -borderwidth 1 -pady 0 -text Apply -command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
xschem setprop -fast rect 2 $graph_selected x1 [.graphdialog.top3.xmin get]
|
|
xschem setprop -fast rect 2 $graph_selected x2 [.graphdialog.top3.xmax get]
|
|
xschem setprop -fast rect 2 $graph_selected y1 [.graphdialog.top3.ymin get]
|
|
xschem setprop -fast rect 2 $graph_selected y2 [.graphdialog.top3.ymax get]
|
|
set_rect_flags $graph_selected
|
|
}
|
|
}
|
|
|
|
# top packs
|
|
pack .graphdialog.bottom.ok -side left
|
|
pack .graphdialog.bottom.apply -side left
|
|
pack .graphdialog.bottom.cancel -side left
|
|
|
|
for {set i 0} {$i <= $cadlayers} {incr i} {
|
|
if {$i == $cadlayers } {
|
|
button .graphdialog.top4.r$i -padx 1 -borderwidth 1 -pady 0 \
|
|
-command "set_graph_default_colors" \
|
|
-text {AUTO SET}
|
|
} else {
|
|
radiobutton .graphdialog.top4.r$i -value $i -background [lindex $tctx::colors $i] \
|
|
-variable graph_sel_color -command graph_change_wave_color \
|
|
-selectcolor white -foreground black
|
|
}
|
|
pack .graphdialog.top4.r$i -side left
|
|
}
|
|
|
|
# top2 frame
|
|
checkbutton .graphdialog.top.legend -text {Legend} -variable graph_legend -indicatoron 1 \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected legend $graph_legend
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
label .graphdialog.top2.labunitx -text {X units}
|
|
spinbox .graphdialog.top2.unitx -values {f p n u m 1 k M G T} -width 2 \
|
|
-command {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected unitx [.graphdialog.top2.unitx get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top2.labunity -text { Y units}
|
|
spinbox .graphdialog.top2.unity -values {f p n u m 1 k M G T} -width 2 \
|
|
-command {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected unity [.graphdialog.top2.unity get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top2.labdivx -text { X div.}
|
|
entry .graphdialog.top2.divx -width 2
|
|
entry_replace_selection .graphdialog.top2.divx
|
|
bind .graphdialog.top2.divx <KeyRelease> {
|
|
graph_update_div $graph_selected divx
|
|
}
|
|
|
|
label .graphdialog.top2.labdivy -text { Y div.}
|
|
entry .graphdialog.top2.divy -width 2
|
|
entry_replace_selection .graphdialog.top2.divy
|
|
bind .graphdialog.top2.divy <KeyRelease> {
|
|
graph_update_div $graph_selected divy
|
|
}
|
|
|
|
label .graphdialog.top2.labsubdivx -text { X subdiv.}
|
|
entry .graphdialog.top2.subdivx -width 2
|
|
entry_replace_selection .graphdialog.top2.subdivx
|
|
bind .graphdialog.top2.subdivx <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected subdivx [.graphdialog.top2.subdivx get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top2.labsubdivy -text { Y subdiv.}
|
|
entry .graphdialog.top2.subdivy -width 2
|
|
entry_replace_selection .graphdialog.top2.subdivy
|
|
bind .graphdialog.top2.subdivy <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected subdivy [.graphdialog.top2.subdivy get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top2.labsweep -text { Sweep}
|
|
entry .graphdialog.top2.sweep -width 10
|
|
entry_replace_selection .graphdialog.top2.sweep
|
|
|
|
label .graphdialog.top2.labmode -text {Mode}
|
|
if { [info tclversion] > 8.4} {
|
|
ttk::combobox .graphdialog.top2.mode -values {Line HistoV HistoH} -width 6
|
|
bind .graphdialog.top2.mode <<ComboboxSelected>> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected mode [.graphdialog.top2.mode get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
} else {
|
|
spinbox .graphdialog.top2.mode -values {Line HistoV HistoH} -width 6 \
|
|
-command {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected mode [.graphdialog.top2.mode get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
|
|
# bind .graphdialog.top2.sweep <KeyRelease> {
|
|
# graph_push_undo
|
|
# xschem setprop rect 2 $graph_selected sweep [.graphdialog.top2.sweep get]
|
|
# xschem draw_graph $graph_selected
|
|
# }
|
|
|
|
bind .graphdialog.top2.sweep <Leave> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected sweep [.graphdialog.top2.sweep get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
.graphdialog.top2.sweep insert 0 [xschem getprop rect 2 $graph_selected sweep]
|
|
|
|
set graph_divx [xschem getprop rect 2 $graph_selected divx]
|
|
if {$graph_divx eq {}} { set graph_divx 5}
|
|
.graphdialog.top2.divx insert 0 $graph_divx
|
|
|
|
set graph_divy [xschem getprop rect 2 $graph_selected divy]
|
|
if {$graph_divy eq {}} { set graph_divy 5}
|
|
.graphdialog.top2.divy insert 0 $graph_divy
|
|
|
|
set graph_subdivx [xschem getprop rect 2 $graph_selected subdivx]
|
|
if {$graph_subdivx eq {}} { set graph_subdivx 1}
|
|
.graphdialog.top2.subdivx insert 0 $graph_subdivx
|
|
|
|
set graph_subdivy [xschem getprop rect 2 $graph_selected subdivy]
|
|
if {$graph_subdivy eq {}} { set graph_subdivy 1}
|
|
.graphdialog.top2.subdivy insert 0 $graph_subdivy
|
|
|
|
set graph_unitx [xschem getprop rect 2 $graph_selected unitx]
|
|
if {$graph_unitx eq {}} { set graph_unitx 1}
|
|
.graphdialog.top2.unitx set $graph_unitx
|
|
|
|
set graph_unity [xschem getprop rect 2 $graph_selected unity]
|
|
if {$graph_unity eq {}} { set graph_unity 1}
|
|
.graphdialog.top2.unity set $graph_unity
|
|
|
|
set graph_mode [xschem getprop rect 2 $graph_selected mode]
|
|
if {$graph_mode eq {}} { set graph_mode Line}
|
|
.graphdialog.top2.mode set $graph_mode
|
|
|
|
pack .graphdialog.top2.labunitx .graphdialog.top2.unitx \
|
|
.graphdialog.top2.labunity .graphdialog.top2.unity -side left
|
|
|
|
pack .graphdialog.top2.labdivx .graphdialog.top2.divx \
|
|
.graphdialog.top2.labdivy .graphdialog.top2.divy \
|
|
.graphdialog.top2.labsubdivx .graphdialog.top2.subdivx \
|
|
.graphdialog.top2.labsubdivy .graphdialog.top2.subdivy -side left
|
|
pack .graphdialog.top2.labmode .graphdialog.top2.mode .graphdialog.top2.labsweep -side left
|
|
pack .graphdialog.top2.sweep -side left -fill x -expand yes
|
|
|
|
# top frame
|
|
checkbutton .graphdialog.top.bus -text Bus -padx 2 -variable graph_bus
|
|
checkbutton .graphdialog.top.incr -text {Incr. sort} -variable graph_sort -indicatoron 1 \
|
|
-command graph_fill_listbox
|
|
checkbutton .graphdialog.top.rainbow -text {Rainbow col.} -variable graph_rainbow \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected rainbow $graph_rainbow
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
label .graphdialog.top.lw -text " Line width:"
|
|
entry .graphdialog.top.lwe -width 4
|
|
entry_replace_selection .graphdialog.top.lwe
|
|
bind .graphdialog.top.lwe <KeyRelease> {
|
|
graph_set_linewidth $graph_selected
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
set custom_lw [xschem getprop rect 2 $n linewidth_mult]
|
|
if {[regexp {^[ \t]*$} $custom_lw]} {
|
|
.graphdialog.top.lwe insert 0 $graph_linewidth_mult
|
|
} else {
|
|
.graphdialog.top.lwe insert 0 $custom_lw
|
|
}
|
|
|
|
label .graphdialog.top.labdset -text { Dataset}
|
|
entry .graphdialog.top.dset -width 4
|
|
entry_replace_selection .graphdialog.top.dset
|
|
bind .graphdialog.top.dset <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected dataset [.graphdialog.top.dset get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
.graphdialog.top.dset insert 0 [xschem getprop rect 2 $graph_selected dataset]
|
|
|
|
checkbutton .graphdialog.top.priv_curs -text {Priv. Cursor} -variable graph_private_cursor \
|
|
-command {set_rect_flags $graph_selected }
|
|
|
|
checkbutton .graphdialog.top.unlocked -text {Unlock. X axis} -variable graph_unlocked \
|
|
-command {set_rect_flags $graph_selected }
|
|
|
|
checkbutton .graphdialog.top.dig -text {Digital} -variable graph_digital -indicatoron 1 \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected digital $graph_digital
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
label .graphdialog.top3.xlabmin -text { X min:}
|
|
entry .graphdialog.top3.xmin -width 7
|
|
entry_replace_selection .graphdialog.top3.xmin
|
|
bind .graphdialog.top3.xmin <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected x1 [.graphdialog.top3.xmin get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
label .graphdialog.top3.xlabmax -text { X max:}
|
|
entry .graphdialog.top3.xmax -width 7
|
|
entry_replace_selection .graphdialog.top3.xmax
|
|
bind .graphdialog.top3.xmax <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected x2 [.graphdialog.top3.xmax get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
|
|
label .graphdialog.top3.ylabmin -text { Y min:}
|
|
entry .graphdialog.top3.ymin -width 7
|
|
entry_replace_selection .graphdialog.top3.ymin
|
|
bind .graphdialog.top3.ymin <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected y1 [.graphdialog.top3.ymin get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top3.ylabmax -text { Y max:}
|
|
entry .graphdialog.top3.ymax -width 7
|
|
entry_replace_selection .graphdialog.top3.ymax
|
|
bind .graphdialog.top3.ymax <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected y2 [.graphdialog.top3.ymax get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top3.xlabmag -text { X/Y lab mag:}
|
|
entry .graphdialog.top3.xmag -width 4
|
|
entry_replace_selection .graphdialog.top3.xmag
|
|
bind .graphdialog.top3.xmag <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected xlabmag [.graphdialog.top3.xmag get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top3.ylabmag -text { }
|
|
entry .graphdialog.top3.ymag -width 4
|
|
entry_replace_selection .graphdialog.top3.ymag
|
|
bind .graphdialog.top3.ymag <KeyRelease> {
|
|
graph_push_undo
|
|
xschem setprop rect 2 $graph_selected ylabmag [.graphdialog.top3.ymag get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
|
|
pack .graphdialog.top.legend -side left
|
|
pack .graphdialog.top.incr -side left
|
|
pack .graphdialog.top.bus -side left
|
|
pack .graphdialog.top.priv_curs -side left
|
|
pack .graphdialog.top.dig -side left
|
|
pack .graphdialog.top.unlocked -side left
|
|
pack .graphdialog.top.rainbow -side left
|
|
pack .graphdialog.top.lw -side left
|
|
pack .graphdialog.top.lwe -side left
|
|
pack .graphdialog.top.labdset -side left
|
|
pack .graphdialog.top.dset -side left
|
|
.graphdialog.top3.ymin insert 0 [xschem getprop rect 2 $graph_selected y1]
|
|
.graphdialog.top3.ymax insert 0 [xschem getprop rect 2 $graph_selected y2]
|
|
.graphdialog.top3.xmin insert 0 [xschem getprop rect 2 $graph_selected x1]
|
|
.graphdialog.top3.xmax insert 0 [xschem getprop rect 2 $graph_selected x2]
|
|
.graphdialog.top3.xmag insert 0 [xschem getprop rect 2 $graph_selected xlabmag]
|
|
.graphdialog.top3.ymag insert 0 [xschem getprop rect 2 $graph_selected ylabmag]
|
|
|
|
# top3 frame
|
|
set graph_rainbow [xschem getprop rect 2 $graph_selected rainbow]
|
|
set graph_logx [xschem getprop rect 2 $graph_selected logx]
|
|
set graph_logy [xschem getprop rect 2 $graph_selected logy]
|
|
if { $graph_rainbow eq {} } { set graph_rainbow 0 }
|
|
if { $graph_logx eq {} } { set graph_logx 0 }
|
|
if { $graph_logy eq {} } { set graph_logy 0 }
|
|
checkbutton .graphdialog.top3.logx -padx 2 -text {Log X} -variable graph_logx \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected logx $graph_logx
|
|
if { $graph_logx eq 1} {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected subdivx 8
|
|
.graphdialog.top2.subdivx delete 0 end
|
|
.graphdialog.top2.subdivx insert 0 8
|
|
xschem setprop rect 2 $graph_selected fullxzoom
|
|
xschem setprop rect 2 $graph_selected fullyzoom
|
|
} else {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected subdivx 4
|
|
.graphdialog.top2.subdivx delete 0 end
|
|
.graphdialog.top2.subdivx insert 0 4
|
|
xschem setprop rect 2 $graph_selected fullxzoom
|
|
xschem setprop rect 2 $graph_selected fullyzoom
|
|
}
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
|
|
checkbutton .graphdialog.top3.logy -text {Log Y} -variable graph_logy \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected logy $graph_logy
|
|
if { $graph_logy eq 1} {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected subdivy 8
|
|
.graphdialog.top2.subdivy delete 0 end
|
|
.graphdialog.top2.subdivy insert 0 8
|
|
xschem setprop rect 2 $graph_selected fullyzoom
|
|
} else {
|
|
graph_push_undo
|
|
xschem setprop -fast rect 2 $graph_selected subdivy 4
|
|
.graphdialog.top2.subdivy delete 0 end
|
|
.graphdialog.top2.subdivy insert 0 4
|
|
xschem setprop rect 2 $graph_selected fullyzoom
|
|
}
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
pack .graphdialog.top3.logx .graphdialog.top3.logy \
|
|
.graphdialog.top3.xlabmin .graphdialog.top3.xmin .graphdialog.top3.xlabmax .graphdialog.top3.xmax \
|
|
.graphdialog.top3.ylabmin .graphdialog.top3.ymin .graphdialog.top3.ylabmax .graphdialog.top3.ymax \
|
|
.graphdialog.top3.xlabmag .graphdialog.top3.xmag .graphdialog.top3.ylabmag .graphdialog.top3.ymag \
|
|
-fill x -expand yes -side left
|
|
# binding
|
|
bind .graphdialog.center.left.search <KeyRelease> {
|
|
graph_fill_listbox
|
|
}
|
|
bind .graphdialog.center.left.list1 <Double-Button-1> {
|
|
graph_add_nodes
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
}
|
|
}
|
|
|
|
bind .graphdialog.center.right.text1 <KeyRelease> {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
}
|
|
}
|
|
bind .graphdialog <Control-Return> {
|
|
.graphdialog.bottom.ok invoke
|
|
}
|
|
bind .graphdialog <Escape> {
|
|
.graphdialog.bottom.cancel invoke
|
|
}
|
|
wm protocol .graphdialog WM_DELETE_WINDOW {
|
|
.graphdialog.bottom.cancel invoke
|
|
}
|
|
# fill data in left listbox
|
|
graph_fill_listbox
|
|
|
|
# fill data in right textbox
|
|
set plotted_nodes [xschem getprop rect 2 $n node 2]
|
|
if {[string length $plotted_nodes] > 0 && [string index $plotted_nodes end] ne "\n"} {append plotted_nodes \n}
|
|
.graphdialog.center.right.text1 insert 1.0 $plotted_nodes
|
|
graph_update_nodelist
|
|
# add stuff in textbox at end of line + 1 char (after newline)
|
|
# .graphdialog.center.right.text1 insert {insert lineend + 1 char} foo\n
|
|
# tkwait window .graphdialog
|
|
wm deiconify .graphdialog
|
|
if {$graph_dialog_default_geometry ne {}} { wm geometry .graphdialog $graph_dialog_default_geometry}
|
|
}
|
|
|
|
proc graph_show_measure {{action show}} {
|
|
global measure_id measure_text has_x
|
|
|
|
if {![info exists has_x]} return;
|
|
set_ne measure_text "y=\nx="
|
|
if { [info exists measure_id] } {
|
|
after cancel $measure_id
|
|
unset measure_id
|
|
}
|
|
destroy .measure
|
|
if {$action eq {stop}} { return }
|
|
set measure_id [after 400 {
|
|
unset measure_id
|
|
toplevel .measure -background {}
|
|
label .measure.lab -text $measure_text -background black -fg yellow -justify left
|
|
pack .measure.lab
|
|
wm overrideredirect .measure 1
|
|
wm geometry .measure +[expr {[winfo pointerx .measure] +10}]+[expr {[winfo pointery .measure] -8}]
|
|
}]
|
|
}
|
|
|
|
# launch a terminal shell, if 'curpath' is given set path to 'curpath'
|
|
proc get_shell { {curpath {}} } {
|
|
global netlist_dir debug_var
|
|
global terminal
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set save [pwd]
|
|
if { $curpath ne {} } {
|
|
cd $curpath
|
|
eval execute 0 $terminal
|
|
} else {
|
|
eval execute 0 $terminal
|
|
}
|
|
cd $save
|
|
}
|
|
|
|
proc edit_netlist {netlist } {
|
|
global netlist_dir debug_var
|
|
global editor terminal OS
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set netlist_type [xschem get netlist_type]
|
|
|
|
if { [regexp vim $editor] } { set ftype "-c \":set filetype=$netlist_type\"" } else { set ftype {} }
|
|
if { [set_netlist_dir 0] ne "" } {
|
|
set save [pwd]
|
|
cd $netlist_dir
|
|
if {$OS == "Windows"} {
|
|
set cmd "$editor \"${netlist}\""
|
|
eval exec $cmd &
|
|
} else {
|
|
eval execute 0 $editor $ftype \"${netlist}\"
|
|
}
|
|
cd $save
|
|
}
|
|
return {}
|
|
}
|
|
|
|
|
|
# 20180926
|
|
# global_initdir should be set to:
|
|
# INITIALLOADDIR for load
|
|
# INITIALINSTDIR for instance placement
|
|
# ext: .sch or .sym or .sch.sym or .sym.sch
|
|
#
|
|
proc save_file_dialog { msg ext global_initdir {initialf {}} {overwrt 1} } {
|
|
upvar #0 $global_initdir initdir
|
|
set temp $initdir
|
|
if { $initialf ne {}} {
|
|
set initialdir [file dirname $initialf]
|
|
set initialf [file tail $initialf]
|
|
} else {
|
|
set initialdir $initdir
|
|
set initialf {}
|
|
}
|
|
set initdir $initialdir
|
|
set r [load_file_dialog $msg $ext $global_initdir 0 $overwrt $initialf]
|
|
set initdir $temp
|
|
return $r
|
|
}
|
|
|
|
# opens indicated instance (or selected one) into a separate tab/window
|
|
# keeping the hierarchy path, as it was descended into (as with 'e' key).
|
|
proc open_sub_schematic {{inst {}} {inst_number 0}} {
|
|
global search_schematic
|
|
set rawfile {}
|
|
set n_sel [xschem get lastsel]
|
|
|
|
if { $inst eq {} && $n_sel == 0} {
|
|
if {$search_schematic == 1} {
|
|
set f [abs_sym_path [xschem get current_name] {.sch}]
|
|
} else {
|
|
set f [file rootname [xschem get schname]].sch
|
|
}
|
|
xschem new_schematic create {} $f
|
|
return 1
|
|
} elseif { $inst eq {} && $n_sel == 1} {
|
|
set inst [lindex [xschem selected_set] 0]
|
|
xschem unselect_all
|
|
} else {
|
|
set instlist {}
|
|
# get list of instances (instance names only)
|
|
foreach {i s t} [xschem instance_list] {lappend instlist $i}
|
|
# if provided $inst is not in the list return 0
|
|
if {[lsearch -exact $instlist $inst] == -1} {return 0}
|
|
}
|
|
# open a new top level in another window / tab
|
|
if {[xschem raw loaded] >= 0} {
|
|
set rawfile [xschem raw_query rawfile]
|
|
set sim_type [xschem raw_query sim_type]
|
|
}
|
|
set res [xschem schematic_in_new_window force]
|
|
# if successfull descend into indicated sub-schematic
|
|
if {$res} {
|
|
xschem copy_hilights
|
|
xschem new_schematic switch [xschem get last_created_window]
|
|
if { $rawfile ne {}} {
|
|
if {$sim_type eq {op}} {
|
|
xschem annotate_op $rawfile
|
|
} else {
|
|
xschem raw_read $rawfile $sim_type
|
|
}
|
|
}
|
|
xschem select instance $inst fast
|
|
xschem descend
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
|
|
proc is_xschem_file {f} {
|
|
# puts "is_xschem_file $f"
|
|
regsub {\(.*} $f {} f ;# remove trailing generator args (gen.tcl(....)) if any
|
|
if { ![file exists $f] } { return 0
|
|
} elseif { [file isdirectory $f] } { return 0 }
|
|
set a [catch {open "$f" r} fd]
|
|
set ret 0
|
|
set score 0
|
|
set instances 0
|
|
set symbol 0
|
|
set nline 0
|
|
set generator 0
|
|
if {$a} {
|
|
puts stderr "Can not open file $f"
|
|
} else {
|
|
fconfigure $fd -translation binary
|
|
while { [gets $fd line] >=0 } {
|
|
|
|
#### Can not use this. schematics may containg 8 bit extended characters
|
|
# if {[regexp {[^[:print:][:space:]]} $line]} { ;# line contains non ascii chars
|
|
# close $fd
|
|
# return 0
|
|
# }
|
|
|
|
# this is a script. not an xschem file
|
|
if { $nline == 0 && [regexp {^#!} $line] } {
|
|
#### too dangerous executing an arbitrary script...
|
|
# close $fd
|
|
# set fd [open "|$f"]
|
|
set generator 1
|
|
break
|
|
# continue
|
|
}
|
|
if { [regexp {format *= *"@} $line] } { incr symbol; incr score}
|
|
if { [regexp {template *= *"} $line] } { incr symbol; incr score}
|
|
if { [regexp {^[TKFGVSE] \{} $line] } { incr score }
|
|
if { [regexp {^[BL] +[0-9]+ +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +\{} $line] } {incr score}
|
|
if { [regexp {^N +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +\{} $line] } {incr score}
|
|
if { [regexp {^C +\{[^{}]+\} +[-0-9.eE]+ +[-0-9.eE]+ +[0-3]+ +[0-3]+ +\{} $line] } {
|
|
incr instances
|
|
incr score
|
|
if {[regexp {ipin\.sym|opin\.sym|iopin\.sym} $line]} {set symbol 0}
|
|
}
|
|
|
|
if { [regexp "^v\[ \t\]+\{xschem\[ \t\]+version\[ \t\]*=.*\[ \t\]+file_version\[ \t\]*=" $line] } {
|
|
set ret 1
|
|
}
|
|
if {$instances >= 4} {break}
|
|
if {$score > 2000} {break} ;# give up on extremely big files
|
|
incr nline
|
|
}
|
|
if { $score > 4 } { set ret 1} ;# Heuristic decision :-)
|
|
if {$generator eq {1}} {
|
|
set ret GENERATOR
|
|
} elseif { $ret ne {0}} {
|
|
if {$symbol && $instances < 4} {
|
|
set ret SYMBOL
|
|
} else {
|
|
set ret SCHEMATIC
|
|
}
|
|
}
|
|
close $fd
|
|
}
|
|
# puts "ret=$ret score=$score"
|
|
return $ret
|
|
}
|
|
|
|
# "xschem hash_string" in scheduler.c is faster
|
|
proc hash_string {s} {
|
|
set hash 5381
|
|
set len [string length $s]
|
|
for {set i 0} { $i < $len} { incr i} {
|
|
set c [string index $s $i]
|
|
set ascii [scan $c %c]
|
|
set hash [expr {($hash + ($hash << 5) + $ascii)%4294967296} ]
|
|
}
|
|
return $hash
|
|
}
|
|
|
|
## Recent component toolbar
|
|
namespace eval c_toolbar {
|
|
# Create a variable inside the namespace
|
|
variable c_t
|
|
variable i
|
|
set c_t(w) .load.l.recent
|
|
set c_t(hash) [xschem hash_string $::XSCHEM_LIBRARY_PATH]
|
|
set c_t(n) 25
|
|
set c_t(top) 0
|
|
for {set i 0} {$i < $c_t(n)} {incr i} {
|
|
set c_t($i,text) {}
|
|
set c_t($i,file) {}
|
|
}
|
|
|
|
proc clear {} {
|
|
variable c_t
|
|
## restore new recent component list...
|
|
### ... first delete...
|
|
if {[info exists c_t(n)]} {
|
|
set c_t(top) 0
|
|
for {set i 0} {$i < $c_t(n)} {incr i} {
|
|
set c_t($i,text) {}
|
|
set c_t($i,file) {}
|
|
}
|
|
}
|
|
# ... then reload.
|
|
set c_t(hash) [xschem hash_string $::XSCHEM_LIBRARY_PATH]
|
|
}
|
|
|
|
proc cleanup {} {
|
|
variable c_t
|
|
if {![info exists c_t(n)]} return
|
|
set j 0
|
|
set n $c_t(n)
|
|
set top $c_t(top)
|
|
set i $top
|
|
while {1} {
|
|
set f [abs_sym_path $c_t($i,file)]
|
|
if { $c_t($i,text) eq {} } {break}
|
|
if { $j } {
|
|
set k [expr {$i - $j}]
|
|
if {$k < 0 } { set k [expr {$k + $n}]}
|
|
set c_t($k,text) $c_t($i,text)
|
|
set c_t($k,file) $c_t($i,file)
|
|
set c_t($i,text) {}
|
|
set c_t($i,file) {}
|
|
}
|
|
if {$f ne {} && ![file exists $f]} {
|
|
incr j
|
|
} elseif {[array names files -exact $f] ne {}} {
|
|
incr j
|
|
}
|
|
set files($f) 1
|
|
set i [expr {($i + 1) % $n} ]
|
|
if {$i == $top} break
|
|
}
|
|
}
|
|
|
|
proc command {i} {
|
|
variable c_t
|
|
set f $c_t($i,file)
|
|
set file_dialog_retval {}
|
|
if {[xschem get ui_state] & 8192 } { xschem abort_operation }
|
|
file_dialog_display_preview $f
|
|
xschem place_symbol $f
|
|
}
|
|
|
|
proc display {} {
|
|
global has_x
|
|
variable c_t
|
|
|
|
if {![info exists has_x]} {return}
|
|
|
|
if { [winfo exists $c_t(w)]} {
|
|
set w $c_t(w)
|
|
set n $c_t(n)
|
|
cleanup
|
|
destroy $w.title
|
|
for {set i 0} {$i < $n} {incr i} {
|
|
destroy $w.b$i
|
|
}
|
|
set i $c_t(top)
|
|
button $w.title -text Recent -takefocus 0 -pady 0 -padx 0 -state disabled -disabledforeground black \
|
|
-background grey60 -borderwidth 0 -font {TkDefaultFont 12 bold}
|
|
pack $w.title -side top -fill x
|
|
while {1} {
|
|
button $w.b$i -text $c_t($i,text) -pady 0 -padx 0 -command "c_toolbar::command $i" -takefocus 0
|
|
pack $w.b$i -side top -fill x
|
|
set i [expr {($i + 1) % $n}]
|
|
if { $i == $c_t(top) } break
|
|
}
|
|
}
|
|
}
|
|
|
|
proc add {f} {
|
|
variable c_t
|
|
for {set i 0} {$i < $c_t(n)} {incr i} {
|
|
if { $c_t($i,file) eq $f } { return 0}
|
|
}
|
|
set ret 0
|
|
set ret 1
|
|
set i [expr { ($c_t(top)-1) % $c_t(n) } ];# last element
|
|
set c_t($i,file) $f
|
|
set c_t($i,text) [file tail [file rootname $f]]
|
|
set c_t(top) $i
|
|
if {$ret} {write_recent_file}
|
|
return $ret
|
|
}
|
|
}
|
|
## end c_toolbar namespace
|
|
|
|
proc file_dialog_set_colors1 {} {
|
|
global file_dialog_files1 dircolor
|
|
for {set i 0} { $i< [.load.l.paneleft.list index end] } { incr i} {
|
|
set maxlen 0
|
|
set name "[lindex $file_dialog_files1 $i]"
|
|
.load.l.paneleft.list itemconfigure $i -foreground black -selectforeground black
|
|
foreach j [array names dircolor] {
|
|
set pattern $j
|
|
set color $dircolor($j)
|
|
set len [string length [regexp -inline $pattern $name]]
|
|
if { $len > $maxlen } {
|
|
.load.l.paneleft.list itemconfigure $i -foreground $color -selectforeground $color
|
|
set maxlen $len
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc file_dialog_set_colors2 {} {
|
|
global file_dialog_index1 file_dialog_files2 dircolor file_dialog_files1
|
|
set dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]]
|
|
for {set i 0} { $i< [.load.l.paneright.f.list index end] } { incr i} {
|
|
set maxlen 0
|
|
set name "$dir1/[lindex $file_dialog_files2 $i]"
|
|
if {[ file isdirectory $name]} {
|
|
.load.l.paneright.f.list itemconfigure $i -foreground blue
|
|
foreach j [array names dircolor] {
|
|
set pattern $j
|
|
set color $dircolor($j)
|
|
set len [string length [regexp -inline $pattern $dir1]]
|
|
# puts "len=$len\npattern=$pattern\nname=$name\n\n\n"
|
|
if { $len > $maxlen } {
|
|
.load.l.paneright.f.list itemconfigure $i -foreground $color -selectforeground $color
|
|
set maxlen $len
|
|
}
|
|
}
|
|
|
|
} else {
|
|
.load.l.paneright.f.list itemconfigure $i -foreground black
|
|
}
|
|
}
|
|
}
|
|
|
|
proc file_dialog_set_names1 {} {
|
|
global file_dialog_names1 file_dialog_files1 load_file_dialog_fullpath
|
|
|
|
set file_dialog_names1 {}
|
|
foreach i $file_dialog_files1 {
|
|
if { $load_file_dialog_fullpath == 1} {
|
|
set item $i
|
|
} else {
|
|
set item [get_cell $i 0]
|
|
}
|
|
lappend file_dialog_names1 $item
|
|
}
|
|
}
|
|
|
|
proc file_dialog_set_home {dir} {
|
|
global pathlist file_dialog_files1 file_dialog_index1 file_dialog_names1
|
|
|
|
set curr_dirname [xschem get current_dirname]
|
|
.load.l.paneleft.list selection clear 0 end
|
|
if { $dir eq {.}} { set dir $curr_dirname}
|
|
# puts "set home: dir=$dir, pathlist=$pathlist"
|
|
set pl {}
|
|
foreach path_elem $pathlist {
|
|
if { ![string compare $path_elem .]} {
|
|
set path_elem $curr_dirname
|
|
}
|
|
lappend pl $path_elem
|
|
}
|
|
set i [lsearch -exact $pl $dir]
|
|
if { $i>=0 } {
|
|
set file_dialog_files1 $pathlist
|
|
file_dialog_set_names1
|
|
update
|
|
file_dialog_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
set file_dialog_index1 $i
|
|
.load.l.paneleft.list selection set $file_dialog_index1
|
|
} else {
|
|
set file_dialog_files1 [list $dir]
|
|
file_dialog_set_names1
|
|
update
|
|
file_dialog_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
set file_dialog_index1 0
|
|
.load.l.paneleft.list selection set 0
|
|
}
|
|
}
|
|
|
|
proc setglob {dir} {
|
|
global file_dialog_globfilter file_dialog_files2 OS
|
|
# puts "setglob: $dir, filter=$file_dialog_globfilter"
|
|
set file_dialog_files2 [lsort [glob -nocomplain -directory $dir -tails -type d .* *]]
|
|
if { $file_dialog_globfilter eq {*}} {
|
|
set file_dialog_files2 ${file_dialog_files2}\ [lsort [
|
|
glob -nocomplain -directory $dir -tails -type {f} .* $file_dialog_globfilter]]
|
|
} else {
|
|
if {$OS == "Windows"} {
|
|
regsub {:} $file_dialog_globfilter {\:} file_dialog_globfilter
|
|
}
|
|
|
|
if {![catch {glob -nocomplain -directory $dir -tails -type {f} $file_dialog_globfilter} res]} {
|
|
set flist $res
|
|
} else {
|
|
set flist [glob -nocomplain -directory $dir -tails -type {f} {*}]
|
|
}
|
|
set file_dialog_files2 ${file_dialog_files2}\ [lsort $flist]
|
|
}
|
|
}
|
|
|
|
proc load_file_dialog_mkdir {dir} {
|
|
global file_dialog_dir1 has_x
|
|
if { $dir ne {} } {
|
|
if {[catch {file mkdir "${file_dialog_dir1}/$dir"} err]} {
|
|
puts $err
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -message "$err" -icon error -parent [xschem get topwindow] -type ok
|
|
}
|
|
}
|
|
setglob ${file_dialog_dir1}
|
|
file_dialog_set_colors2
|
|
}
|
|
}
|
|
|
|
proc load_file_dialog_up {dir} {
|
|
global file_dialog_dir1
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
bind .load.l.paneright.draw <Configure> {}
|
|
.load.l.paneright.draw configure -background white
|
|
set d [file dirname $dir]
|
|
if { [file isdirectory $d]} {
|
|
file_dialog_set_home $d
|
|
setglob $d
|
|
file_dialog_set_colors2
|
|
set file_dialog_dir1 $d
|
|
}
|
|
}
|
|
|
|
|
|
proc file_dialog_getresult {loadfile confirm_overwrt} {
|
|
global file_dialog_dir1 file_dialog_retval file_dialog_ext has_x
|
|
if { $file_dialog_retval ne {}} {
|
|
if { [regexp {^https?://} $file_dialog_retval] } {
|
|
set fname $file_dialog_retval
|
|
} elseif { [regexp {^/} $file_dialog_retval]} {
|
|
set fname $file_dialog_retval
|
|
} else {
|
|
regsub {/*$} $file_dialog_dir1 {/} file_dialog_dir1
|
|
set fname "${file_dialog_dir1}${file_dialog_retval}"
|
|
}
|
|
if {![file exists "$fname"] } {
|
|
return "$fname"
|
|
}
|
|
if { $loadfile == 0 } {
|
|
if {[file exists "$fname"]} {
|
|
if {$confirm_overwrt == 1 } {
|
|
set answer [alert_ "Overwrite $fname?" {} 0 1]
|
|
} else {
|
|
set answer 1
|
|
}
|
|
if {$answer eq {1}} {
|
|
return "$fname"
|
|
} else {
|
|
set file_dialog_retval {}
|
|
return {}
|
|
}
|
|
}
|
|
}
|
|
set type [is_xschem_file "$fname"]
|
|
if { $type eq {0} || $type eq {GENERATOR} } {
|
|
if { $type eq {0} } {
|
|
set answer [alert_ "$fname does not seem to be an xschem file...\nContinue?" {} 0 1]
|
|
} else { ;# $type == GENERATOR
|
|
set answer 1
|
|
}
|
|
if { $answer eq {0}} {
|
|
set file_dialog_retval {}
|
|
return {}
|
|
} else { ;# $answer == 1
|
|
if { $type eq {GENERATOR} } {
|
|
return "${fname}"
|
|
}
|
|
# $type == 0 but $answer==1 so return selected filename
|
|
return "$fname"
|
|
}
|
|
# $type == SYMBOL or SCHEMATIC
|
|
} elseif { $type ne {SYMBOL} && ($file_dialog_ext eq {*.sym}) } { ;# SCHEMATIC
|
|
set answer [
|
|
alert_ "$fname does not seem to be a SYMBOL file...\nContinue?" {} 0 1]
|
|
if { $answer eq {0}} {
|
|
set file_dialog_retval {}
|
|
return {}
|
|
} else {
|
|
return "$fname"
|
|
}
|
|
} else { ;# SYMBOL
|
|
return "$fname"
|
|
}
|
|
} else {
|
|
return {}
|
|
}
|
|
}
|
|
|
|
proc file_dialog_place_symbol {} {
|
|
global file_dialog_retval
|
|
|
|
set entry [.load.buttons_bot.entry get]
|
|
# puts "entry=$entry"
|
|
set file_dialog_retval $entry
|
|
set sym [file_dialog_getresult 2 0]
|
|
# puts "sym=$sym"
|
|
if { [xschem get ui_state] & 8192 } {
|
|
xschem abort_operation
|
|
}
|
|
if {$sym ne {}} {
|
|
xschem place_symbol "$sym"
|
|
}
|
|
}
|
|
|
|
proc file_dialog_display_preview {f} {
|
|
set type [is_xschem_file $f]
|
|
if { $type ne {0} } {
|
|
if { [winfo exists .load] } {
|
|
.load.l.paneright.draw configure -background {}
|
|
xschem preview_window draw .load.l.paneright.draw "$f"
|
|
bind .load.l.paneright.draw <Expose> [subst {xschem preview_window draw .load.l.paneright.draw "$f"}]
|
|
bind .load.l.paneright.draw <Configure> [subst {xschem preview_window draw .load.l.paneright.draw "$f"}]
|
|
}
|
|
} else {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
bind .load.l.paneright.draw <Configure> {}
|
|
.load.l.paneright.draw configure -background white
|
|
}
|
|
}
|
|
|
|
proc file_dialog_right_listboxselect {dirselect} {
|
|
global file_dialog_yview file_dialog_dir1 file_dialog_dir2 file_dialog_retval file_dialog_sel
|
|
global OS file_dialog_loadfile file_dialog_index1 file_dialog_files1 file_dialog_globfilter
|
|
global file_dialog_others
|
|
set file_dialog_yview [.load.l.paneright.f.list yview]
|
|
set file_dialog_sel [lindex [.load.l.paneright.f.list curselection] 0]
|
|
|
|
if { $file_dialog_sel ne {} } {
|
|
set curr_dir [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]]
|
|
set curr_item [.load.l.paneright.f.list get $file_dialog_sel]
|
|
|
|
if {$curr_item eq {..}} {
|
|
set file_dialog_d [file dirname $curr_dir]
|
|
} elseif {$curr_item eq {.} } {
|
|
set file_dialog_d $curr_dir
|
|
} else {
|
|
if {$OS == "Windows"} {
|
|
if {[regexp {^[A-Za-z]\:/$} $curr_dir]} {
|
|
set file_dialog_d "$curr_dir$curr_item"
|
|
} else {
|
|
set file_dialog_d "$curr_dir/$curr_item"
|
|
}
|
|
} else {
|
|
if {$curr_dir eq "/"} {
|
|
set file_dialog_d "$curr_dir$curr_item"
|
|
} else {
|
|
set file_dialog_d "$curr_dir/$curr_item"
|
|
}
|
|
}
|
|
}
|
|
|
|
if { !$dirselect && [file isdirectory $file_dialog_d] } {
|
|
.load.buttons_bot.entry delete 0 end
|
|
set file_dialog_retval { }
|
|
return
|
|
}
|
|
|
|
set file_dialog_dir1 $curr_dir
|
|
set file_dialog_dir2 $curr_item
|
|
|
|
set file_dialog_others {}
|
|
if {$file_dialog_loadfile == 1} {
|
|
foreach i [lrange [.load.l.paneright.f.list curselection] 1 end] {
|
|
set file_dialog_retval [.load.l.paneright.f.list get $i]
|
|
lappend file_dialog_others [file_dialog_getresult 1 0]
|
|
}
|
|
}
|
|
set file_dialog_retval {} ;# we used this variable above to communicate with file_dialog_getresult
|
|
|
|
|
|
if { [file isdirectory $file_dialog_d]} {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
bind .load.l.paneright.draw <Configure> {}
|
|
.load.l.paneright.draw configure -background white
|
|
file_dialog_set_home $file_dialog_d
|
|
setglob $file_dialog_d
|
|
file_dialog_set_colors2
|
|
set file_dialog_dir1 $file_dialog_d
|
|
} else {
|
|
.load.buttons_bot.entry delete 0 end
|
|
.load.buttons_bot.entry insert 0 $file_dialog_dir2
|
|
|
|
file_dialog_display_preview $file_dialog_d
|
|
# puts "xschem preview_window draw .load.l.paneright.draw \"$file_dialog_dir1/$file_dialog_dir2\""
|
|
}
|
|
}
|
|
if {$file_dialog_loadfile == 2} {
|
|
# set to something different to any file to force a new placement in file_dialog_place_symbol
|
|
set file_dialog_retval { }
|
|
}
|
|
}
|
|
|
|
proc load_additional_files {} {
|
|
global file_dialog_others
|
|
|
|
if {$file_dialog_others ne {} } {
|
|
foreach i $file_dialog_others {
|
|
xschem load_new_window $i
|
|
}
|
|
}
|
|
}
|
|
|
|
# global_initdir: name of global variable containing the initial directory
|
|
# loadfile: set to 0 if calling for saving instead of loading a file
|
|
# set to 2 for non blocking operation (symbol insertion)
|
|
# confirm_overwrt: ask before overwriting an existing file
|
|
# initialf: fill the file entry box with this name (used when saving)
|
|
#
|
|
proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
|
|
{loadfile {1}} {confirm_overwrt {1}} {initialf {}}} {
|
|
global file_dialog_index1 file_dialog_files2 file_dialog_files1 file_dialog_retval file_dialog_dir1 pathlist OS
|
|
global file_dialog_default_geometry file_dialog_sp0 file_dialog_sp1 file_dialog_v_sp0 file_dialog_yview
|
|
global file_dialog_names1 tcl_version file_dialog_globfilter file_dialog_dir2
|
|
global file_dialog_save_initialfile file_dialog_loadfile file_dialog_ext
|
|
|
|
if { [winfo exists .load] } {
|
|
.load.buttons_bot.cancel invoke
|
|
}
|
|
set file_dialog_loadfile $loadfile
|
|
if {$ext ne {}} {set file_dialog_ext $ext}
|
|
set file_dialog_globfilter $file_dialog_ext
|
|
|
|
set file_dialog_save_initialfile $initialf
|
|
set file_dialog_retval {}
|
|
upvar #0 $global_initdir initdir
|
|
if { $loadfile != 2} {xschem set semaphore [expr {[xschem get semaphore] +1}]}
|
|
toplevel .load -class Dialog
|
|
wm title .load $msg
|
|
# wm transient .load [xschem get topwindow]
|
|
set_ne file_dialog_index1 0
|
|
if { ![info exists file_dialog_files1]} {
|
|
set file_dialog_files1 $pathlist
|
|
file_dialog_set_names1
|
|
update
|
|
set file_dialog_index1 0
|
|
}
|
|
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} \
|
|
-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 \
|
|
-xscrollcommand ".load.l.paneleft.xscroll set" -exportselection 0}]
|
|
if { ![catch {.load.l.paneleft.list cget -justify}]} {
|
|
.load.l.paneleft.list configure -justify right
|
|
}
|
|
file_dialog_set_colors1
|
|
scrollbar .load.l.paneleft.yscroll -command ".load.l.paneleft.list yview" -takefocus 0
|
|
scrollbar .load.l.paneleft.xscroll -command ".load.l.paneleft.list xview" -orient horiz -takefocus 0
|
|
bind .load.l.paneleft.list <<ListboxSelect>> {
|
|
set file_dialog_sel [.load.l.paneleft.list curselection]
|
|
if { $file_dialog_sel ne {} } {
|
|
set file_dialog_dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_sel]]
|
|
set file_dialog_index1 $file_dialog_sel
|
|
|
|
set file_dialog_globfilter *[.load.buttons_bot.src get]*
|
|
if { $file_dialog_globfilter eq {**} } { set file_dialog_globfilter * }
|
|
|
|
setglob $file_dialog_dir1
|
|
file_dialog_set_colors2
|
|
}
|
|
}
|
|
|
|
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}
|
|
} else {
|
|
set optnever {}
|
|
set optalways {}
|
|
}
|
|
|
|
|
|
eval .load.l.paneright paneconfigure .load.l.paneright.f $optnever
|
|
eval .load.l.paneright paneconfigure .load.l.paneright.draw $optalways
|
|
|
|
if {$global_initdir eq {INITIALINSTDIR}} {
|
|
set selmode browse
|
|
} else {
|
|
set selmode extended
|
|
}
|
|
|
|
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
|
|
scrollbar .load.l.paneright.f.xscroll -command ".load.l.paneright.f.list xview" -orient horiz -takefocus 0
|
|
|
|
if { $loadfile == 2} {
|
|
.load.l add .load.l.recent
|
|
c_toolbar::display
|
|
}
|
|
.load.l add .load.l.paneleft -minsize 40
|
|
.load.l add .load.l.paneright -minsize 150
|
|
eval .load.l paneconfigure .load.l.paneleft $optnever
|
|
eval .load.l paneconfigure .load.l.paneright $optalways
|
|
frame .load.buttons -takefocus 0
|
|
frame .load.buttons_bot -takefocus 0
|
|
button .load.buttons_bot.ok -width 5 -text OK -takefocus 0 -command "
|
|
set file_dialog_retval \[.load.buttons_bot.entry get\]
|
|
xschem preview_window destroy .load.l.paneright.draw {}
|
|
destroy .load
|
|
set $global_initdir \"\$file_dialog_dir1\"
|
|
"
|
|
button .load.buttons_bot.cancel -width 5 -text Cancel -takefocus 0 -command "
|
|
set file_dialog_retval {}
|
|
if {\$file_dialog_loadfile == 2} {xschem abort_operation}
|
|
xschem preview_window destroy .load.l.paneright.draw {}
|
|
destroy .load
|
|
set $global_initdir \"\$file_dialog_dir1\"
|
|
"
|
|
wm protocol .load WM_DELETE_WINDOW {.load.buttons_bot.cancel invoke}
|
|
button .load.buttons.home -width 5 -text {Home} -takefocus 0 -command {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
bind .load.l.paneright.draw <Configure> {}
|
|
.load.l.paneright.draw configure -background white
|
|
set file_dialog_files1 $pathlist
|
|
file_dialog_set_names1
|
|
update
|
|
file_dialog_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
set file_dialog_index1 0
|
|
set file_dialog_dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]]
|
|
setglob $file_dialog_dir1
|
|
file_dialog_set_colors2
|
|
.load.l.paneleft.list selection clear 0 end
|
|
.load.l.paneright.f.list selection clear 0 end
|
|
.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 -takefocus 0 \
|
|
-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 \
|
|
-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
|
|
if { $file_dialog_save_initialfile ne {} } {
|
|
.load.buttons_bot.entry insert 0 $file_dialog_save_initialfile
|
|
}
|
|
bind .load.buttons_bot.src <KeyRelease> {
|
|
if {$file_dialog_save_initialfile eq {} } {
|
|
set file_dialog_globfilter *[.load.buttons_bot.src get]*
|
|
if { $file_dialog_globfilter eq {**} } { set file_dialog_globfilter * }
|
|
setglob $file_dialog_dir1
|
|
if {[.load.buttons_bot.entry get] ne {}} {
|
|
.load.l.paneright.f.list yview moveto 1.0
|
|
} else {
|
|
if { [info exists file_dialog_yview]} {
|
|
.load.l.paneright.f.list yview moveto [lindex $file_dialog_yview 0]
|
|
}
|
|
}
|
|
}
|
|
# set to something different to any file to force a new placement in file_dialog_place_symbol
|
|
set file_dialog_retval { }
|
|
}
|
|
bind .load.buttons_bot.entry <ButtonPress> {
|
|
# set to something different to any file to force a new placement in file_dialog_place_symbol
|
|
set file_dialog_retval { }
|
|
}
|
|
|
|
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
|
|
entry_replace_selection .load.buttons.newdir
|
|
button .load.buttons.mkdir -width 5 -text Create -takefocus 0 -command {
|
|
load_file_dialog_mkdir [.load.buttons.newdir get]
|
|
}
|
|
button .load.buttons.rmdir -width 5 -text Delete -takefocus 0 -command {
|
|
if { [.load.buttons.newdir get] ne {} } {
|
|
file delete "${file_dialog_dir1}/[.load.buttons.newdir get]"
|
|
setglob ${file_dialog_dir1}
|
|
file_dialog_set_colors2
|
|
}
|
|
}
|
|
button .load.buttons.pwd -text {Current dir} -takefocus 0 -command {load_file_dialog_up [xschem get schname]}
|
|
checkbutton .load.buttons.path -text {Library paths} -variable load_file_dialog_fullpath -takefocus 0 \
|
|
-command {
|
|
file_dialog_set_names1
|
|
update
|
|
file_dialog_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
}
|
|
|
|
pack .load.l -expand true -fill both
|
|
pack .load.l.paneleft.yscroll -side right -fill y
|
|
pack .load.l.paneleft.xscroll -side bottom -fill x
|
|
pack .load.l.paneleft.list -fill both -expand true -padx 12
|
|
|
|
pack .load.buttons.home .load.buttons.up .load.buttons.pwd .load.buttons.path -side left
|
|
pack .load.buttons.mkdirlab -side left
|
|
pack .load.buttons.newdir -expand true -fill x -side left
|
|
pack .load.buttons.rmdir .load.buttons.mkdir -side right
|
|
pack .load.buttons_bot.srclab -side left
|
|
pack .load.buttons_bot.src -side left
|
|
pack .load.buttons_bot.label -side left
|
|
pack .load.buttons_bot.entry -side left -fill x -expand true
|
|
|
|
pack .load.l.paneright.f.yscroll -side right -fill y
|
|
pack .load.l.paneright.f.xscroll -side bottom -fill x
|
|
pack .load.l.paneright.f.list -side bottom -fill both -expand true
|
|
|
|
pack .load.buttons_bot.cancel .load.buttons_bot.ok -side left
|
|
pack .load.buttons_bot -side bottom -fill x
|
|
pack .load.buttons -side bottom -fill x
|
|
if { [info exists file_dialog_default_geometry]} {
|
|
wm geometry .load "${file_dialog_default_geometry}"
|
|
}
|
|
file_dialog_set_home $initdir
|
|
if { $loadfile != 2} {
|
|
bind .load <Return> "
|
|
set file_dialog_retval \[.load.buttons_bot.entry get\]
|
|
if {\$file_dialog_retval ne {} && !\[file isdirectory \$file_dialog_retval\]} {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
bind .load.l.paneright.draw <Configure> {}
|
|
xschem preview_window destroy .load.l.paneright.draw {}
|
|
destroy .load
|
|
set $global_initdir \"\$file_dialog_dir1\"
|
|
}
|
|
"
|
|
bind .load.l.paneright.f.list <Double-Button-1> "
|
|
set file_dialog_retval \[.load.buttons_bot.entry get\]
|
|
if {\$file_dialog_retval ne {} && !\[file isdirectory \$file_dialog_retval\]} {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
bind .load.l.paneright.draw <Configure> {}
|
|
xschem preview_window destroy .load.l.paneright.draw {}
|
|
destroy .load
|
|
set $global_initdir \"\$file_dialog_dir1\"
|
|
}
|
|
"
|
|
}
|
|
bind .load <Escape> "
|
|
set file_dialog_retval {}
|
|
if {\$file_dialog_loadfile == 2} {xschem abort_operation}
|
|
xschem preview_window destroy .load.l.paneright.draw {}
|
|
destroy .load
|
|
set $global_initdir \"\$file_dialog_dir1\"
|
|
"
|
|
bind .load <KeyPress-H> {.load.buttons.home invoke }
|
|
bind .load <KeyPress-U> {.load.buttons.up invoke }
|
|
### update
|
|
|
|
if { [info exists file_dialog_v_sp0] } {
|
|
eval .load.l.paneright sash mark 0 [.load.l.paneright sash coord 0]
|
|
eval .load.l.paneright sash dragto 0 [subst {1 $file_dialog_v_sp0}]
|
|
}
|
|
|
|
if { [info exists file_dialog_sp0] } {
|
|
if { $file_dialog_loadfile == 2} {
|
|
eval .load.l sash mark 1 [.load.l sash coord 1]
|
|
eval .load.l sash dragto 1 [subst {$file_dialog_sp0 1}]
|
|
} else {
|
|
eval .load.l sash mark 0 [.load.l sash coord 0]
|
|
eval .load.l sash dragto 0 [subst {$file_dialog_sp0 1}]
|
|
}
|
|
}
|
|
if { $file_dialog_loadfile == 2 && [info exists file_dialog_sp1] } {
|
|
eval .load.l sash mark 0 [.load.l sash coord 0]
|
|
eval .load.l sash dragto 0 [subst {$file_dialog_sp1 1}]
|
|
}
|
|
### update
|
|
.load.l.paneleft.list xview moveto 1
|
|
|
|
bind .load <Configure> {
|
|
set file_dialog_v_sp0 [lindex [.load.l.paneright sash coord 0] 1]
|
|
if { $file_dialog_loadfile == 2} {
|
|
set file_dialog_sp0 [lindex [.load.l sash coord 1] 0]
|
|
} else {
|
|
set file_dialog_sp0 [lindex [.load.l sash coord 0] 0]
|
|
}
|
|
if {$file_dialog_loadfile == 2} {
|
|
set file_dialog_sp1 [lindex [.load.l sash coord 0] 0]
|
|
}
|
|
set file_dialog_default_geometry [wm geometry .load]
|
|
.load.l.paneleft.list xview moveto 1
|
|
# regsub {\+.*} $file_dialog_default_geometry {} file_dialog_default_geometry
|
|
}
|
|
|
|
bind .load.l.paneright.f.yscroll <Motion> {
|
|
set file_dialog_yview [.load.l.paneright.f.list yview]
|
|
}
|
|
|
|
xschem preview_window create .load.l.paneright.draw {}
|
|
set file_dialog_dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]]
|
|
setglob $file_dialog_dir1
|
|
file_dialog_set_colors2
|
|
|
|
|
|
if {$file_dialog_loadfile == 2} {
|
|
bind .load <Leave> {
|
|
if { {%W} eq {.load} && $file_dialog_retval ne {} && [.load.buttons_bot.entry get] ne $file_dialog_retval} {
|
|
file_dialog_place_symbol
|
|
}
|
|
}
|
|
}
|
|
|
|
bind .load.l.paneright.f.list <KeyRelease-Return> {
|
|
file_dialog_right_listboxselect 1
|
|
}
|
|
|
|
bind .load.l.paneright.f.list <ButtonRelease-1> {
|
|
file_dialog_right_listboxselect 1
|
|
}
|
|
|
|
bind .load.l.paneright.f.list <KeyRelease-Up> {
|
|
file_dialog_right_listboxselect 0
|
|
}
|
|
|
|
bind .load.l.paneright.f.list <KeyRelease-Down> {
|
|
file_dialog_right_listboxselect 0
|
|
}
|
|
|
|
# bind .load.l.paneright.f.list <<ListboxSelect>> {
|
|
# file_dialog_right_listboxselect
|
|
# }
|
|
|
|
if { [info exists file_dialog_yview]} {
|
|
.load.l.paneright.f.list yview moveto [lindex $file_dialog_yview 0]
|
|
}
|
|
focus .load.buttons_bot.src
|
|
.load.buttons_bot.src selection range 0 end
|
|
if {$loadfile != 2} {
|
|
tkwait window .load
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
return [file_dialog_getresult $loadfile $confirm_overwrt]
|
|
}
|
|
|
|
# recursive procedure. Returns list of directories containing
|
|
# files by extension 'ext' from a list of supplied 'paths'
|
|
# if paths empty use XSCHEM_LIBRARY_PATH list.
|
|
# 'levels' is set to the number of levels to descend into.
|
|
# 'level' is used internally by the function and should not be set.
|
|
# incl_base_levels: if set to 1 always include level 0 dirs
|
|
proc get_list_of_dirs_with_files {{paths {}} {levels -1} \
|
|
{ext {\.(sch|sym)$}} \
|
|
{level -1} \
|
|
{incl_base_levels 1} \
|
|
} {
|
|
# puts "get_list_of_dirs_with_files paths=$paths"
|
|
global pathlist
|
|
set dir_with_symbols {}
|
|
if {$level == -1} { set level 0}
|
|
if {$levels >=0 && $level > $levels} {return {}}
|
|
if {$paths eq {}} {set paths $pathlist}
|
|
foreach i $paths {
|
|
# puts "dir:$i"
|
|
set filelist [glob -nocomplain -directory $i -type f *]
|
|
set there_are_symbols 0
|
|
if {$incl_base_levels == 0 || $level > 0} {
|
|
foreach f $filelist {
|
|
if {[regexp $ext $f]} {
|
|
# puts "match: $f"
|
|
set there_are_symbols 1
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if {($incl_base_levels && $level == 0) || $there_are_symbols} {
|
|
lappend dir_with_symbols $i
|
|
}
|
|
set dirlist [lsort -dictionary [glob -nocomplain -directory $i -type d *]]
|
|
if {$level < $levels} {
|
|
foreach d $dirlist {
|
|
set dirs [get_list_of_dirs_with_files [list $d] $levels $ext [expr {$level + 1} ]]
|
|
if { $dirs ne {}} {
|
|
foreach dd $dirs {
|
|
if {[lsearch $dir_with_symbols $dd] < 0} {
|
|
lappend dir_with_symbols $dd
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $dir_with_symbols
|
|
}
|
|
|
|
#######################################################################
|
|
##### new alternate file_chooser browser
|
|
#######################################################################
|
|
|
|
#### Display preview of selected symbol and start sym placement
|
|
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 "$f"
|
|
|
|
|
|
## preview window draw causes a save / restore context.
|
|
## restore_ctx writes XSCHEM_LIBRARY_PATH --> set_paths --> .ins.top3.upd invoke
|
|
## this rewrites the file_chooser(dirtails) list variable and list loses selection...
|
|
# .ins.center.leftdir.l selection set [.ins.center.leftdir.l index active]
|
|
|
|
bind .ins.center.right <Expose> "xschem preview_window draw .ins.center.right {$f}"
|
|
bind .ins.center.right <Configure> "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 file_chooser_preview {} {
|
|
# puts "file_chooser_preview"
|
|
global file_chooser
|
|
if {[info exists file_chooser(f)]} {
|
|
after cancel ".ins.center.right configure -bg white"
|
|
after cancel "file_chooser_draw_preview {$file_chooser(f)}"
|
|
unset file_chooser(f)
|
|
}
|
|
xschem preview_window close .ins.center.right {}
|
|
bind .ins.center.right <Expose> {}
|
|
bind .ins.center.right <Configure> {}
|
|
set sel [lindex [.ins.center.left.l curselection] 0]
|
|
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 $file_chooser(fullpathlist) $sel]
|
|
# puts "file_chooser_preview: f=$f"
|
|
if {$f ne {}} {
|
|
set file_chooser(f) $f
|
|
set type [is_xschem_file $f]
|
|
if {$type ne {0}} {
|
|
set dir [rel_sym_path $f]
|
|
set file_chooser(abs_filename) $f
|
|
set file_chooser(rel_filename) $dir
|
|
# global used to cancel delayed script
|
|
after 200 "file_chooser_draw_preview {$f}"
|
|
} else {
|
|
after 200 {.ins.center.right configure -bg white}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc file_chooser_dirlist {} {
|
|
# puts "file_chooser_dirlist [xschem get topwindow]"
|
|
global file_chooser pathlist dark_gui_colorscheme new_file_browser_depth new_file_browser_ext
|
|
if {$dark_gui_colorscheme} { set col {cyan} } else { set col {blue} }
|
|
# regenerate list of dirs
|
|
set file_chooser(dirs) [
|
|
get_list_of_dirs_with_files {} $new_file_browser_depth $new_file_browser_ext
|
|
]
|
|
set file_chooser(dirtails) {}
|
|
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 file_chooser_filelist {} {
|
|
global file_chooser new_file_browser_ext
|
|
|
|
if {![info exists file_chooser(dirs)]} {return}
|
|
set sel [lindex [.ins.center.leftdir.l curselection] 0]
|
|
if {$sel eq {}} { return }
|
|
set file_chooser(dirindex) $sel
|
|
set path [lindex $file_chooser(dirs) $sel]
|
|
set file_chooser(abs_filename) $path
|
|
# check if regex is valid
|
|
set err [catch {regexp $file_chooser(regex) {12345}} res]
|
|
if {$err} {return}
|
|
set f {}
|
|
if {$path ne {} } {
|
|
set f [match_file $file_chooser(regex) [list $path] 0 $file_chooser(fullpath)]
|
|
}
|
|
set filelist {}
|
|
set file_chooser(fullpathlist) {}
|
|
set sel [lindex [.ins.center.left.l curselection] 0]
|
|
if {$sel ne {}} {
|
|
set file_chooser(fileindex) $sel
|
|
# puts "set fileindex=$sel"
|
|
}
|
|
if {$sel eq {}} { set sel 0}
|
|
.ins.center.left.l selection clear 0 end
|
|
.ins.center.left.l activate $sel
|
|
.ins.center.left.l selection set $sel
|
|
foreach i $f {
|
|
set err [catch {regexp $new_file_browser_ext $i} type]
|
|
if {!$err && $type} {
|
|
set fname [file tail $i]
|
|
lappend filelist $fname
|
|
lappend file_chooser(fullpathlist) $i
|
|
}
|
|
}
|
|
set file_chooser(nitems) [llength $filelist]
|
|
# assign listbox variable all at the end, it is faster...
|
|
set file_chooser(files) $filelist
|
|
}
|
|
|
|
# called when double clicking a file item in the file_chooser file listbox
|
|
proc file_chooser_symbol_or_schematic {{shift 0}} {
|
|
global file_chooser
|
|
if {[xschem get semaphore] > 0} {return}
|
|
set sel [.ins.center.left.l index active]
|
|
if {$sel ne {}} {
|
|
set f [lindex $file_chooser(fullpathlist) $sel]
|
|
if {$f ne {}} {
|
|
set type [is_xschem_file $f]
|
|
if {$type eq {SCHEMATIC}} {
|
|
if {$shift == 0} {
|
|
file_chooser_place load
|
|
} else {
|
|
file_chooser_place load_new_win
|
|
}
|
|
} elseif {$type eq {SYMBOL}} {
|
|
if {$shift == 0} {
|
|
set file_chooser(action) {symbol1} ;# only one time insert symbol
|
|
file_chooser_preview
|
|
} else {
|
|
file_chooser_place load_new_win
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc file_chooser_place {action} {
|
|
# puts file_chooser_place
|
|
global file_chooser open_in_new_window
|
|
if {[xschem get semaphore] > 0} {return}
|
|
set sel [.ins.center.left.l index active]
|
|
if {$sel ne {}} {
|
|
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
|
|
}
|
|
if {$action eq {symbol}} {
|
|
xschem place_symbol $f
|
|
} elseif {$action eq {load}} {
|
|
if {$open_in_new_window} {
|
|
xschem load_new_window $f
|
|
} else {
|
|
xschem load -gui $f
|
|
}
|
|
} elseif {$action eq {load_new_win}} {
|
|
xschem load_new_window $f
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc file_chooser_select {f} {
|
|
global file_chooser
|
|
if {$f ne {} && [info exists file_chooser(dirs)] && [info exists file_chooser(files)]} {
|
|
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 activate $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 activate $fileindex
|
|
.ins.center.left.l selection set $fileindex
|
|
.ins.center.left.l see $fileindex
|
|
file_chooser_preview
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc file_chooser_search {{current {}}} {
|
|
global file_chooser new_file_browser_depth new_file_browser_ext
|
|
# 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) {} $new_file_browser_depth $file_chooser(fullpath)
|
|
]
|
|
foreach i $allfiles {
|
|
set err [catch {regexp $new_file_browser_ext $i} type]
|
|
if {!$err && $type} {
|
|
incr nth
|
|
if {$current ne {}} {
|
|
set dir1 [file dirname $i]
|
|
set sel [.ins.center.leftdir.l index active]
|
|
if {$sel ne {}} {
|
|
set dir2 [lindex $file_chooser(dirs) $sel]
|
|
# puts " dir1=$dir1\n dir2=$dir2\n sel=$sel\n------\n"
|
|
if {$dir2 ne {}} {
|
|
if {$dir1 eq $dir2} {
|
|
set f $i
|
|
set file_chooser(nth) $nth
|
|
break
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if {$nth == $file_chooser(nth)} {
|
|
set f $i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if {$f ne {}} {
|
|
file_chooser_select $f
|
|
} 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_set_paths {} {
|
|
global XSCHEM_LIBRARY_PATH
|
|
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
|
|
}
|
|
}
|
|
|
|
proc file_chooser_edit_paths {} {
|
|
global pathlist XSCHEM_LIBRARY_PATH dark_gui_colorscheme file_chooser
|
|
if {$dark_gui_colorscheme} { set col {cyan} } else { set col {blue} }
|
|
set tctx::rcode 0
|
|
if {[winfo exists .editpaths]} {
|
|
raise .editpaths
|
|
return
|
|
}
|
|
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}]
|
|
file_chooser_set_paths
|
|
.ins.top3.upd invoke
|
|
destroy .editpaths
|
|
}
|
|
|
|
button .editpaths.bottom.apply -text Apply -command {
|
|
set tctx::rcode 1
|
|
set tctx::retval [.editpaths.center.paths get 1.0 {end - 1 chars}]
|
|
file_chooser_set_paths
|
|
.ins.top3.upd invoke
|
|
}
|
|
button .editpaths.bottom.dismiss -text Dismiss -command {
|
|
destroy .editpaths
|
|
}
|
|
button .editpaths.bottom.browse -text {Browse directory} -command {
|
|
file_chooser_browsedir
|
|
}
|
|
|
|
button .editpaths.bottom.show -text {Show resulting XSCHEM_LIBRARY_PATH} -command {
|
|
set tctx::rcode 1
|
|
set tctx::retval [.editpaths.center.paths get 1.0 {end - 1 chars}]
|
|
file_chooser_set_paths
|
|
.ins.top3.upd invoke
|
|
if {[winfo exists .editdata]} {destroy .editdata}
|
|
editdata "set XSCHEM_LIBRARY_PATH {$XSCHEM_LIBRARY_PATH}" {XSCHEM_LIBRARY_PATH} char 0
|
|
}
|
|
|
|
wm protocol .editpaths WM_DELETE_WINDOW {.editpaths.bottom.dismiss invoke}
|
|
bind .editpaths <KeyPress-Escape> {.editpaths.bottom.dismiss invoke}
|
|
pack .editpaths.bottom.ok .editpaths.bottom.apply .editpaths.bottom.dismiss -side left
|
|
pack .editpaths.bottom.browse .editpaths.bottom.show -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
|
|
}
|
|
|
|
proc file_chooser_saveas {} {
|
|
global file_chooser
|
|
|
|
set f $file_chooser(abs_filename)
|
|
if {[file exists $f]} {
|
|
if {[file isdirectory $f]} {return}
|
|
if {[xschem get modified]} { ;# modified
|
|
if {[xschem get schname] eq $f} { ;# file name not changed
|
|
xschem saveas
|
|
.ins.top2.save configure -bg [option get . background {}]
|
|
file_chooser_filelist
|
|
} else { ;# file name changed
|
|
set answer [tk_messageBox -message "Warning: file $f already exists. Overwrite?" \
|
|
-icon warning -parent .ins -type okcancel]
|
|
if {$answer ne {ok}} { return }
|
|
xschem saveas
|
|
.ins.top2.save configure -bg [option get . background {}]
|
|
file_chooser_filelist
|
|
}
|
|
} else { ;# not modified
|
|
if {[xschem get schname] eq $f} { ;# file name not changed
|
|
# ...
|
|
} else { ;# file name changed
|
|
set answer [tk_messageBox -message "Warning: file $f already exists. Overwrite?" \
|
|
-icon warning -parent .ins -type okcancel]
|
|
if {$answer ne {ok}} { return }
|
|
xschem saveas
|
|
.ins.top2.save configure -bg [option get . background {}]
|
|
file_chooser_filelist
|
|
}
|
|
}
|
|
} else { ;# file does not exist
|
|
xschem saveas $f
|
|
.ins.top2.save configure -bg [option get . background {}]
|
|
file_chooser_filelist
|
|
}
|
|
}
|
|
|
|
proc file_chooser_delete {} {
|
|
global file_chooser
|
|
|
|
set f $file_chooser(abs_filename)
|
|
if {[file exists $f]} {
|
|
if {[file isdirectory $f]} { return }
|
|
set answer [tk_messageBox -message "Delete $f ?" \
|
|
-icon warning -parent .ins -type okcancel]
|
|
if {$answer eq {ok}} {
|
|
file delete -force $f
|
|
file_chooser_filelist
|
|
}
|
|
}
|
|
}
|
|
|
|
#### maxdepth: how many levels to descend for each $paths directory (-1: no limit)
|
|
proc file_chooser {} {
|
|
global file_chooser new_file_browser_ext new_file_browser_depth USER_CONF_DIR
|
|
set file_chooser(action) load
|
|
set file_chooser(old_new_file_browser_ext) $new_file_browser_ext
|
|
set file_chooser(old_new_file_browser_depth) $new_file_browser_depth
|
|
set_ne file_chooser(fullpath) 0
|
|
set_ne file_chooser(ontop) 0
|
|
set file_chooser(enter) 1 ;# let file_chooser show current open schematic file name when mouse enters
|
|
# xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
if {[winfo exists .ins]} {
|
|
raise .ins
|
|
return
|
|
}
|
|
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
|
|
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
|
|
.ins.center add .ins.center.right
|
|
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 file_chooser(dirtails) -width 40 -height 5 \
|
|
-yscrollcommand ".ins.center.leftdir.s set" -highlightcolor red -highlightthickness 2 \
|
|
-activestyle underline -highlightbackground [option get . background {}] \
|
|
-exportselection 0
|
|
|
|
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 3000
|
|
listbox .ins.center.left.l -listvariable file_chooser(files) -width 20 -height 5 \
|
|
-yscrollcommand ".ins.center.left.s set" -highlightcolor red -highlightthickness 2 \
|
|
-activestyle underline -highlightbackground [option get . background {}] \
|
|
-exportselection 0
|
|
|
|
balloon .ins.center.left.l [string cat \
|
|
"List of symbols in selected directory\n" \
|
|
"Double click on a schematic will load in current window\n" \
|
|
"Shift-Double click on a schematic will load it in a new window\n" \
|
|
"Double click on a symbol will place the symbol in current window\n" \
|
|
"Shift-Double click on a symbol will load it in a new window"] 0 1 3000
|
|
scrollbar .ins.center.leftdir.s -command ".ins.center.leftdir.l yview" -takefocus 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
|
|
|
|
pack .ins.center.leftdir.l -expand 1 -fill both -side left
|
|
pack .ins.center.leftdir.s -fill y -side left
|
|
|
|
label .ins.top2.dir_l -text {Full path:}
|
|
entry .ins.top2.dir_e -width 20 -state normal -textvariable file_chooser(abs_filename) \
|
|
-readonlybackground [option get . background {}] -takefocus 0
|
|
|
|
button .ins.top2.save -takefocus 0 -text {Save current window} -command {
|
|
set file_chooser(regex) {}
|
|
file_chooser_select [xschem get schname]
|
|
file_chooser_saveas
|
|
}
|
|
button .ins.top2.delete -takefocus 0 -text {Delete} -command {
|
|
file_chooser_delete
|
|
}
|
|
|
|
balloon .ins.top2.delete "Delete the shown file"
|
|
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 -textvariable file_chooser(rel_filename) \
|
|
-readonlybackground [option get . background {}] -takefocus 0
|
|
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
|
|
}
|
|
balloon .ins.top.editpaths [string cat \
|
|
"Allows to edit XSCHEM_LIBRARY_PATH.\n" \
|
|
"A hash (#) before a line will comment out\n" \
|
|
"the path 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 {}
|
|
}
|
|
}
|
|
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 new_file_browser_depth
|
|
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 new_file_browser_ext
|
|
balloon .ins.top3.ext_e "Show only files matching the\nextension regular expression"
|
|
|
|
button .ins.top3.select_current -takefocus 0 -text {Select current} -command {
|
|
set file_chooser(regex) {}
|
|
file_chooser_select [xschem get schname]
|
|
}
|
|
balloon .ins.top3.select_current "Select directory and file name\nof current active xschem window"
|
|
|
|
button .ins.top3.upd -takefocus 0 -text "Reload" -command {
|
|
set file_chooser(abs_filename) {}
|
|
set file_chooser(rel_filename) {}
|
|
set file_chooser(fullpathlist) {}
|
|
set file_chooser(files) {}
|
|
.ins.center.left.l selection clear 0 end
|
|
xschem preview_window close .ins.center.right {}
|
|
.ins.center.right configure -bg white
|
|
file_chooser_dirlist
|
|
file_chooser_filelist
|
|
}
|
|
balloon .ins.top3.upd "Reset and reload list of files"
|
|
|
|
button .ins.top3.search_curr -takefocus 0 -text {Search curr. dir.} -activebackground red -command {
|
|
file_chooser_search current
|
|
}
|
|
balloon .ins.top3.search_curr "Show and select match\n in current directory"
|
|
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\nlooking in all directories"
|
|
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_preview
|
|
}
|
|
balloon .ins.top3.clear {Clear pattern entry box}
|
|
# -command {
|
|
# file_chooser_search
|
|
# file_chooser_filelist
|
|
# file_chooser_preview
|
|
# }
|
|
bind .ins <KeyPress-Escape> {.ins.bottom.dismiss invoke}
|
|
bind .ins <Enter> {
|
|
if {{%W} eq {.ins} && $file_chooser(enter) } {
|
|
# set file_chooser(regex) {}
|
|
# file_chooser_select [xschem get schname]
|
|
if {[xschem get modified]} {
|
|
.ins.top2.save configure -bg red
|
|
} else {
|
|
.ins.top2.save configure -bg [option get . background {}]
|
|
}
|
|
set file_chooser(enter) 0 ;# do not reset shown filename to current xschem filename when entering again
|
|
}
|
|
}
|
|
|
|
bind .ins.top3.pat_e <KeyRelease> {
|
|
file_chooser_search current
|
|
}
|
|
bind .ins.center.leftdir.l <<ListboxSelect>> {
|
|
listbox:select %W
|
|
if {[.ins.center.leftdir.l curselection] ne {}} {
|
|
set file_chooser(abs_filename) {}
|
|
set file_chooser(rel_filename) {}
|
|
set file_chooser(fullpathlist) {}
|
|
set file_chooser(files) {}
|
|
.ins.center.left.l selection clear 0 end
|
|
xschem preview_window close .ins.center.right {}
|
|
.ins.center.right configure -bg white
|
|
file_chooser_filelist
|
|
}
|
|
}
|
|
bind .ins.center.left.l <<ListboxSelect>> {
|
|
listbox:select %W
|
|
if {[.ins.center.left.l curselection] ne {}} {
|
|
if { [xschem get ui_state] & 8192 } {
|
|
xschem abort_operation
|
|
}
|
|
file_chooser_preview
|
|
}
|
|
}
|
|
bind .ins.center.left.l <KeyPress-Return> {
|
|
if {$file_chooser(action) eq {load}} {
|
|
.ins.bottom.load invoke
|
|
}
|
|
xschem preview_window close .ins.center.right {}
|
|
destroy .ins
|
|
}
|
|
label .ins.bottom.n -text { N. of items:}
|
|
label .ins.bottom.nitems -textvariable file_chooser(nitems)
|
|
button .ins.bottom.dismiss -takefocus 0 -text Dismiss -command {
|
|
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 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
|
|
}
|
|
|
|
button .ins.bottom.sym -text {Place symbol} -takefocus 0 \
|
|
-command {
|
|
set file_chooser(action) {symbol1} ;# only one time insert symbol
|
|
file_chooser_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_preview
|
|
}
|
|
}
|
|
balloon .ins.bottom.stickysym {persistent insert symbol mode}
|
|
|
|
bind .ins.center.left.l <Double-Button-1> {file_chooser_symbol_or_schematic 0}
|
|
bind .ins.center.left.l <Shift-Double-Button-1> {file_chooser_symbol_or_schematic 1}
|
|
|
|
wm protocol .ins WM_DELETE_WINDOW {.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.top2.delete -side left
|
|
pack .ins.top2.save -side left
|
|
pack .ins.top3.select_current -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_curr -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.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)}"
|
|
} elseif {[file exists $USER_CONF_DIR/file_chooser_geometry]} {
|
|
source $USER_CONF_DIR/file_chooser_geometry
|
|
set valid 0
|
|
set xmax [winfo screenwidth .]
|
|
set ymax [winfo screenheight .]
|
|
if {[info exists file_chooser(geometry)]} {
|
|
set n [scan $file_chooser(geometry) {%dx%d+%d+%d} x y dx dy]
|
|
if {$n == 4} {
|
|
# puts "xmax=$xmax, ymax=$ymax, x=$x, y=$y dx=$dx dy=$dy"
|
|
# off screen. do not use.
|
|
set valid 1
|
|
if { $dx > $xmax - 100 || $dy > $ymax - 100} {
|
|
set valid 0
|
|
}
|
|
}
|
|
}
|
|
if {$valid} {wm geometry .ins "${file_chooser(geometry)}"}
|
|
} else {
|
|
# wm geometry .ins 800x300
|
|
}
|
|
.ins.center paneconfigure .ins.center.leftdir -minsize [winfo reqwidth .ins.center.leftdir]
|
|
.ins.center paneconfigure .ins.center.left -minsize [winfo reqwidth .ins.center.left]
|
|
update
|
|
if { [info exists file_chooser(sp0)]} {
|
|
.ins.center sash place 0 $file_chooser(sp0) 1
|
|
}
|
|
if { [info exists file_chooser(sp1)]} {
|
|
.ins.center sash place 1 $file_chooser(sp1) 1
|
|
}
|
|
bind .ins <Configure> {
|
|
# puts "sash0: [.ins.center sash coord 0]"
|
|
# puts "sash1: [.ins.center sash coord 1]"
|
|
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]
|
|
|
|
write_data [string cat \
|
|
"set file_chooser(geometry) $file_chooser(geometry)\n" \
|
|
"set file_chooser(sp0) $file_chooser(sp0)\n" \
|
|
"set file_chooser(sp1) $file_chooser(sp1)\n" \
|
|
] $USER_CONF_DIR/file_chooser_geometry
|
|
}
|
|
file_chooser_dirlist
|
|
file_chooser_filelist
|
|
set file_chooser(old_dirs) $file_chooser(dirs)
|
|
return {}
|
|
}
|
|
#######################################################################
|
|
##### /new alternate file_chooser 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]
|
|
set l [llength $slist]
|
|
if { $n >= $l } {set n [expr {$l - 1}]}
|
|
set p {}
|
|
for {set i [expr {$l-1-$n}]} {$i < $l} { incr i } {
|
|
append p [lindex $slist $i]
|
|
if {$i < $l - 1} {
|
|
append p {/}
|
|
}
|
|
}
|
|
return $p
|
|
}
|
|
|
|
# chop last n path components from s
|
|
proc path_head {s n } {
|
|
set slist [file split $s]
|
|
set l [llength $slist]
|
|
if { $n < 0 } { set n 0 }
|
|
set p {}
|
|
for {set i 0} {$i < [expr {$l - $n}]} { incr i } {
|
|
append p [lindex $slist $i]
|
|
if {$i < $l -$n- 1 && ([lindex $slist $i] ne {/})} {
|
|
append p {/}
|
|
}
|
|
}
|
|
return $p
|
|
}
|
|
|
|
|
|
proc delete_files { dir } {
|
|
if { [info tclversion] >=8.4} {
|
|
set x [tk_getOpenFile -title "DELETE FILES" -multiple 1 -initialdir [file dirname $dir] ]
|
|
} else {
|
|
set x [tk_getOpenFile -title "DELETE FILES" -initialdir [file dirname $dir] ]
|
|
}
|
|
foreach i $x {
|
|
file delete $i
|
|
}
|
|
}
|
|
|
|
proc create_user_xschemrc {} {
|
|
global USER_CONF_DIR XSCHEM_SHAREDIR
|
|
|
|
if {![file exists $USER_CONF_DIR/xschemrc]} {
|
|
file copy $XSCHEM_SHAREDIR/xschemrc $USER_CONF_DIR/xschemrc
|
|
puts stderr "copied system $XSCHEM_SHAREDIR/xschemrc to $USER_CONF_DIR/xschemrc"
|
|
puts stderr "Please review the file and make your changes, then restart xschem"
|
|
} else {
|
|
puts stderr "$USER_CONF_DIR/xschemrc already exists, will not overwrite."
|
|
}
|
|
}
|
|
|
|
proc create_pins {} {
|
|
global env USER_CONF_DIR
|
|
global filetmp
|
|
|
|
set tctx::retval [ read_data_nonewline $filetmp ]
|
|
regsub -all {<} $tctx::retval {[} tctx::retval
|
|
regsub -all {>} $tctx::retval {]} tctx::retval
|
|
set lines [split $tctx::retval \n]
|
|
set dirprefix [file dirname [rel_sym_path [find_file_first ipin.sym]]]
|
|
if {$dirprefix == {.}} { set dirprefix {}} else {append dirprefix {/}}
|
|
|
|
# viewdata $tctx::retval
|
|
set pcnt 0
|
|
set y 0
|
|
set fd [open $USER_CONF_DIR/.clipboard.sch w]
|
|
foreach i $lines {
|
|
puts $fd "C \{${dirprefix}[lindex $i 1].sym\} 0 [set y [expr {$y-20}]] \
|
|
0 0 \{ name=p[incr pcnt] lab=[lindex $i 0] \}"
|
|
}
|
|
close $fd
|
|
xschem merge $USER_CONF_DIR/.clipboard.sch
|
|
}
|
|
|
|
proc rectorder {x1 y1 x2 y2} {
|
|
if {$x2 < $x1} {set tmp $x1; set x1 $x2; set x2 $tmp}
|
|
if {$y2 < $y1} {set tmp $y1; set y1 $y2; set y2 $tmp}
|
|
return [list $x1 $y1 $x2 $y2]
|
|
}
|
|
|
|
proc order {x1 y1 x2 y2} {
|
|
if {$x2 < $x1} {set tmp $x1; set x1 $x2; set x2 $tmp; set tmp $y1; set y1 $y2; set y2 $tmp
|
|
} elseif {$x2==$x1 && $y2<$y1} {set tmp $y1; set y1 $y2; set y2 $tmp}
|
|
return [list $x1 $y1 $x2 $y2]
|
|
}
|
|
|
|
proc rotation {x0 y0 x y rot flip} {
|
|
set tmp [expr {$flip? 2*$x0-$x : $x}]
|
|
if {$rot==0} {set rx $tmp; set ry $y }
|
|
if {$rot==1} {set rx [expr {$x0 - $y +$y0}]; set ry [expr {$y0+$tmp-$x0}]}
|
|
if {$rot==2} {set rx [expr {2*$x0-$tmp}]; set ry [expr {2*$y0-$y}]}
|
|
if {$rot==3} {set rx [expr {$x0+$y-$y0}]; set ry [expr {$y0-$tmp+$x0}]}
|
|
return [list $rx $ry]
|
|
}
|
|
|
|
proc schpins_to_sympins {} {
|
|
global env USER_CONF_DIR
|
|
set pinhsize 2.5
|
|
set first 1
|
|
xschem copy
|
|
set clipboard [read_data_nonewline $USER_CONF_DIR/.clipboard.sch]
|
|
set lines [split $clipboard \n]
|
|
set fd [open $USER_CONF_DIR/.clipboard.sch w]
|
|
foreach i $lines {
|
|
set ii [split [regexp -all -inline {\S+} $i]]
|
|
if {[regexp {^C \{.*(i|o|io)pin} $i ]} {
|
|
if {[regexp {ipin} [lindex $ii 1]]} { set dir in }
|
|
if {[regexp {opin} [lindex $ii 1]]} { set dir out }
|
|
if {[regexp {iopin} [lindex $ii 1]]} { set dir inout }
|
|
set rot [lindex $ii 4]
|
|
set flip [lindex $ii 5]
|
|
while {1} {
|
|
if { [regexp {lab=} $i] } {
|
|
regsub {^.*lab=} $i {} lab
|
|
regsub {[\} ].*} $lab {} lab
|
|
}
|
|
if { [regexp {\}} $i]} { break}
|
|
}
|
|
set x0 [lindex $ii 2]
|
|
set y0 [lindex $ii 3]
|
|
if {$first} {
|
|
puts $fd "G {$x0 $y0 }"
|
|
set first 0
|
|
}
|
|
set pinx1 [expr {$x0-$pinhsize}]
|
|
set pinx2 [expr {$x0+$pinhsize}]
|
|
set piny1 [expr {$y0-$pinhsize}]
|
|
set piny2 [expr {$y0+$pinhsize}]
|
|
if {![string compare $dir "out"] || ![string compare $dir "inout"] } {
|
|
set linex1 [expr {$x0-20}]
|
|
set liney1 $y0
|
|
set linex2 $x0
|
|
set liney2 $y0
|
|
set textx0 [expr {$x0-25}]
|
|
set texty0 [expr {$y0-4}]
|
|
set textflip [expr {!$flip}]
|
|
} else {
|
|
set linex1 [expr {$x0+20}]
|
|
set liney1 $y0
|
|
set linex2 $x0
|
|
set liney2 $y0
|
|
set textx0 [expr {$x0+25}]
|
|
set texty0 [expr {$y0-4}]
|
|
set textflip [expr {$flip}]
|
|
}
|
|
## lassign not available pre-tck8.5
|
|
lassign [rotation $x0 $y0 $linex1 $liney1 $rot $flip] linex1 liney1
|
|
lassign [rotation $x0 $y0 $linex2 $liney2 $rot $flip] linex2 liney2
|
|
lassign [order $linex1 $liney1 $linex2 $liney2] linex1 liney1 linex2 liney2
|
|
lassign [rotation $x0 $y0 $textx0 $texty0 $rot $flip] textx0 texty0
|
|
foreach {textx0 texty0} [rotation $x0 $y0 $textx0 $texty0 $rot $flip] break
|
|
puts $fd "B 5 $pinx1 $piny1 $pinx2 $piny2 \{name=$lab dir=$dir\}"
|
|
puts $fd "L 4 $linex1 $liney1 $linex2 $liney2 \{\}"
|
|
puts $fd "T \{$lab\} $textx0 $texty0 $rot $textflip 0.2 0.2 \{\}"
|
|
}
|
|
}
|
|
close $fd
|
|
xschem paste
|
|
}
|
|
|
|
|
|
proc add_lab_no_prefix {} {
|
|
global env USER_CONF_DIR
|
|
global filetmp
|
|
|
|
set dirprefix [file dirname [rel_sym_path [find_file_first ipin.sym]]]
|
|
if {$dirprefix == {.}} { set dirprefix {}} else {append dirprefix {/}}
|
|
set tctx::retval [ read_data_nonewline $filetmp ]
|
|
regsub -all {<} $tctx::retval {[} tctx::retval
|
|
regsub -all {>} $tctx::retval {]} tctx::retval
|
|
set lines [split $tctx::retval \n]
|
|
# viewdata $tctx::retval
|
|
set pcnt 0
|
|
set y 0
|
|
set fd [open $USER_CONF_DIR/.clipboard.sch w]
|
|
foreach i $lines {
|
|
puts $fd "C \{${dirprefix}lab_pin.sym\} 0 [set y [expr {$y+20}]] \
|
|
0 0 \{ name=p[incr pcnt] verilog_type=wire lab=[lindex $i 0] \}"
|
|
}
|
|
close $fd
|
|
xschem merge $USER_CONF_DIR/.clipboard.sch
|
|
}
|
|
|
|
proc add_lab_prefix {} {
|
|
global env USER_CONF_DIR
|
|
global filetmp
|
|
|
|
set dirprefix [file dirname [rel_sym_path [find_file_first ipin.sym]]]
|
|
if {$dirprefix == {.}} { set dirprefix {}} else {append dirprefix {/}}
|
|
set tctx::retval [ read_data_nonewline $filetmp ]
|
|
regsub -all {<} $tctx::retval {[} tctx::retval
|
|
regsub -all {>} $tctx::retval {]} tctx::retval
|
|
set lines [split $tctx::retval \n]
|
|
# viewdata $tctx::retval
|
|
set pcnt 0
|
|
set y 0
|
|
set fd [open $USER_CONF_DIR/.clipboard.sch w]
|
|
foreach i $lines {
|
|
puts $fd "C \{${dirprefix}lab_pin.sym\} 0 [set y [expr {$y+20}]] \
|
|
0 0 \{ name=p[incr pcnt] verilog_type=reg lab=i[lindex $i 0] \}"
|
|
}
|
|
close $fd
|
|
xschem merge $USER_CONF_DIR/.clipboard.sch
|
|
}
|
|
|
|
# Create an xschem symbol from a list of in, out, inout pins.
|
|
# Example:
|
|
# create_symbol test.sym {CLK RST D} {Q QB} {VCC VSS}
|
|
#
|
|
proc create_symbol {name {in {}} {out {}} {inout {}}} {
|
|
set symname [file rootname $name].sym
|
|
set res [catch {open $symname {WRONLY CREAT EXCL}} fd]
|
|
if {$res} {puts $fd; return 0} ;# Error. Print reason and exit.
|
|
puts $fd {v {xschem version=3.4.8RC file_version=1.3}}
|
|
puts $fd {K {type=subcircuit format="@name @pinlist @symname" template="name=X1"}}
|
|
set x -150
|
|
set y 0
|
|
foreach pin $in { ;# create all input pins on the left
|
|
puts $fd "B 5 [expr {$x - 2.5}] [expr {$y - 2.5}] [expr {$x + 2.5}] [expr {$y + 2.5}] {name=$pin dir=in}"
|
|
puts $fd "T {$pin} [expr {$x + 25}] [expr {$y - 6}] 0 0 0.2 0.2 {}"
|
|
puts $fd "L 4 $x $y [expr {$x + 20}] $y {}"
|
|
incr y 20
|
|
}
|
|
set x 150
|
|
set y 0
|
|
foreach pin $out { ;# create all out pins on the top right
|
|
puts $fd "B 5 [expr {$x - 2.5}] [expr {$y - 2.5}] [expr {$x + 2.5}] [expr {$y + 2.5}] {name=$pin dir=out}"
|
|
puts $fd "T {$pin} [expr {$x - 25}] [expr {$y - 6}] 0 1 0.2 0.2 {}"
|
|
puts $fd "L 4 [expr {$x - 20}] $y $x $y {}"
|
|
incr y 20
|
|
}
|
|
foreach pin $inout { ;# create all inout pins on the bottom right
|
|
puts $fd "B 5 [expr {$x - 2.5}] [expr {$y - 2.5}] [expr {$x + 2.5}] [expr {$y + 2.5}] {name=$pin dir=inout}"
|
|
puts $fd "T {$pin} [expr {$x - 25}] [expr {$y - 6}] 0 1 0.2 0.2 {}"
|
|
puts $fd "L 7 [expr {$x - 20}] $y $x $y {}"
|
|
incr y 20
|
|
}
|
|
puts $fd "B 4 -130 -10 130 [expr {$y - 10}] {fill=0}" ;# symbol box
|
|
puts $fd "T {@symname} 0 [expr {($y - 20) / 2}] 0 0 0.3 0.3 {hcenter=1 vcenter=1}" ;#symbol name
|
|
puts $fd "T {@name} 130 -10 2 1 0.2 0.2 {}" ;# instance name
|
|
close $fd
|
|
puts "Created symbol ${symname}"
|
|
return 1
|
|
}
|
|
|
|
proc make_symbol {name {ask {no}} } {
|
|
global XSCHEM_SHAREDIR symbol_width
|
|
set name [abs_sym_path $name ]
|
|
set symname [abs_sym_path $name .sym]
|
|
if { $ask eq {no} && [file exists $symname] } {
|
|
set answer [tk_messageBox -message "Warning: symbol $symname already exists. Overwrite?" \
|
|
-icon warning -parent [xschem get topwindow] -type okcancel]
|
|
if {$answer ne {ok}} { return {}}
|
|
|
|
}
|
|
# puts "make_symbol{}, executing: ${XSCHEM_SHAREDIR}/make_sym.awk $symbol_width ${name}"
|
|
eval exec {awk -f ${XSCHEM_SHAREDIR}/make_sym.awk $symbol_width $name}
|
|
return {}
|
|
}
|
|
|
|
proc make_symbol_lcc {name} {
|
|
global XSCHEM_SHAREDIR
|
|
set name [abs_sym_path $name]
|
|
# puts "make_symbol{}, executing: ${XSCHEM_SHAREDIR}/make_sym_lcc.awk ${name}"
|
|
eval exec {awk -f ${XSCHEM_SHAREDIR}/make_sym_lcc.awk $name}
|
|
return {}
|
|
}
|
|
|
|
# point netlist_dir to simulation dir 'simulation/' under current schematic directory
|
|
proc simuldir {} {
|
|
global netlist_dir local_netlist_dir has_x
|
|
if { $local_netlist_dir == 1 } {
|
|
set simdir [xschem get current_dirname]/simulation
|
|
set netlist_dir $simdir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
return $netlist_dir
|
|
}
|
|
if { $local_netlist_dir == 2 } {
|
|
set simdir [xschem get current_dirname]/simulation/[get_cell [xschem get current_name] 0]
|
|
set netlist_dir $simdir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
return $netlist_dir
|
|
}
|
|
return {}
|
|
}
|
|
|
|
#
|
|
# what==0: force creation of $netlist_dir (if netlist_dir variable not empty)
|
|
# and return current setting.
|
|
#
|
|
# what==1: if no dir given prompt user
|
|
# else set netlist_dir to dir
|
|
#
|
|
# what==2: just set netlist_dir according to local_netlist_dir setting
|
|
#
|
|
# Return current netlist directory
|
|
#
|
|
proc set_netlist_dir { what {dir {} }} {
|
|
global netlist_dir env OS has_x local_netlist_dir USER_CONF_DIR
|
|
|
|
if { ![info exists netlist_dir] } {
|
|
set netlist_dir {}
|
|
}
|
|
#### set local-to-schematic-dir if local_netlist_dir tcl var is set
|
|
simuldir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
if {$what == 2} { return $netlist_dir }
|
|
|
|
#### what == 0
|
|
if {$what == 0} {
|
|
if {$netlist_dir eq {}} { set netlist_dir "$USER_CONF_DIR/simulations" }
|
|
if {![file exist $netlist_dir]} {
|
|
if {[catch {file mkdir "$netlist_dir"} err]} {
|
|
puts stderr $err
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -message "$err" -icon error -parent [xschem get topwindow] -type ok
|
|
}
|
|
}
|
|
}
|
|
#### what == 1
|
|
} else {
|
|
# if local_netlist_dir is set can not provide a dir, set dir to netlist_dir as set by proc simuldir
|
|
if {$local_netlist_dir != 0} {
|
|
set dir $netlist_dir
|
|
}
|
|
if { $dir eq {} } {
|
|
# set to default simulations/ directory.
|
|
if {$local_netlist_dir == 0 && $netlist_dir eq {}} {
|
|
set initdir "$USER_CONF_DIR/simulations"
|
|
} elseif {$local_netlist_dir == 0 } {
|
|
set initdir $netlist_dir
|
|
} elseif { $netlist_dir ne {} } {
|
|
set initdir $netlist_dir
|
|
} else {
|
|
if {$OS == "Windows"} {
|
|
set initdir $env(windir)
|
|
} else {
|
|
set initdir [pwd]
|
|
}
|
|
}
|
|
# prompt user for a dir
|
|
set new_dir [tk_chooseDirectory -initialdir $initdir \
|
|
-parent [xschem get topwindow] -title {Select netlist DIR} -mustexist false]
|
|
} else {
|
|
# use provided dir argument
|
|
set new_dir $dir
|
|
}
|
|
|
|
# create new dir if not already existing
|
|
if {$new_dir ne {} } {
|
|
if {![file exist $new_dir]} {
|
|
if {[catch {file mkdir "$new_dir"} err]} {
|
|
puts stderr $err
|
|
if {[info exists has_x]} {
|
|
tk_messageBox -message "$err" -icon error -parent [xschem get topwindow] -type ok
|
|
}
|
|
}
|
|
|
|
}
|
|
set netlist_dir $new_dir
|
|
}
|
|
} ;# what == 1
|
|
regsub {^~/} $netlist_dir ${env(HOME)}/ netlist_dir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
# return $netlist_dir if valid and existing, else return empty string
|
|
if {$netlist_dir ne {} && [file exists $netlist_dir]} {
|
|
return $netlist_dir
|
|
}
|
|
return {}
|
|
}
|
|
|
|
|
|
proc enter_text {textlabel {preserve_disabled disabled}} {
|
|
global has_cairo preserve_unchanged_attrs wm_fix props enter_text_default_geometry
|
|
global text_tabs_setting tabstop
|
|
set tctx::rcode {}
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Enter text}
|
|
wm transient .dialog [xschem get topwindow]
|
|
|
|
set X [expr {[winfo pointerx .dialog] - 30}]
|
|
set Y [expr {[winfo pointery .dialog] - 25}]
|
|
|
|
bind .dialog <Configure> {
|
|
set enter_text_default_geometry [wm geometry .dialog]
|
|
regsub {\+.*} $enter_text_default_geometry {} enter_text_default_geometry
|
|
}
|
|
|
|
# 20100203
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
wm geometry .dialog "${enter_text_default_geometry}+$X+$Y"
|
|
frame .dialog.f1
|
|
frame .dialog.f2
|
|
label .dialog.f1.txtlab -text $textlabel
|
|
eval text .dialog.f2.txt -undo 1 -width 90 -height 9 $text_tabs_setting -yscrollcommand \".dialog.f2.yscroll set\"
|
|
scrollbar .dialog.f2.yscroll -command ".dialog.f2.txt yview"
|
|
|
|
.dialog.f2.txt delete 1.0 end
|
|
.dialog.f2.txt insert 1.0 $tctx::retval
|
|
checkbutton .dialog.f1.l1 -text "preserve unchanged props" -variable preserve_unchanged_attrs \
|
|
-state $preserve_disabled
|
|
pack .dialog.f1 -side top -fill x ;# -expand yes
|
|
pack .dialog.f2 -side top -fill both -expand yes
|
|
pack .dialog.f1.l1 -side left
|
|
pack .dialog.f1.txtlab -side left -expand yes -fill x
|
|
|
|
pack .dialog.f2.txt -side left -fill both -expand yes
|
|
pack .dialog.f2.yscroll -side left -expand no -fill y
|
|
frame .dialog.edit
|
|
frame .dialog.edit.hsize
|
|
frame .dialog.edit.vsize
|
|
frame .dialog.edit.props
|
|
pack .dialog.edit.hsize -side bottom -expand yes -fill x
|
|
pack .dialog.edit.vsize -side bottom -expand yes -fill x
|
|
pack .dialog.edit.props -side bottom -expand yes -fill x
|
|
pack .dialog.edit -side top -fill x
|
|
if {$has_cairo } {
|
|
entry .dialog.edit.hsize.hsize -relief sunken -textvariable tctx::vsize -width 20
|
|
entry_replace_selection .dialog.edit.hsize.hsize
|
|
} else {
|
|
entry .dialog.edit.hsize.hsize -relief sunken -textvariable tctx::hsize -width 20
|
|
entry_replace_selection .dialog.edit.hsize.hsize
|
|
}
|
|
entry .dialog.edit.vsize.vsize -relief sunken -textvariable tctx::vsize -width 20
|
|
entry_replace_selection .dialog.edit.vsize.vsize
|
|
text .dialog.edit.props.props -undo 1 -width 70 -height 3
|
|
.dialog.edit.props.props insert 1.0 $props
|
|
label .dialog.edit.hsize.hlab -text "hsize:"
|
|
label .dialog.edit.vsize.vlab -text "vsize:"
|
|
label .dialog.edit.props.proplab -text "props:"
|
|
pack .dialog.edit.hsize.hlab -side left
|
|
pack .dialog.edit.hsize.hsize -side left -fill x -expand yes
|
|
pack .dialog.edit.vsize.vlab -side left
|
|
pack .dialog.edit.vsize.vsize -side left -fill x -expand yes
|
|
pack .dialog.edit.props.proplab -side left
|
|
pack .dialog.edit.props.props -side left -fill x -expand yes
|
|
frame .dialog.buttons
|
|
button .dialog.buttons.ok -text "OK" -command \
|
|
{
|
|
set props [.dialog.edit.props.props get 1.0 {end - 1 chars}]
|
|
set tctx::retval [.dialog.f2.txt get 1.0 {end - 1 chars}]
|
|
if {$has_cairo} {
|
|
set tctx::hsize $tctx::vsize
|
|
}
|
|
set tctx::rcode {ok}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.buttons.cancel -text "Cancel" -command \
|
|
{
|
|
set tctx::retval {}
|
|
set tctx::rcode {}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.buttons.b3 -text "Load" -command \
|
|
{
|
|
global INITIALTEXTDIR
|
|
if { ![info exists INITIALTEXTDIR] } { set INITIALTEXTDIR [xschem get current_dirname] }
|
|
set a [tk_getOpenFile -parent .dialog -initialdir $INITIALTEXTDIR ]
|
|
if [string compare $a ""] {
|
|
set INITIALTEXTDIR [file dirname $a]
|
|
read_data_window .dialog.f2.txt $a
|
|
}
|
|
}
|
|
button .dialog.buttons.b4 -text "Del" -command \
|
|
{
|
|
.dialog.f2.txt delete 1.0 end
|
|
}
|
|
pack .dialog.buttons.ok -side left -fill x -expand yes
|
|
pack .dialog.buttons.cancel -side left -fill x -expand yes
|
|
pack .dialog.buttons.b3 -side left -fill x -expand yes
|
|
pack .dialog.buttons.b4 -side left -fill x -expand yes
|
|
pack .dialog.buttons -side bottom -fill x
|
|
bind .dialog <Escape> {
|
|
if ![string compare $tctx::retval [.dialog.f2.txt get 1.0 {end - 1 chars}]] {
|
|
.dialog.buttons.cancel invoke
|
|
}
|
|
}
|
|
bind .dialog.f2.txt <Shift-KeyRelease-Return> {return_release %W; .dialog.buttons.ok invoke}
|
|
.dialog.f2.txt tag add sel 1.0 {end - 1 chars}
|
|
.dialog.f2.txt mark set insert 1.0
|
|
focus .dialog.f2.txt
|
|
#grab set .dialog
|
|
tkwait window .dialog
|
|
return $tctx::retval
|
|
}
|
|
|
|
# will redefine puts to output into tclcmd_puts
|
|
proc redef_puts {} {
|
|
global tclcmd_puts
|
|
set tclcmd_puts {}
|
|
if ![llength [info command ::tcl::puts]] {
|
|
rename puts ::tcl::puts
|
|
proc puts args {
|
|
global tclcmd_puts
|
|
set la [llength $args]
|
|
if {$la<1 || $la>3} {
|
|
error "usage: puts ?-nonewline? ?channel? string"
|
|
}
|
|
set nl \n
|
|
if {[lindex $args 0]=="-nonewline"} {
|
|
set nl ""
|
|
set args [lrange $args 1 end]
|
|
}
|
|
if {[llength $args]==1} {
|
|
set args [list stdout [join $args]] ;# (2)
|
|
}
|
|
foreach {channel s} $args break
|
|
#set s [join $s] ;# (1) prevent braces at leading/tailing spaces
|
|
if {$channel=="stdout" || $channel=="stderr"} {
|
|
append tclcmd_puts $s$nl
|
|
} else {
|
|
set cmd ::tcl::puts
|
|
if {$nl==""} {lappend cmd -nonewline}
|
|
lappend cmd $channel $s
|
|
eval $cmd
|
|
}
|
|
};# puts
|
|
}
|
|
}
|
|
|
|
# return key release, used to remove last entered character
|
|
# when binding close text-widget window to Shift-return or Control-return.
|
|
proc return_release {window} {
|
|
set curs [$window index insert]
|
|
$window delete "$curs - 1 chars" $curs
|
|
}
|
|
|
|
proc tclcmd_ok_button {} {
|
|
global tclcmd_txt tclcmd_puts
|
|
|
|
set tclcmd_txt [.tclcmd.t.t get 1.0 end]
|
|
regsub -all -line {^ *= *} $tclcmd_txt {= } tclcmd_txt
|
|
redef_puts
|
|
catch {uplevel #0 $tclcmd_txt} tclcmd_cmd
|
|
rename puts {}
|
|
rename ::tcl::puts puts
|
|
if {$tclcmd_cmd ne {}} {
|
|
if {$tclcmd_puts ne {}} {
|
|
if {[string index $tclcmd_puts end] != "\n"} {
|
|
append tclcmd_puts \n $tclcmd_cmd
|
|
} else {
|
|
append tclcmd_puts $tclcmd_cmd
|
|
}
|
|
} else {
|
|
set tclcmd_puts $tclcmd_cmd
|
|
}
|
|
}
|
|
if {$tclcmd_puts != {} && [string index $tclcmd_puts end] != "\n"} {
|
|
append tclcmd_puts "\n"
|
|
}
|
|
.tclcmd.r.r insert end $tclcmd_puts
|
|
.tclcmd.r.r yview moveto 1
|
|
}
|
|
|
|
# evaluate a tcl command from GUI
|
|
proc tclcmd {} {
|
|
global tclcmd_txt tclcmd_default_geometry
|
|
set_ne tclcmd_default_geometry {}
|
|
if {[winfo exists .tclcmd]} {
|
|
destroy .tclcmd
|
|
}
|
|
toplevel .tclcmd -class dialog
|
|
label .tclcmd.txtlab -text {Enter TCL expression. Shift-Return will evaluate}
|
|
panedwindow .tclcmd.p -orient vert
|
|
|
|
bind .tclcmd <Configure> {
|
|
set tclcmd_default_geometry [wm geometry .tclcmd]
|
|
}
|
|
|
|
frame .tclcmd.t
|
|
text .tclcmd.t.t -width 60 -height 4 -font {Monospace 10} -yscrollcommand ".tclcmd.t.yscroll set"
|
|
scrollbar .tclcmd.t.yscroll -command ".tclcmd.t.t yview"
|
|
|
|
frame .tclcmd.r
|
|
text .tclcmd.r.r -width 60 -height 5 -font {Monospace 10} -yscrollcommand ".tclcmd.r.yscroll set"
|
|
scrollbar .tclcmd.r.yscroll -command ".tclcmd.r.r yview"
|
|
|
|
.tclcmd.p add .tclcmd.t .tclcmd.r
|
|
.tclcmd.t.t insert 1.0 $tclcmd_txt
|
|
|
|
frame .tclcmd.b
|
|
button .tclcmd.b.cleari -text {Clear Input} -command {
|
|
.tclcmd.t.t delete 1.0 end
|
|
}
|
|
button .tclcmd.b.clear -text {Clear Results} -command {
|
|
.tclcmd.r.r delete 1.0 end
|
|
}
|
|
button .tclcmd.b.close -text Close -command {
|
|
set tclcmd_txt [.tclcmd.t.t get 1.0 {end - 1 chars}]
|
|
destroy .tclcmd
|
|
}
|
|
button .tclcmd.b.ok -text Evaluate -command {tclcmd_ok_button}
|
|
# bind .tclcmd.t <Shift-KeyPress-Return> { .tclcmd.b.ok invoke }
|
|
bind .tclcmd.t.t <Shift-KeyRelease-Return> {return_release %W; .tclcmd.b.ok invoke }
|
|
bind .tclcmd.t.t <Shift-Delete> {
|
|
.tclcmd.r.r delete 1.0 end
|
|
}
|
|
bind .tclcmd <Escape> {.tclcmd.b.close invoke}
|
|
pack .tclcmd.txtlab -side top -fill x
|
|
pack .tclcmd.b -side bottom -fill x
|
|
pack .tclcmd.p -side top -fill both -expand yes
|
|
pack .tclcmd.r.yscroll -side right -fill y
|
|
pack .tclcmd.r.r -side top -fill both -expand yes
|
|
pack .tclcmd.t.yscroll -side right -fill y
|
|
pack .tclcmd.t.t -side top -fill both -expand yes
|
|
pack .tclcmd.b.ok -side left -expand yes -fill x
|
|
pack .tclcmd.b.clear -side left -expand yes -fill x
|
|
pack .tclcmd.b.cleari -side left -expand yes -fill x
|
|
pack .tclcmd.b.close -side left -expand yes -fill x
|
|
if { $tclcmd_default_geometry ne {}} {wm geometry .tclcmd $tclcmd_default_geometry}
|
|
}
|
|
|
|
proc select_layers {} {
|
|
global dark_colorscheme enable_layer
|
|
# xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .sl -class Dialog
|
|
wm transient .sl [xschem get topwindow]
|
|
if { $dark_colorscheme == 1 } {
|
|
set txt_color black
|
|
} else {
|
|
set txt_color white
|
|
}
|
|
set j 0
|
|
set f 0
|
|
frame .sl.f0
|
|
frame .sl.f1
|
|
pack .sl.f0 .sl.f1 -side top -fill x
|
|
button .sl.f1.ok -text OK -command { destroy .sl}
|
|
pack .sl.f1.ok -side left -expand yes -fill x
|
|
frame .sl.f0.f$f
|
|
pack .sl.f0.f$f -side left -fill y
|
|
foreach i $tctx::colors {
|
|
if { $dark_colorscheme == 1 } {
|
|
set ind_bg white
|
|
} else {
|
|
set ind_bg black
|
|
}
|
|
if { $j == [xschem get pinlayer] } {
|
|
set laylab [format %2d $j]-PIN
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get wirelayer] } {
|
|
set laylab [format %2d $j]-WIRE
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get textlayer] } {
|
|
set laylab [format %2d $j]-TEXT
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get backlayer] } {
|
|
set laylab [format %2d $j]-BG
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg white
|
|
set ind_bg black
|
|
} else {
|
|
set layfg black
|
|
set ind_bg white
|
|
}
|
|
} elseif { $j == [xschem get gridlayer] } {
|
|
set laylab [format %2d $j]-GRID
|
|
set layfg $txt_color
|
|
} else {
|
|
set laylab "[format %2d $j] "
|
|
set layfg $txt_color
|
|
}
|
|
|
|
checkbutton .sl.f0.f$f.cb$j -text $laylab -variable enable_layer($j) -activeforeground $layfg \
|
|
-selectcolor $ind_bg -anchor w -foreground $layfg -background $i -activebackground $i \
|
|
-command {
|
|
xschem enable_layers
|
|
xschem redraw
|
|
}
|
|
pack .sl.f0.f$f.cb$j -side top -fill x
|
|
incr j
|
|
if { [expr {$j%10}] == 0 } {
|
|
incr f
|
|
frame .sl.f0.f$f
|
|
pack .sl.f0.f$f -side left -fill y
|
|
}
|
|
}
|
|
# tkwait window .sl
|
|
# xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
|
|
proc color_dim {} {
|
|
global dim_bg dim_value enable_dim_bg
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dim -class Dialog
|
|
wm title .dim {Dim colors}
|
|
wm transient .dim [xschem get topwindow]
|
|
checkbutton .dim.bg -text {Dim background} -variable enable_dim_bg
|
|
# xschem color_dim <scale value> sets also dim_value variable
|
|
scale .dim.scale -digits 2 -label {Dim factor} -length 256 \
|
|
-showvalue 1 -command {xschem color_dim} -orient horizontal \
|
|
-from -5 -to 5 -resolution 0.1
|
|
button .dim.ok -text OK -command {destroy .dim}
|
|
.dim.scale set $dim_value
|
|
pack .dim.scale
|
|
pack .dim.bg -side left
|
|
pack .dim.ok -side right -anchor e
|
|
tkwait window .dim
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
|
|
# show xschem about dialog
|
|
proc about {} {
|
|
global OS running_in_src_dir
|
|
if [winfo exists .about] {
|
|
bind .about.link <Button-1> {}
|
|
bind .about.link2 <Button-1> {}
|
|
destroy .about
|
|
}
|
|
toplevel .about -class Dialog
|
|
wm title .about {About XSCHEM}
|
|
wm transient .about [xschem get topwindow]
|
|
label .about.xschem -text "XSCHEM V[xschem get version]" -font {Sans 24 bold}
|
|
label .about.descr -text "Schematic editor / netlister for VHDL, Verilog, SPICE, tEDAx"
|
|
button .about.link -text {http://repo.hu/projects/xschem} -font Underline-Font -fg blue -relief flat
|
|
button .about.link2 -text {https://github.com/StefanSchippers/xschem} -font Underline-Font -fg blue -relief flat
|
|
button .about.link3 -text {Online XSCHEM Manual} -font Underline-Font -fg blue -relief flat
|
|
button .about.link4 -text {Local XSCHEM Manual} -font Underline-Font -fg blue -relief flat
|
|
label .about.copyright -text "\n Copyright (C) 1998-2024 Stefan Schippers (stefan.schippers@gmail.com) \n
|
|
This is free software; see the source for copying conditions. There is NO warranty;
|
|
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\n"
|
|
button .about.close -text Close -command {destroy .about} -font {Sans 18}
|
|
pack .about.xschem
|
|
pack .about.link
|
|
pack .about.link2
|
|
pack .about.link3
|
|
pack .about.link4
|
|
pack .about.descr
|
|
pack .about.copyright
|
|
pack .about.close
|
|
if {$OS == "Windows"} {
|
|
bind .about.link <Button-1> {eval start http://repo.hu/projects/xschem}
|
|
bind .about.link2 <Button-1> {eval start https://github.com/StefanSchippers/xschem}
|
|
bind .about.link3 <Button-1> {eval start http://repo.hu/projects/xschem/index.html}
|
|
bind .about.link4 <Button-1> {
|
|
if {$running_in_src_dir} {
|
|
eval start [pwd]/../doc/xschem_man/xschem_man.html
|
|
} else {
|
|
eval start $XSCHEM_SHAREDIR/../doc/xschem/xschem_man/xschem_man.html
|
|
}
|
|
}
|
|
} else {
|
|
bind .about.link <Button-1> {execute 0 xdg-open http://repo.hu/projects/xschem}
|
|
bind .about.link2 <Button-1> {execute 0 xdg-open https://github.com/StefanSchippers/xschem}
|
|
bind .about.link3 <Button-1> {execute 0 xdg-open http://repo.hu/projects/xschem/index.html}
|
|
bind .about.link4 <Button-1> {
|
|
if {$running_in_src_dir} {
|
|
execute 0 xdg-open file://$XSCHEM_SHAREDIR/../doc/xschem_man/xschem_man.html
|
|
} else {
|
|
execute 0 xdg-open file://$XSCHEM_SHAREDIR/../doc/xschem/xschem_man/xschem_man.html
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc property_search {} {
|
|
global search_value search_found
|
|
global search_exact search_case
|
|
global search_select
|
|
global custom_token OS
|
|
|
|
set search_found 0
|
|
while { !$search_found} {
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Search}
|
|
wm transient .dialog [xschem get topwindow]
|
|
if { ![info exists X] } {
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
}
|
|
wm geometry .dialog "+$X+$Y"
|
|
frame .dialog.custom
|
|
label .dialog.custom.l -text "Token"
|
|
entry .dialog.custom.e -width 32
|
|
entry_replace_selection .dialog.custom.e
|
|
.dialog.custom.e insert 0 $custom_token
|
|
pack .dialog.custom.e .dialog.custom.l -side right
|
|
frame .dialog.val
|
|
label .dialog.val.l -text "Value"
|
|
entry .dialog.val.e -width 32
|
|
entry_replace_selection .dialog.val.e
|
|
.dialog.val.e insert 0 $search_value
|
|
pack .dialog.val.e .dialog.val.l -side right
|
|
frame .dialog.but
|
|
button .dialog.but.ok -text OK -command {
|
|
set search_value [.dialog.val.e get]
|
|
set custom_token [.dialog.custom.e get]
|
|
if {$debug_var<=-1} { puts stderr "|$custom_token|" }
|
|
if { $search_exact==1 } {
|
|
set search_found [xschem searchmenu exact $search_select $custom_token $search_value $search_case]
|
|
} else {
|
|
set search_found [xschem searchmenu regex $search_select $custom_token $search_value $search_case]
|
|
}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.but.cancel -text Cancel -command { set search_found 1; destroy .dialog }
|
|
|
|
# Window doesn't support regular expression, has to be exact match for now
|
|
checkbutton .dialog.but.sub -text {Exact search} -variable search_exact
|
|
checkbutton .dialog.but.case -text {Match case} -variable search_case
|
|
radiobutton .dialog.but.nosel -text {Highlight} -variable search_select -value 0
|
|
radiobutton .dialog.but.sel -text {Select} -variable search_select -value 1
|
|
# 20171211 added unselect
|
|
radiobutton .dialog.but.unsel -text {Unselect} -variable search_select -value -1
|
|
pack .dialog.but.ok -anchor w -side left
|
|
pack .dialog.but.sub -side left
|
|
pack .dialog.but.case -side left
|
|
pack .dialog.but.nosel -side left
|
|
pack .dialog.but.sel -side left
|
|
pack .dialog.but.unsel -side left
|
|
pack .dialog.but.cancel -anchor e
|
|
pack .dialog.custom -anchor e
|
|
pack .dialog.val -anchor e
|
|
pack .dialog.but -expand yes -fill x
|
|
focus .dialog
|
|
bind .dialog <Escape> {.dialog.but.cancel invoke}
|
|
bind .dialog <Return> {.dialog.but.ok invoke}
|
|
wm protocol .dialog WM_DELETE_WINDOW {.dialog.but.cancel invoke}
|
|
# grab set .dialog
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
return {}
|
|
}
|
|
|
|
#20171029
|
|
# allows to call TCL hooks from 'format' strings during netlisting
|
|
# example of symbol spice format definition:
|
|
# format="@name @pinlist @symname @tcleval(<script>) m=@m"
|
|
# NOTE: spaces and quotes in <script> must be escaped
|
|
# symname and instname are predefined variables in the <script> context
|
|
# they can be used together with TCL xschem command to query instance or symbol
|
|
# attributes.
|
|
#
|
|
proc tclpropeval {s instname symname} {
|
|
# puts "tclpropeval: $s $instname $symname"
|
|
global env debug_var
|
|
regsub {^@tcleval\(} $s {} s
|
|
regsub {\)([ \t\n]*)$} $s {\1} s
|
|
# puts "tclpropeval: $s $instname $symname"
|
|
if { [catch {subst $s} res] } {
|
|
# puts stderr $res
|
|
set res ?\n
|
|
}
|
|
return $res
|
|
}
|
|
|
|
# this hook is called in translate() if whole string is contained in a tcleval(...) construct
|
|
proc tclpropeval2 {s} {
|
|
global debug_tcleval env path debug_var sch_basename
|
|
|
|
set raw_level [xschem get raw_level]
|
|
set netlist_type [xschem get netlist_type]
|
|
# puts "tclpropeval2: s=|$s|"
|
|
if {$debug_var <=-1} {puts "tclpropeval2: $s"}
|
|
set path [string range [xschem get sch_path] 1 end]
|
|
set sch_basename [file tail [file rootname [xschem get current_name]]]
|
|
# skip hierarchy components above the level where raw file has been loaded.
|
|
# node path names to look up in raw file begin from there.
|
|
set skip 0
|
|
while { $skip < $raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
|
|
if { $netlist_type eq {spice} } {
|
|
# this is necessary if spiceprefix is being used in netlists
|
|
regsub {^([^xX])} $path {x\1} path
|
|
while { [regsub {\.([^xX])} $path {.x\1} path] } {}
|
|
}
|
|
|
|
## no more necessary, ':' are converted to '.' when reading raw file */
|
|
# if { [sim_is_xyce]} {
|
|
# regsub -all {\.} [string toupper $path] {:} path
|
|
# }
|
|
|
|
if { $debug_var<=-1 } { puts "---> path=$path" }
|
|
regsub {^tcleval\(} $s {} s
|
|
regsub {\)([ \n\t]*)$} $s {\1} s
|
|
# puts "tclpropeval2: s=|$s|"
|
|
# puts "tclpropeval2: subst $s=|[subst $s]|"
|
|
if { [catch {uplevel #0 "subst \{$s\}"} res] } {
|
|
if { $debug_tcleval > 0} { puts "tclpropeval2 warning: $s --> $res"}
|
|
set res ?\n
|
|
}
|
|
# puts "tclpropeval2: res=|$res|"
|
|
return $res
|
|
}
|
|
|
|
proc attach_labels_to_inst {} {
|
|
global use_lab_wire use_label_prefix custom_label_prefix do_all_inst rotated_text
|
|
|
|
set tctx::rcode {}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Add labels to instances}
|
|
wm transient .dialog [xschem get topwindow]
|
|
|
|
# 20100408
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
wm geometry .dialog "+$X+$Y"
|
|
|
|
frame .dialog.custom
|
|
label .dialog.custom.l -text "Prefix"
|
|
entry .dialog.custom.e -width 32
|
|
entry_replace_selection .dialog.custom.e
|
|
.dialog.custom.e insert 0 $custom_label_prefix
|
|
pack .dialog.custom.e .dialog.custom.l -side right
|
|
|
|
|
|
frame .dialog.but
|
|
button .dialog.but.ok -text OK -command {
|
|
set custom_label_prefix [.dialog.custom.e get]
|
|
#### put command here
|
|
set tctx::rcode yes
|
|
destroy .dialog
|
|
}
|
|
button .dialog.but.cancel -text Cancel -command { set tctx::rcode {}; destroy .dialog }
|
|
checkbutton .dialog.but.wire -text {use wire labels} -variable use_lab_wire
|
|
checkbutton .dialog.but.do_all -text {Do all} -variable do_all_inst
|
|
label .dialog.but.rot -text {Rotated Text}
|
|
entry .dialog.but.rotated -textvariable rotated_text -width 2
|
|
entry_replace_selection .dialog.but.rotated
|
|
checkbutton .dialog.but.prefix -text {use prefix} -variable use_label_prefix
|
|
pack .dialog.but.ok -anchor w -side left
|
|
pack .dialog.but.prefix -side left
|
|
pack .dialog.but.wire -side left
|
|
pack .dialog.but.do_all -side left
|
|
pack .dialog.but.rotated -side left
|
|
pack .dialog.but.rot -side left
|
|
pack .dialog.but.cancel -anchor e
|
|
|
|
pack .dialog.custom -anchor e
|
|
pack .dialog.but -expand yes -fill x
|
|
|
|
focus .dialog
|
|
bind .dialog <Escape> {.dialog.but.cancel invoke}
|
|
bind .dialog <Return> {.dialog.but.ok invoke}
|
|
grab set .dialog
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return {}
|
|
}
|
|
|
|
# if no_ask_save is set to 1 just return yes (always save)
|
|
proc ask_save_optional { {ask {save file?}} {cancel 1}} {
|
|
global no_ask_save
|
|
|
|
if { $no_ask_save } {
|
|
return yes
|
|
} else {
|
|
return [ask_save $ask $cancel]
|
|
}
|
|
}
|
|
|
|
proc ask_save { {ask {save file?}} {cancel 1}} {
|
|
global wm_fix
|
|
set tctx::rcode {}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Ask Save}
|
|
wm transient .dialog [xschem get topwindow]
|
|
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
|
|
wm geometry .dialog "+$X+$Y"
|
|
label .dialog.l1 -text $ask
|
|
frame .dialog.f1
|
|
button .dialog.f1.b1 -text {Yes} -command\
|
|
{
|
|
set tctx::rcode {yes}
|
|
destroy .dialog
|
|
}
|
|
if {$cancel} {
|
|
button .dialog.f1.b2 -text {Cancel} -command\
|
|
{
|
|
set tctx::rcode {}
|
|
destroy .dialog
|
|
}
|
|
}
|
|
button .dialog.f1.b3 -text {No} -command\
|
|
{
|
|
set tctx::rcode {no}
|
|
destroy .dialog
|
|
}
|
|
pack .dialog.l1 .dialog.f1 -side top -fill x
|
|
pack .dialog.f1.b1 -side left -fill x -expand yes
|
|
bind .dialog <Return> {.dialog.f1.b1 invoke}
|
|
bind .dialog <y> {.dialog.f1.b1 invoke}
|
|
bind .dialog <n> {.dialog.f1.b3 invoke}
|
|
if { $cancel} {
|
|
pack .dialog.f1.b2 -side left -fill x -expand yes
|
|
}
|
|
pack .dialog.f1.b3 -side left -fill x -expand yes
|
|
if {$cancel} {
|
|
bind .dialog <Escape> {.dialog.f1.b2 invoke}
|
|
}
|
|
# needed, otherwise problems when descending with double clixk 23012004
|
|
tkwait visibility .dialog
|
|
grab set .dialog
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $tctx::rcode
|
|
}
|
|
|
|
|
|
proc edit_vi_prop {txtlabel} {
|
|
global XSCHEM_TMP_DIR symbol prev_symbol debug_var editor
|
|
global user_wants_copy_cell
|
|
|
|
set netlist_type [xschem get netlist_type]
|
|
set user_wants_copy_cell 0
|
|
set tctx::rcode {}
|
|
set filename .xschem_edit_file.[pid]
|
|
if ![string compare $netlist_type "vhdl"] { set suffix vhd } else { set suffix v }
|
|
set filename $filename.$suffix
|
|
write_data $tctx::retval $XSCHEM_TMP_DIR/$filename
|
|
# since $editor can be an executable with options (gvim -f) I *need* to use eval
|
|
eval execute_wait 0 $editor $XSCHEM_TMP_DIR/$filename ;# 20161119
|
|
if {$debug_var<=-1} {puts "edit_vi_prop{}:\n--------\nretval=$tctx::retval\n---------\n"}
|
|
if {$debug_var<=-1} {puts "edit_vi_prop{}:\n--------\nsymbol=$symbol\n---------\n"}
|
|
set tmp [read_data $XSCHEM_TMP_DIR/$filename]
|
|
file delete $XSCHEM_TMP_DIR/$filename
|
|
if {$debug_var<=-1} {puts "edit_vi_prop{}:\n--------\n$tmp\n---------\n"}
|
|
if [string compare $tmp $tctx::retval] {
|
|
set tctx::retval $tmp
|
|
if {$debug_var<=-1} {puts "modified"}
|
|
set tctx::rcode ok
|
|
return $tctx::rcode
|
|
} else {
|
|
set tctx::rcode {}
|
|
return $tctx::rcode
|
|
}
|
|
}
|
|
|
|
proc edit_vi_netlist_prop {txtlabel} {
|
|
global XSCHEM_TMP_DIR debug_var editor
|
|
global user_wants_copy_cell
|
|
|
|
set netlist_type [xschem get netlist_type]
|
|
set user_wants_copy_cell 0
|
|
set filename .xschem_edit_file.[pid]
|
|
if ![string compare $netlist_type "vhdl"] { set suffix vhd } else { set suffix v }
|
|
set filename $filename.$suffix
|
|
regsub -all {\\?"} $tctx::retval {"} tctx::retval
|
|
regsub -all {\\?\\} $tctx::retval {\\} tctx::retval
|
|
write_data $tctx::retval $XSCHEM_TMP_DIR/$filename
|
|
if { [regexp vim $editor] } { set ftype "\{-c :set filetype=$netlist_type\}" } else { set ftype {} }
|
|
# since $editor can be an executable with options (gvim -f) I *need* to use eval
|
|
eval execute_wait 0 $editor $ftype $XSCHEM_TMP_DIR/$filename
|
|
if {$debug_var <= -1} {puts "edit_vi_prop{}:\n--------\n$tctx::retval\n---------\n"}
|
|
set tmp [read_data $XSCHEM_TMP_DIR/$filename]
|
|
file delete $XSCHEM_TMP_DIR/$filename
|
|
if {$debug_var <= -1} {puts "edit_vi_prop{}:\n--------\n$tmp\n---------\n"}
|
|
if [string compare $tmp $tctx::retval] {
|
|
set tctx::retval $tmp
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
if {$debug_var <= -1} {puts "modified"}
|
|
set tctx::rcode ok
|
|
return $tctx::rcode
|
|
} else {
|
|
set tctx::rcode {}
|
|
return $tctx::rcode
|
|
}
|
|
}
|
|
|
|
proc reset_colors {ask} {
|
|
global dark_colors light_colors dark_colorscheme USER_CONF_DIR svg_colors ps_colors
|
|
global light_colors_save dark_colors_save
|
|
|
|
if {$ask} {
|
|
set answer [tk_messageBox -message "Warning: delete 'colors' configuration file?" \
|
|
-icon warning -parent [xschem get topwindow] -type okcancel]
|
|
if {$answer ne {ok}} { return }
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
set light_colors $light_colors_save
|
|
set dark_colors $dark_colors_save
|
|
if { $dark_colorscheme == 1 } {
|
|
set tctx::colors $dark_colors
|
|
} else {
|
|
set tctx::colors $light_colors
|
|
}
|
|
regsub -all {"} $light_colors {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
regsub -all {"} $tctx::colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
file delete ${USER_CONF_DIR}/colors
|
|
xschem build_colors
|
|
xschem redraw
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
|
|
proc change_color {} {
|
|
global dark_colors light_colors dark_colorscheme cadlayers USER_CONF_DIR svg_colors ps_colors
|
|
|
|
set n [xschem get rectcolor]
|
|
if { $n < 0 || $n >=$cadlayers} return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
if { $dark_colorscheme == 1 } {
|
|
set c $dark_colors
|
|
} else {
|
|
set c $light_colors
|
|
}
|
|
set initial_color [lindex $c $n]
|
|
set value [tk_chooseColor -initialcolor $initial_color]
|
|
if {[string compare $value {}] } {
|
|
set cc [lreplace $c $n $n $value]
|
|
set tctx::colors $cc
|
|
if { $dark_colorscheme == 1 } {
|
|
set dark_colors $cc
|
|
} else {
|
|
set light_colors $cc
|
|
regsub -all {"} $cc {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
}
|
|
regsub -all {"} $tctx::colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
|
|
xschem build_colors
|
|
xschem redraw
|
|
set savedata "#### THIS FILE IS AUTOMATICALLY GENERATED BY XSCHEM, DO NOT EDIT.\n"
|
|
append savedata "set cadlayers $cadlayers\n"
|
|
append savedata "set light_colors {$light_colors}\n"
|
|
append savedata "set dark_colors {$dark_colors}\n"
|
|
write_data $savedata ${USER_CONF_DIR}/colors
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
|
|
proc edit_prop {txtlabel} {
|
|
global edit_prop_size infowindow_text edit_symbol_prop_new_sel edit_prop_pos
|
|
global prev_symbol symbol no_change_attrs preserve_unchanged_attrs copy_cell debug_var
|
|
global user_wants_copy_cell editprop_sympath text_tabs_setting
|
|
global tabstop
|
|
set user_wants_copy_cell 0
|
|
set tctx::rcode {}
|
|
set tctx::retval_orig $tctx::retval
|
|
if {$debug_var <= -1} {puts " edit_prop{}: tctx::retval=$tctx::retval"}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Edit Properties}
|
|
wm transient .dialog [xschem get topwindow]
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
|
|
# 20160325 change and remember widget size
|
|
bind .dialog <Configure> {
|
|
# puts [wm geometry .dialog]
|
|
if { $edit_symbol_prop_new_sel != 1 } {
|
|
set edit_prop_size [wm geometry .dialog]
|
|
set edit_prop_pos $edit_prop_size
|
|
regsub {\+.*} $edit_prop_size {} edit_prop_size
|
|
regsub {[^+]*\+} $edit_prop_pos {+} edit_prop_pos
|
|
}
|
|
}
|
|
wm geometry .dialog "${edit_prop_size}+$X+$Y"
|
|
set prev_symbol $symbol
|
|
set editprop_sympath [get_directory [abs_sym_path [tclpropeval2 $symbol]]]
|
|
frame .dialog.f4
|
|
label .dialog.f4.l1 -text $txtlabel
|
|
label .dialog.f4.path -text "Path:"
|
|
entry .dialog.f4.symprop -textvariable editprop_sympath -width 0 -state readonly
|
|
entry_replace_selection .dialog.f4.symprop
|
|
eval text .dialog.symprop -undo 1 -yscrollcommand \".dialog.yscroll set\" -setgrid 1 \
|
|
-xscrollcommand \".dialog.xscroll set\" -wrap none $text_tabs_setting
|
|
.dialog.symprop delete 1.0 end
|
|
.dialog.symprop insert 1.0 $tctx::retval
|
|
scrollbar .dialog.yscroll -command ".dialog.symprop yview"
|
|
scrollbar .dialog.xscroll -command ".dialog.symprop xview" -orient horiz
|
|
frame .dialog.f1
|
|
frame .dialog.f2
|
|
label .dialog.f1.l2 -text "Symbol"
|
|
entry .dialog.f1.e2 -width 30
|
|
entry_replace_selection .dialog.f1.e2
|
|
.dialog.f1.e2 insert 0 $symbol
|
|
button .dialog.f1.b5 -text "Browse" -command {
|
|
set r [tk_getOpenFile -parent .dialog -initialdir $INITIALINSTDIR ]
|
|
if {$r ne {} } {
|
|
.dialog.f1.e2 delete 0 end
|
|
.dialog.f1.e2 insert 0 $r
|
|
}
|
|
raise .dialog .drw
|
|
}
|
|
button .dialog.f1.b1 -text "OK" -command {
|
|
set tctx::retval [.dialog.symprop get 1.0 {end - 1 chars}]
|
|
if { $tctx::selected_tok ne {<ALL>} } {
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval [xschem subst_tok $tctx::retval_orig $tctx::selected_tok $tctx::retval]
|
|
set tctx::selected_tok {<ALL>}
|
|
}
|
|
set symbol [.dialog.f1.e2 get]
|
|
set abssymbol [abs_sym_path $symbol]
|
|
set tctx::rcode {ok}
|
|
set user_wants_copy_cell $copy_cell
|
|
set prev_symbol [abs_sym_path $prev_symbol]
|
|
if { ($abssymbol ne $prev_symbol) && $copy_cell } {
|
|
if { ![regexp {^/} $symbol] && ![regexp {^[a-zA-Z]:} $symbol] } {
|
|
set symlist [file split $symbol]
|
|
set symlen [llength $symlist]
|
|
set abssymbol "[path_head $prev_symbol $symlen]/$symbol"
|
|
}
|
|
# puts "$abssymbol $prev_symbol"
|
|
if { [file exists "[file rootname $prev_symbol].sch"] } {
|
|
if { ! [file exists "[file rootname ${abssymbol}].sch"] } {
|
|
file copy "[file rootname $prev_symbol].sch" "[file rootname $abssymbol].sch"
|
|
# puts "file copy [file rootname $prev_symbol].sch [file rootname $abssymbol].sch"
|
|
}
|
|
}
|
|
if { [file exists "$prev_symbol"] } {
|
|
if { ! [file exists "$abssymbol"] } {
|
|
file copy "$prev_symbol" "$abssymbol"
|
|
# puts "file copy [file rootname $prev_symbol].sym [file rootname $abssymbol].sym"
|
|
}
|
|
}
|
|
}
|
|
#puts "symbol: $symbol , prev_symbol: $prev_symbol"
|
|
set copy_cell 0 ;# 20120919
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b2 -text "Cancel" -command {
|
|
set tctx::rcode {}
|
|
set edit_symbol_prop_new_sel {}
|
|
destroy .dialog
|
|
}
|
|
wm protocol .dialog WM_DELETE_WINDOW {
|
|
set tctx::rcode {}
|
|
set edit_symbol_prop_new_sel {}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b3 -text "Load" -command {
|
|
global INITIALPROPDIR
|
|
set a [tk_getOpenFile -parent .dialog -initialdir $INITIALPROPDIR ]
|
|
if [string compare $a ""] {
|
|
set INITIALPROPDIR [file dirname $a]
|
|
read_data_window .dialog.symprop $a
|
|
}
|
|
}
|
|
button .dialog.f1.b4 -text "Del" -command {
|
|
.dialog.symprop delete 1.0 end
|
|
}
|
|
checkbutton .dialog.f2.r1 -text "No change properties" -variable no_change_attrs -state normal
|
|
checkbutton .dialog.f2.r2 -text "Preserve unchanged props" -variable preserve_unchanged_attrs -state normal
|
|
checkbutton .dialog.f2.r3 -text "Copy cell" -variable copy_cell -state normal
|
|
set tok_list "<ALL> [list_tokens $tctx::retval]"
|
|
set tctx::selected_tok {<ALL>}
|
|
set tctx::old_selected_tok {<ALL>}
|
|
label .dialog.f2.r4 -text { Edit Attr:}
|
|
if { [info tclversion] > 8.4} {
|
|
ttk::combobox .dialog.f2.r5 -values $tok_list -textvariable tctx::selected_tok -width 14
|
|
}
|
|
pack .dialog.f1.l2 -side left
|
|
pack .dialog.f1.e2 -side left -fill x -expand yes
|
|
pack .dialog.f1.b1 -side left
|
|
pack .dialog.f1.b2 -side left
|
|
pack .dialog.f1.b3 -side left
|
|
pack .dialog.f1.b4 .dialog.f1.b5 -side left
|
|
pack .dialog.f4 -side top -anchor nw
|
|
#pack .dialog.f4.path .dialog.f4.symprop .dialog.f4.l1 -side left -fill x
|
|
pack .dialog.f4.path -side left
|
|
pack .dialog.f4.symprop -side left
|
|
pack .dialog.f1 .dialog.f2 -side top -fill x
|
|
pack .dialog.f2.r1 -side left
|
|
pack .dialog.f2.r2 -side left
|
|
pack .dialog.f2.r3 -side left
|
|
if { [info tclversion] > 8.4 } {
|
|
pack .dialog.f2.r4 -side left
|
|
pack .dialog.f2.r5 -side left
|
|
}
|
|
pack .dialog.yscroll -side right -fill y
|
|
pack .dialog.xscroll -side bottom -fill x
|
|
pack .dialog.symprop -fill both -expand yes
|
|
bind .dialog.symprop <Shift-KeyRelease-Return> {return_release %W;.dialog.f1.b1 invoke}
|
|
bind .dialog <Escape> {
|
|
if { ![string compare $tctx::retval [.dialog.symprop get 1.0 {end - 1 chars}]] && \
|
|
![string compare $symbol [ .dialog.f1.e2 get]] } {
|
|
.dialog.f1.b2 invoke
|
|
}
|
|
}
|
|
if { [info tclversion] > 8.4} {
|
|
bind .dialog.f2.r5 <<ComboboxSelected>> {
|
|
if {$tctx::old_selected_tok ne $tctx::selected_tok} {
|
|
if { $tctx::old_selected_tok eq {<ALL>} } {
|
|
set tctx::retval_orig [.dialog.symprop get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set tctx::retval [.dialog.symprop get 1.0 {end - 1 chars}]
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;# vim syntax fix "
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval_orig [xschem subst_tok $tctx::retval_orig $tctx::old_selected_tok $tctx::retval]
|
|
}
|
|
}
|
|
if {$tctx::selected_tok eq {<ALL>} } {
|
|
set tctx::retval $tctx::retval_orig
|
|
} else {
|
|
set tctx::retval [xschem get_tok $tctx::retval_orig $tctx::selected_tok 2]
|
|
# regsub -all {\\?"} $tctx::retval {"} tctx::retval
|
|
}
|
|
.dialog.symprop delete 1.0 end
|
|
.dialog.symprop insert 1.0 $tctx::retval
|
|
set tctx::old_selected_tok $tctx::selected_tok
|
|
}
|
|
|
|
bind .dialog.f2.r5 <KeyRelease> {
|
|
set tctx::selected_tok [.dialog.f2.r5 get]
|
|
if { $tctx::old_selected_tok eq {<ALL>}} {
|
|
set tctx::retval_orig [.dialog.symprop get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set tctx::retval [.dialog.symprop get 1.0 {end - 1 chars}]
|
|
if {$tctx::retval ne {}} {
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval_orig [xschem subst_tok $tctx::retval_orig $tctx::old_selected_tok $tctx::retval]
|
|
}
|
|
}
|
|
if {$tctx::selected_tok eq {<ALL>} } {
|
|
set tctx::retval $tctx::retval_orig
|
|
} else {
|
|
set tctx::retval [xschem get_tok $tctx::retval_orig $tctx::selected_tok 2]
|
|
# regsub -all {\\?"} $tctx::retval {"} tctx::retval
|
|
}
|
|
.dialog.symprop delete 1.0 end
|
|
.dialog.symprop insert 1.0 $tctx::retval
|
|
set tctx::old_selected_tok $tctx::selected_tok
|
|
}
|
|
}
|
|
if {$edit_symbol_prop_new_sel == 1} {
|
|
wm geometry .dialog $edit_prop_pos
|
|
}
|
|
set edit_symbol_prop_new_sel 0
|
|
|
|
tkwait visibility .dialog
|
|
# select text after value= or lab= and place cursor just before selection
|
|
|
|
set sym_sel_attr [xschem get_tok $tctx::retval select] ;# get from instance
|
|
if {$sym_sel_attr eq {}} {
|
|
if {[catch {xschem getprop symbol $symbol select} sym_sel_attr]} {
|
|
set sym_sel_attr {}
|
|
}
|
|
}
|
|
if {$sym_sel_attr eq {*}} {
|
|
.dialog.symprop tag add sel 1.0 {end - 1 chars}
|
|
.dialog.symprop mark set insert 1.0
|
|
} else {
|
|
foreach attr [list $sym_sel_attr value lab name] {
|
|
if {$attr eq {}} {continue}
|
|
set regx {}
|
|
set regx1 {}
|
|
append regx $attr { *= *("([^"]|(\\"))+"|[^ \t\n"]+)} ;# vim syntax fix "
|
|
append regx1 $attr { *= *[^ \n]}
|
|
if { [info tclversion] > 8.4} {
|
|
set idx [.dialog.symprop search -regexp -nolinestop -count nchars $regx 1.0]
|
|
.dialog.symprop search -regexp -nolinestop -count len $regx1 1.0
|
|
} else {
|
|
set idx [.dialog.symprop search -regexp -count nchars $regx 1.0]
|
|
.dialog.symprop search -regexp -count len $regx1 1.0
|
|
}
|
|
if {$idx ne {}} break
|
|
}
|
|
if { $idx ne {} } {
|
|
incr len -1
|
|
.dialog.symprop tag add sel "$idx + $len chars" "$idx + $nchars chars"
|
|
.dialog.symprop mark set insert "$idx + $len chars"
|
|
}
|
|
}
|
|
focus .dialog.symprop
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $tctx::rcode
|
|
}
|
|
|
|
# reads metadata tokens from header component of the symbol inside `v {data}` element
|
|
# and returns dictionary in name of the token as key and value of the token as value in dictionary
|
|
# Courtesy @georgtree
|
|
proc symbolParse {file} {
|
|
try {
|
|
set file [open $file r]
|
|
} on error {errmsg erropts} {
|
|
puts stderr "Error while reading symbol file '$file': $errmsg"
|
|
return
|
|
}
|
|
set data [read $file]
|
|
close $file
|
|
# pattern to find v {} and extract content inside brackets
|
|
set pattern {(?:^|\n)v\s+\{((?:[^{}]|\\[{}])*)\}}
|
|
if {![regexp $pattern $data -> content]} {
|
|
return
|
|
}
|
|
# outer braces {...} are not part of content, so remove escaping of inner {, } and \ .
|
|
set content [string map { \\\{ \{ \\\} \} \\\\ \\ } $content]
|
|
# pattern to find: name="value" or name=value or name = "value" or name = value
|
|
set pattern {(\w+)\s*=\s*(?:"((?:[^"]|\\["])*)"|(\S+))}
|
|
set start 0
|
|
# 'match' variable holds the complete matched pattern, used for searching next one
|
|
while {[regexp -start $start $pattern $content -> name quotedValue unquotedValue]} {
|
|
# Determine the value (quoted or unquoted)
|
|
if {[string length $quotedValue] > 0} {
|
|
set value $quotedValue
|
|
# outer quotes are removed from value,
|
|
# remove escaping of internal backslashes and doublequotes
|
|
dict append tokens $name [string map {\\\\ \\ \\\" \" } $value]
|
|
} else {
|
|
set value $unquotedValue
|
|
dict append tokens $name $value
|
|
}
|
|
# Update the start index to continue searching after this match
|
|
set start [expr {[string first $value $content $start] + [string length $value]}]
|
|
# Safety check to prevent infinite loops
|
|
if {$start <= 0} {
|
|
break
|
|
}
|
|
}
|
|
return $tokens
|
|
}
|
|
|
|
proc read_data_nonewline {f} {
|
|
set res [catch {open $f r} fid]
|
|
if {$res} { puts "read_data_nonewline: $fid"; return {}}
|
|
set data [read -nonewline $fid]
|
|
close $fid
|
|
return $data
|
|
}
|
|
|
|
proc read_data {f} {
|
|
set res [catch {open $f r} fid]
|
|
if {$res} { puts "read_data: $fid"; return {}}
|
|
set data [read $fid]
|
|
close $fid
|
|
return $data
|
|
}
|
|
|
|
proc read_data_window {w f} {
|
|
set res [catch {open $f r} fid]
|
|
if {$res} { puts "read_data_window: $fid"; return {}}
|
|
set t [read $fid]
|
|
# $w delete 0.0 end
|
|
## 20171103 insert text at cursor position instead of at beginning (insert index tag)
|
|
$w insert insert $t
|
|
close $fid
|
|
}
|
|
|
|
proc write_data {data f} {
|
|
|
|
set res [catch {open $f w} fid]
|
|
if {$res} { puts "write_data: $fid"; return {}}
|
|
puts -nonewline $fid $data
|
|
close $fid
|
|
return {}
|
|
}
|
|
|
|
proc text_line {txtlabel clear {preserve_disabled disabled} } {
|
|
global text_line_default_geometry preserve_unchanged_attrs wm_fix tabstop
|
|
global debug_var text_tabs_setting
|
|
|
|
set buttonstate $preserve_disabled
|
|
if {$preserve_disabled eq {header}} { set buttonstate {disabled}}
|
|
|
|
if {$preserve_disabled eq {disabled}} {
|
|
set tctx::selected_mode [xschem get netlist_type]
|
|
set glob_attr [string map {
|
|
spice schprop
|
|
vhdl schvhdlprop
|
|
verilog schverilogprop
|
|
tedax schtedaxprop
|
|
symbol schsymbolprop
|
|
spectre schspectreprop
|
|
} $tctx::selected_mode]
|
|
set mode_list {Spice[S] Vhdl[G] Verilog[V] Tedax[E] Symbol[K] Spectre[F]}
|
|
set tctx::selected_mode [string map {
|
|
spice Spice[S]
|
|
vhdl Vhdl[G]
|
|
verilog Verilog[V]
|
|
tedax Tedax[E]
|
|
symbol Symbol[K]
|
|
spectre Spectre[F]} $tctx::selected_mode]
|
|
set tctx::old_selected_mode $tctx::selected_mode
|
|
set tctx::retval [xschem get $glob_attr]
|
|
}
|
|
|
|
set tctx::retval_orig $tctx::retval
|
|
if $clear==1 then {set tctx::retval ""}
|
|
set tctx::rcode {}
|
|
if { [winfo exists .dialog] } return
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Text input}
|
|
wm transient .dialog [xschem get topwindow]
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
|
|
set tok_list "<ALL> [list_tokens $tctx::retval]"
|
|
set tctx::selected_tok {<ALL>}
|
|
set tctx::old_selected_tok {<ALL>}
|
|
bind .dialog <Configure> {
|
|
# puts [wm geometry .dialog]
|
|
set text_line_default_geometry [wm geometry .dialog]
|
|
regsub {\+.*} $text_line_default_geometry {} text_line_default_geometry
|
|
}
|
|
|
|
# 20100203
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
wm geometry .dialog "${text_line_default_geometry}+$X+$Y"
|
|
|
|
frame .dialog.f0
|
|
frame .dialog.f1
|
|
label .dialog.f0.l1 -text $txtlabel
|
|
eval text .dialog.textinput -undo 1 -relief sunken -bd 2 -yscrollcommand \".dialog.yscroll set\" -setgrid 1 \
|
|
-xscrollcommand \".dialog.xscroll set\" -wrap none -width 90 -height 40 $text_tabs_setting
|
|
scrollbar .dialog.yscroll -command ".dialog.textinput yview"
|
|
scrollbar .dialog.xscroll -command ".dialog.textinput xview" -orient horiz
|
|
.dialog.textinput delete 1.0 end
|
|
.dialog.textinput insert 1.0 $tctx::retval
|
|
button .dialog.f1.b1 -text "OK" -command \
|
|
{
|
|
set tctx::retval [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
if { $tctx::selected_tok ne {<ALL>} } {
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval [xschem subst_tok $tctx::retval_orig $tctx::selected_tok $tctx::retval]
|
|
set tctx::selected_tok {<ALL>}
|
|
}
|
|
|
|
set tctx::rcode {ok}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b2 -text "Cancel" -command \
|
|
{
|
|
set tctx::retval [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
set tctx::rcode {}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b3 -text "Load" -command \
|
|
{
|
|
global INITIALPROPDIR
|
|
set a [tk_getOpenFile -parent .dialog -initialdir $INITIALPROPDIR ]
|
|
if [string compare $a ""] {
|
|
set INITIALPROPDIR [file dirname $a]
|
|
read_data_window .dialog.textinput $a
|
|
}
|
|
}
|
|
button .dialog.f1.b4 -text "Del" -command \
|
|
{
|
|
.dialog.textinput delete 1.0 end
|
|
}
|
|
|
|
if { [info tclversion] > 8.4} {
|
|
if {$preserve_disabled eq {disabled}} {
|
|
label .dialog.f1.r6 -text {Mode:}
|
|
ttk::combobox .dialog.f1.r7 -values $mode_list -textvariable tctx::selected_mode -width 14
|
|
}
|
|
if { $preserve_disabled ne {header} } {
|
|
label .dialog.f1.r4 -text { Edit Attr:}
|
|
ttk::combobox .dialog.f1.r5 -values $tok_list -textvariable tctx::selected_tok -width 14
|
|
}
|
|
}
|
|
|
|
checkbutton .dialog.f0.l2 -text "preserve unchanged props" -variable preserve_unchanged_attrs \
|
|
-state $buttonstate
|
|
pack .dialog.f0 -fill x
|
|
pack .dialog.f0.l2 -side left
|
|
pack .dialog.f0.l1 -side left -expand yes
|
|
pack .dialog.f1 -fill x
|
|
pack .dialog.f1.b1 -side left -fill x -expand yes
|
|
pack .dialog.f1.b2 -side left -fill x -expand yes
|
|
pack .dialog.f1.b3 -side left -fill x -expand yes
|
|
pack .dialog.f1.b4 -side left -fill x -expand yes
|
|
if { [info tclversion] > 8.4} {
|
|
if { $preserve_disabled ne {header} } {
|
|
pack .dialog.f1.r4 -side left
|
|
pack .dialog.f1.r5 -side left
|
|
}
|
|
if {$preserve_disabled eq {disabled}} {
|
|
pack .dialog.f1.r6 -side left
|
|
pack .dialog.f1.r7 -side left
|
|
}
|
|
}
|
|
|
|
|
|
pack .dialog.yscroll -side right -fill y
|
|
pack .dialog.xscroll -side bottom -fill x
|
|
pack .dialog.textinput -expand yes -fill both
|
|
bind .dialog <Escape> {
|
|
if ![string compare $tctx::retval [.dialog.textinput get 1.0 {end - 1 chars}]] {
|
|
.dialog.f1.b2 invoke
|
|
}
|
|
}
|
|
|
|
if { $preserve_disabled ne {header} && [info tclversion] > 8.4} {
|
|
bind .dialog.f1.r5 <<ComboboxSelected>> {
|
|
if {$tctx::old_selected_tok ne $tctx::selected_tok} {
|
|
if { $tctx::old_selected_tok eq {<ALL>} } {
|
|
set tctx::retval_orig [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set tctx::retval [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval_orig [xschem subst_tok $tctx::retval_orig $tctx::old_selected_tok $tctx::retval]
|
|
}
|
|
}
|
|
if {$tctx::selected_tok eq {<ALL>} } {
|
|
set tctx::retval $tctx::retval_orig
|
|
} else {
|
|
set tctx::retval [xschem get_tok $tctx::retval_orig $tctx::selected_tok 2]
|
|
# regsub -all {\\?"} $tctx::retval {"} tctx::retval
|
|
}
|
|
.dialog.textinput delete 1.0 end
|
|
.dialog.textinput insert 1.0 $tctx::retval
|
|
set tctx::old_selected_tok $tctx::selected_tok
|
|
}
|
|
bind .dialog.f1.r5 <KeyRelease> {
|
|
set tctx::selected_tok [.dialog.f1.r5 get]
|
|
if { $tctx::old_selected_tok eq {<ALL>}} {
|
|
set tctx::retval_orig [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set tctx::retval [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
if {$tctx::retval ne {}} {
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval_orig [xschem subst_tok $tctx::retval_orig $tctx::old_selected_tok $tctx::retval]
|
|
}
|
|
}
|
|
if {$tctx::selected_tok eq {<ALL>} } {
|
|
set tctx::retval $tctx::retval_orig
|
|
} else {
|
|
set tctx::retval [xschem get_tok $tctx::retval_orig $tctx::selected_tok 2]
|
|
# regsub -all {\\?"} $tctx::retval {"} tctx::retval
|
|
}
|
|
.dialog.textinput delete 1.0 end
|
|
.dialog.textinput insert 1.0 $tctx::retval
|
|
set tctx::old_selected_tok $tctx::selected_tok
|
|
}
|
|
}
|
|
|
|
if { [info tclversion] > 8.4} {
|
|
if {$preserve_disabled eq {disabled}} {
|
|
bind .dialog.f1.r7 <<ComboboxSelected>> {
|
|
proc set_global_mode {} {
|
|
|
|
set tctx::retval [.dialog.textinput get 1.0 {end - 1 chars}]
|
|
if { $tctx::selected_tok ne {<ALL>} } {
|
|
regsub -all {(["\\])} $tctx::retval {\\\1} tctx::retval ;#" editor is confused by the previous quote
|
|
set tctx::retval \"${tctx::retval}\"
|
|
set tctx::retval [xschem subst_tok $tctx::retval_orig $tctx::selected_tok $tctx::retval]
|
|
}
|
|
|
|
if {$tctx::retval ne $tctx::retval_orig} {
|
|
xschem push_undo
|
|
xschem set_modify 1
|
|
set glob_attr [string map {
|
|
Spice[S] schprop
|
|
Vhdl[G] schvhdlprop
|
|
Verilog[V] schverilogprop
|
|
Tedax[E] schtedaxprop
|
|
Symbol[K] schsymbolprop
|
|
Spectre[F] schspectreprop
|
|
} $tctx::old_selected_mode]
|
|
xschem set $glob_attr $tctx::retval
|
|
}
|
|
set mode [string map {
|
|
Spice[S] spice
|
|
Vhdl[G] vhdl
|
|
Verilog[V] verilog
|
|
Tedax[E] tedax
|
|
Symbol[K] symbol
|
|
Spectre[F] spectre} $tctx::selected_mode]
|
|
|
|
set glob_attr [string map {
|
|
spice schprop
|
|
vhdl schvhdlprop
|
|
verilog schverilogprop
|
|
tedax schtedaxprop
|
|
symbol schsymbolprop
|
|
spectre schspectreprop
|
|
} $mode]
|
|
|
|
set tctx::old_selected_mode $tctx::selected_mode
|
|
set $tctx::selected_tok {<ALL>}
|
|
set tctx::retval [xschem get $glob_attr]
|
|
set tctx::retval_orig $tctx::retval
|
|
set tok_list "<ALL> [list_tokens $tctx::retval]"
|
|
.dialog.f1.r5 configure -values $tok_list
|
|
.dialog.textinput delete 1.0 end
|
|
.dialog.textinput insert 1.0 $tctx::retval
|
|
}
|
|
set_global_mode
|
|
}
|
|
}
|
|
}
|
|
|
|
bind .dialog.textinput <Shift-KeyRelease-Return> {return_release %W; .dialog.f1.b1 invoke}
|
|
#tkwait visibility .dialog
|
|
#grab set .dialog
|
|
#focus .dialog.textinput
|
|
set tctx::rcode {}
|
|
tkwait window .dialog
|
|
|
|
if {$preserve_disabled eq {disabled}} {
|
|
if {$tctx::retval ne $tctx::retval_orig} {
|
|
xschem push_undo
|
|
xschem set_modify 1
|
|
set glob_attr [string map {
|
|
Spice[S] schprop
|
|
Vhdl[G] schvhdlprop
|
|
Verilog[V] schverilogprop
|
|
Tedax[E] schtedaxprop
|
|
Symbol[K] schsymbolprop
|
|
Spectre[F] schspectreprop
|
|
} $tctx::selected_mode]
|
|
xschem set $glob_attr $tctx::retval
|
|
}
|
|
}
|
|
|
|
return $tctx::rcode
|
|
}
|
|
|
|
# alert_ text [position] [nowait] [yesno]
|
|
# show an alert dialog box and display 'text'.
|
|
# if 'position' is empty (example: alert_ {hello, world} {}) show at mouse coordinates
|
|
# otherwise use specified coordinates example: alert_ {hello, world} +300+400
|
|
# if nowait is 1 do not wait for user to close dialog box
|
|
# if yesnow is 1 show yes and no buttons and return user choice (1 / 0).
|
|
# (this works only if nowait is unset).
|
|
proc alert_ {txtlabel {position +200+300} {nowait {0}} {yesno 0}} {
|
|
global has_x
|
|
set tctx::rcode 1
|
|
if {![info exists has_x] } {return}
|
|
toplevel .alert -class Dialog
|
|
wm title .alert {Alert}
|
|
wm transient .alert [xschem get topwindow]
|
|
set X [expr {[winfo pointerx .alert] - 70}]
|
|
set Y [expr {[winfo pointery .alert] - 60}]
|
|
if { [string compare $position ""] != 0 } {
|
|
wm geometry .alert $position
|
|
} else {
|
|
wm geometry .alert "+$X+$Y"
|
|
}
|
|
label .alert.l1 -font {Sans 10 bold} -justify left \
|
|
-text " \n${txtlabel} \n" -wraplength 750
|
|
if { $yesno} {
|
|
set oktxt Yes
|
|
} else {
|
|
set oktxt OK
|
|
}
|
|
button .alert.b1 -text $oktxt -command \
|
|
{
|
|
set tctx::rcode 1
|
|
destroy .alert
|
|
}
|
|
if {$yesno} {
|
|
button .alert.b2 -text "No" -command \
|
|
{
|
|
set tctx::rcode 0
|
|
destroy .alert
|
|
}
|
|
}
|
|
|
|
pack .alert.l1 -side top -fill both -expand yes
|
|
pack .alert.b1 -side left -fill x -expand yes
|
|
if {$yesno} {pack .alert.b2 -side left -fill x -expand yes}
|
|
tkwait visibility .alert
|
|
# grab set .alert
|
|
focus .alert.b1
|
|
bind .alert <Return> { destroy .alert }
|
|
bind .alert <Escape> { destroy .alert }
|
|
bind .alert <Visibility> {
|
|
if { [winfo exists .alert] && [winfo ismapped .alert] && [winfo ismapped .] && [wm stackorder .alert isbelow . ]} {
|
|
if { [winfo exists .drw] } {
|
|
raise .alert .drw
|
|
} else {
|
|
raise .alert
|
|
}
|
|
|
|
}
|
|
}
|
|
if {!$nowait} {tkwait window .alert}
|
|
return $tctx::rcode
|
|
}
|
|
|
|
proc show_infotext {{err 0}} {
|
|
global has_x infowindow_text show_infowindow_after_netlist
|
|
set s $show_infowindow_after_netlist
|
|
if {$s == 1} { set s always}
|
|
if {$s == 0} { set s onerror}
|
|
if {[info exists has_x]} {
|
|
infowindow
|
|
}
|
|
if {($s eq {always}) || ($err != 0 && $s eq {onerror})} {
|
|
if {[info exists has_x]} {
|
|
wm deiconify .infotext
|
|
} else {
|
|
xschem log_write [xschem get infowindow_text]
|
|
}
|
|
}
|
|
}
|
|
|
|
proc infowindow {} {
|
|
global infowindow_text has_x
|
|
set infowindow_text [xschem get infowindow_text]
|
|
if {![info exists has_x]} { return }
|
|
set z {.infotext}
|
|
if ![string compare $infowindow_text ""] {
|
|
if [winfo exists $z] {
|
|
$z.f1.text delete 1.0 end
|
|
}
|
|
}
|
|
if ![winfo exists $z] {
|
|
toplevel $z
|
|
wm title $z {Info window}
|
|
# wm transient $z [xschem get topwindow]
|
|
wm geometry $z 90x24+0+400 ;# gridded window: grid units, not pixels
|
|
wm iconname $z {Info window}
|
|
wm withdraw $z
|
|
wm protocol .infotext WM_DELETE_WINDOW "wm withdraw $z; set show_infowindow 0"
|
|
# button $z.dismiss -text Dismiss -command "destroy $z"
|
|
frame $z.f1
|
|
frame $z.f2
|
|
text $z.f1.text -undo 1 -relief sunken -bd 2 -yscrollcommand "$z.f1.yscroll set" -setgrid 1 \
|
|
-height 6 -width 50 -xscrollcommand "$z.f1.xscroll set" -wrap none
|
|
scrollbar $z.f1.yscroll -command "$z.f1.text yview" -orient v
|
|
scrollbar $z.f1.xscroll -command "$z.f1.text xview" -orient h
|
|
grid $z.f1.text - $z.f1.yscroll -sticky nsew
|
|
grid $z.f1.xscroll - -sticky ew
|
|
# grid $z.dismiss - -
|
|
grid rowconfig $z.f1 0 -weight 1
|
|
grid columnconfig $z.f1 0 -weight 1
|
|
pack $z.f1 -fill both -expand yes
|
|
button $z.f2.dismiss -text Dismiss -command "wm withdraw $z; set show_infowindow 0"
|
|
pack $z.f2.dismiss
|
|
pack $z.f2 -fill x
|
|
bind $z <Escape> "wm withdraw $z; set show_infowindow 0"
|
|
}
|
|
$z.f1.text delete 1.0 end
|
|
$z.f1.text insert 1.0 $infowindow_text
|
|
## does not work in tcl/tk8.4
|
|
# set lines [$z.f1.text count -displaylines 1.0 end]
|
|
set lines [regexp -all \n [$z.f1.text get 1.0 end]]
|
|
$z.f1.text see ${lines}.0
|
|
return {}
|
|
}
|
|
|
|
proc editdata {{data {}} {title {Edit data}} {wrap {none}} {ro 1}} {
|
|
global text_tabs_setting tabstop
|
|
set window .editdata
|
|
set tctx::retval $data
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel $window
|
|
wm title $window $title
|
|
wm iconname $window $title
|
|
# wm transient $window [xschem get topwindow]
|
|
frame $window.buttons
|
|
pack $window.buttons -side bottom -fill x -pady 2m
|
|
button $window.buttons.copy -text {Copy to clipboard} -command "
|
|
clipboard clear
|
|
clipboard append \[$window.text get 1.0 {end - 1 chars}\]
|
|
"
|
|
button $window.buttons.ok -text OK -command "
|
|
set tctx::retval \[$window.text get 1.0 {end - 1 chars}\]; destroy $window
|
|
"
|
|
button $window.buttons.cancel -text Cancel -command "destroy $window"
|
|
|
|
pack $window.buttons.ok -side left -expand 1
|
|
pack $window.buttons.cancel -side left -expand 1
|
|
pack $window.buttons.copy -side left -expand 1
|
|
|
|
if { $ro ne {1} } {
|
|
button $window.buttons.saveas -text {Save a copy} -command {
|
|
proc editdata_save {} {
|
|
global OS env
|
|
|
|
if {$OS == "Windows"} {
|
|
set editdata_filename [tk_getSaveFile -initialdir $env(windir) ]
|
|
} else {
|
|
set editdata_filename [tk_getSaveFile -initialdir [pwd] ]
|
|
}
|
|
if { $editdata_filename != "" } {
|
|
if {[catch {open $editdata_filename w} editdata_fileid]} {
|
|
puts "editdata: $editdata_fileid"
|
|
} else {
|
|
puts -nonewline $editdata_fileid [.editdata.text get 1.0 {end - 1 chars}]
|
|
close $editdata_fileid
|
|
}
|
|
}
|
|
}
|
|
editdata_save
|
|
}
|
|
pack $window.buttons.saveas -side left -expand 1
|
|
}
|
|
|
|
eval text $window.text -undo 1 -relief sunken -bd 2 -yscrollcommand \"$window.yscroll set\" -setgrid 1 \
|
|
-xscrollcommand \"$window.xscroll set\" -wrap $wrap -height 30 $text_tabs_setting
|
|
scrollbar $window.yscroll -command "$window.text yview"
|
|
scrollbar $window.xscroll -command "$window.text xview" -orient horiz
|
|
pack $window.yscroll -side right -fill y
|
|
pack $window.text -expand yes -fill both
|
|
pack $window.xscroll -side bottom -fill x
|
|
bind $window <Escape> "$window.buttons.cancel invoke"
|
|
|
|
# 20171103 insert at insertion cursor(insert tag) instead of 0.0
|
|
$window.text insert insert $data
|
|
tkwait window $window
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $tctx::retval
|
|
}
|
|
|
|
proc textwindow {filename {ro {}}} {
|
|
global textwindow_wcounter
|
|
global textwindow_w
|
|
# set textwindow_w .win$textwindow_wcounter
|
|
# catch {destroy $textwindow_w}
|
|
set textwindow_wcounter [expr {$textwindow_wcounter+1}]
|
|
set textwindow_w .win$textwindow_wcounter
|
|
|
|
|
|
global textwindow_filename text_tabs_setting tabstop
|
|
global textwindow_fileid
|
|
set textwindow_filename $filename
|
|
toplevel $textwindow_w
|
|
wm title $textwindow_w $filename
|
|
wm iconname $textwindow_w $filename
|
|
# wm transient $textwindow_w [xschem get topwindow]
|
|
frame $textwindow_w.buttons
|
|
pack $textwindow_w.buttons -side bottom -fill x -pady 2m
|
|
button $textwindow_w.buttons.dismiss -text Dismiss -command "destroy $textwindow_w"
|
|
pack $textwindow_w.buttons.dismiss -side left -expand 1
|
|
if { $ro eq {} } {
|
|
button $textwindow_w.buttons.save -text "Save" -command \
|
|
{
|
|
if {[catch {open $textwindow_filename w} textwindow_fileid]} {
|
|
puts "textwindow: $textwindow_fileid"
|
|
} else {
|
|
puts -nonewline $textwindow_fileid [$textwindow_w.text get 1.0 {end - 1 chars}]
|
|
close $textwindow_fileid
|
|
}
|
|
destroy $textwindow_w
|
|
}
|
|
pack $textwindow_w.buttons.save -side left -expand 1
|
|
}
|
|
|
|
eval text $textwindow_w.text -undo 1 -relief sunken -bd 2 -yscrollcommand \"$textwindow_w.yscroll set\" -setgrid 1 \
|
|
-xscrollcommand \"$textwindow_w.xscroll set\" -wrap none -height 30 $text_tabs_setting
|
|
scrollbar $textwindow_w.yscroll -command "$textwindow_w.text yview"
|
|
scrollbar $textwindow_w.xscroll -command "$textwindow_w.text xview" -orient horiz
|
|
pack $textwindow_w.yscroll -side right -fill y
|
|
pack $textwindow_w.text -expand yes -fill both
|
|
pack $textwindow_w.xscroll -side bottom -fill x
|
|
bind $textwindow_w <Escape> "$textwindow_w.buttons.dismiss invoke"
|
|
set textwindow_fileid [open $filename r]
|
|
if {[catch {open $filename r} textwindow_fileid]} {
|
|
puts "textwindow: $textwindow_fileid"
|
|
} else {
|
|
$textwindow_w.text insert insert [read $textwindow_fileid]
|
|
close $textwindow_fileid
|
|
}
|
|
return {}
|
|
}
|
|
|
|
proc viewdata {data {ro {}} {win .view} {wrap none}} {
|
|
global viewdata_wcounter viewdata_filename
|
|
global viewdata_w OS viewdata_fileid env has_x text_tabs_setting tabstop
|
|
if {![info exists has_x]} {return}
|
|
# set viewdata_w .view$viewdata_wcounter
|
|
# catch {destroy $viewdata_w}
|
|
if {$win eq {.view}} {
|
|
set viewdata_wcounter [expr {$viewdata_wcounter+1}]
|
|
set viewdata_w $win$viewdata_wcounter
|
|
} else {
|
|
set viewdata_w $win
|
|
}
|
|
set tctx::rcode {}
|
|
toplevel $viewdata_w
|
|
wm title $viewdata_w {View data}
|
|
# wm transient $viewdata_w [xschem get topwindow]
|
|
frame $viewdata_w.buttons
|
|
pack $viewdata_w.buttons -side bottom -fill x -pady 2m
|
|
|
|
button $viewdata_w.buttons.dismiss -text Dismiss -command "destroy $viewdata_w"
|
|
pack $viewdata_w.buttons.dismiss -side left -expand 1
|
|
|
|
if { $ro eq {} } {
|
|
button $viewdata_w.buttons.saveas -text {Save As} -command {
|
|
if {$OS == "Windows"} {
|
|
set viewdata_filename [tk_getSaveFile -initialdir $env(windir) ]
|
|
} else {
|
|
set viewdata_filename [tk_getSaveFile -initialdir [pwd] ]
|
|
}
|
|
if { $viewdata_filename != "" } {
|
|
if {[catch {open $viewdata_filename w} viewdata_fileid]} {
|
|
puts "viewdata: $viewdata_fileid"
|
|
} else {
|
|
puts -nonewline $viewdata_fileid [$viewdata_w.text get 1.0 {end - 1 chars}]
|
|
close $viewdata_fileid
|
|
}
|
|
}
|
|
}
|
|
pack $viewdata_w.buttons.saveas -side left -expand 1
|
|
}
|
|
|
|
eval text $viewdata_w.text -undo 1 -relief sunken -bd 2 -yscrollcommand \"$viewdata_w.yscroll set\" -setgrid 1 \
|
|
-xscrollcommand \"$viewdata_w.xscroll set\" -wrap $wrap -height 30 $text_tabs_setting
|
|
scrollbar $viewdata_w.yscroll -command "$viewdata_w.text yview"
|
|
scrollbar $viewdata_w.xscroll -command "$viewdata_w.text xview" -orient horiz
|
|
pack $viewdata_w.yscroll -side right -fill y
|
|
pack $viewdata_w.text -expand yes -fill both
|
|
pack $viewdata_w.xscroll -side bottom -fill x
|
|
# 20171103 insert at insertion cursor(insert tag) instead of 0.0
|
|
$viewdata_w.text insert insert $data
|
|
bind $viewdata_w <Escape> "$viewdata_w.buttons.dismiss invoke"
|
|
return $tctx::rcode
|
|
}
|
|
|
|
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 [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]} {
|
|
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 {![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 $first $fullpath] ;# recursive call
|
|
incr match_file_level -1
|
|
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 {$fullpath} { set file $j } else { set file [file tail $j]}
|
|
if {[regexp $f $file]} {
|
|
lappend res $j
|
|
if {$first} {return $res}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
# 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} {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 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 {}} {maxdepth -1} {first 0}} {
|
|
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 {![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 $maxdepth $first] ;# recursive call
|
|
incr match_file_level -1
|
|
if {$sub_res != {} } {
|
|
set res [concat $res $sub_res]
|
|
if {$first} {return $res}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
set fname [file tail $j]
|
|
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}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
# find given file $f into $paths directories
|
|
# use $pathlist global search path if $paths empty
|
|
# recursively descend directories
|
|
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 $maxdepth 0]
|
|
catch {unset match_file_dir_arr}
|
|
|
|
return $res
|
|
}
|
|
|
|
# find given file $f into $paths directories
|
|
# use $pathlist global search path if $paths empty
|
|
# recursively descend directories
|
|
# only return FIRST FOUND
|
|
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 $maxdepth 1]
|
|
catch {unset match_file_dir_arr}
|
|
return $res
|
|
}
|
|
|
|
|
|
# alternative implementation of "file dirname ... "
|
|
# that does not mess with http:// (file dirname removes double slashes)
|
|
proc get_directory {f} {
|
|
if {![regexp {/} $f]} {
|
|
set r .
|
|
} else {
|
|
set r [regsub {/[^/]*$} $f {}]
|
|
}
|
|
regsub {/\.$} $r {} r
|
|
return $r
|
|
}
|
|
|
|
# set 'n' last directory components to every symbol
|
|
proc fix_symbols {n {pattern {}}} {
|
|
xschem push_undo
|
|
foreach {i s t} [xschem instance_list] {
|
|
if {$pattern ne {} && ![regexp $pattern $s]} {continue}
|
|
if {![regexp {\(.*\)$} $s param]} { set param {}}
|
|
regsub {\([^)]*\)$} $s {} s
|
|
set sympath [find_file_first [file tail $s]]
|
|
if { $sympath ne {}} {
|
|
set new_sym_ref [get_cell $sympath $n]$param
|
|
puts "Remapping $i: $s$param --> $new_sym_ref"
|
|
xschem reset_symbol $i $new_sym_ref
|
|
}
|
|
}
|
|
xschem reload_symbols
|
|
xschem set_modify 1
|
|
xschem redraw
|
|
}
|
|
|
|
# fetch a remote url into ${XSCHEM_TMP_DIR}/xschem_web
|
|
proc download_url {url} {
|
|
global XSCHEM_TMP_DIR download_url_helper OS has_x
|
|
# puts "download_url: $url"
|
|
# puts "xschem_web_dirname: $xschem_web_dirname"
|
|
set xschem_web_dirname [xschem get xschem_web_dirname]
|
|
if {![file exists $xschem_web_dirname]} {
|
|
set msg {xschem_web_xxxxx directory was not created. Remote url download will not work}
|
|
puts stderr $msg
|
|
if {[info exists has_x]} {
|
|
alert_ $msg {} 0 0
|
|
}
|
|
return 1 ;# fail
|
|
}
|
|
if {$OS eq "Windows"} {
|
|
set cmd "cmd /c \"cd ${xschem_web_dirname} & $download_url_helper $url\""
|
|
set r [catch {eval exec $cmd } res]
|
|
} else {
|
|
set r [catch {exec sh -c "cd ${xschem_web_dirname}; $download_url_helper $url"} res]
|
|
}
|
|
# puts "download_url: url=$url, exit code=$r, res=$res"
|
|
return $r
|
|
}
|
|
|
|
# use some heuristic to find a sub sch/sym reference in the web repository.
|
|
proc try_download_url {dirname sch_or_sym} {
|
|
set url $dirname/$sch_or_sym
|
|
# puts "try_download_url: dirname=$dirname, sch_or_sym=$sch_or_sym"
|
|
set r [download_url $url]
|
|
if { $r!=0} {
|
|
# count # of directories in sch/sym reference
|
|
set nitems [regexp -all {/+} $sch_or_sym]
|
|
# puts "try_download_url: dirname=$dirname, sch_or_sym=$sch_or_sym, nitems=$nitems"
|
|
while { $nitems > 0} {
|
|
# remove one path component from dirname and try to download URL
|
|
set dirname [get_directory $dirname]
|
|
incr nitems -1
|
|
set url $dirname/$sch_or_sym
|
|
set r [download_url $url]
|
|
# done if url found
|
|
if { $r == 0 } { break }
|
|
}
|
|
}
|
|
}
|
|
|
|
# Given an absolute path 'symbol' of a symbol/schematic remove the path prefix
|
|
# if file is in a library directory (a $pathlist dir)
|
|
# Example: rel_sym_path /home/schippes/share/xschem/xschem_library/devices/iopin.sym
|
|
# devices/iopin.sym
|
|
proc rel_sym_path {symbol {paths {}} } {
|
|
global OS pathlist env
|
|
# puts "rel_sym_path: $symbol $paths"
|
|
|
|
if { $paths eq {}} {set paths $pathlist}
|
|
regsub {^~/} $symbol ${env(HOME)}/ symbol
|
|
# if {$OS eq "Windows"} {
|
|
# if {![regexp {^[A-Za-z]\:/} $symbol]} {
|
|
# set symbol [pwd]/$symbol
|
|
# }
|
|
# } else {
|
|
# if {![regexp {^/} $symbol]} {
|
|
# set symbol [pwd]/$symbol
|
|
# }
|
|
# }
|
|
set curr_dirname [pwd]
|
|
set name {}
|
|
foreach path_elem $paths {
|
|
if { ![string compare $path_elem .] && [info exist curr_dirname]} {
|
|
set path_elem $curr_dirname
|
|
}
|
|
regsub {/*$} $path_elem {/} path_elem
|
|
set pl [string length $path_elem]
|
|
if { [string equal -length $pl $path_elem $symbol] } {
|
|
set name [string range $symbol [expr {$pl}] end]
|
|
# When $path_elem is "C:/", string equal will match,
|
|
# but $path_elem should not be removed from $name if $name
|
|
# has more / for more directory levels.
|
|
if {$OS eq "Windows" && [regexp {^[A-Za-z]\:/$} $path_elem ] && [regexp {/} $name]} {
|
|
set name {}
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if {$name eq {} } {
|
|
# no known lib, so return full path
|
|
set name ${symbol}
|
|
if {[file dirname $name] eq $curr_dirname} {
|
|
# remove path if file is in pwd
|
|
set name [file tail $name]
|
|
}
|
|
|
|
}
|
|
|
|
return $name
|
|
}
|
|
|
|
# given a symbol reference 'sym' return its absolute path
|
|
# Example: % abs_sym_path devices/iopin.sch
|
|
# /home/schippes/share/xschem/xschem_library/devices/iopin.sym
|
|
proc abs_sym_path {fname {ext {} } {paths {}}} {
|
|
global pathlist OS
|
|
|
|
if { $paths eq {}} {set paths $pathlist}
|
|
set curr_dirname [pwd]
|
|
## empty: do nothing
|
|
if {$fname eq {} } return {}
|
|
## add extension for 1.0 file format compatibility
|
|
if { $ext ne {} } {
|
|
set fname [file rootname $fname]$ext
|
|
}
|
|
# web url: return as is
|
|
if { [regexp {^https?://} $fname]} {
|
|
return "$fname"
|
|
}
|
|
if {$OS eq "Windows"} {
|
|
## absolute path: return as is
|
|
if { [regexp {^[A-Za-z]\:/} $fname ] } {
|
|
return "$fname"
|
|
}
|
|
# network drive, return as is
|
|
if { [regexp {^/} $fname] } {
|
|
return "$fname"
|
|
}
|
|
} else {
|
|
## absolute path: return as is
|
|
if { [regexp {^/} $fname] } {
|
|
return "$fname"
|
|
}
|
|
}
|
|
## replace all runs of multiple / with single / in fname
|
|
regsub -all {/+} $fname {/} fname
|
|
## replace all '/./' with '/'
|
|
while {[regsub {/\./} $fname {/} fname]} {}
|
|
## transform a/b/../c to a/c or a/b/c/.. to a/b
|
|
while {[regsub {([^/]*\.*[^./]+[^/]*)/\.\./?} $fname {} fname] } {}
|
|
## remove trailing '/' or '/.'
|
|
while {[regsub {/\.?$} $fname {} fname]} {}
|
|
## 'found' set to 1 if fname begins with './' or '../'
|
|
set found 0
|
|
## remove any leading './'
|
|
while {[regsub {^\./} $fname {} fname]} {set found 1}
|
|
## if previous operation left fname empty set to '.'
|
|
if { $fname eq {} } { set fname . }
|
|
## if fname is just "." return $curr_dirname
|
|
if {[regexp {^\.$} $fname] } { return "$curr_dirname" }
|
|
set tmpdirname $curr_dirname
|
|
set tmpfname $fname
|
|
## if tmpfname begins with '../' remove this prefix and remove one path component from tmpdirname
|
|
while { [regsub {^\.\./} $tmpfname {} tmpfname] } {
|
|
set found 1
|
|
set tmpdirname [file dirname $tmpdirname]
|
|
}
|
|
## if tmpfname reduced to '..' return dirname of tmpdirname
|
|
if { $tmpfname eq {..}} { return "[file dirname $tmpdirname]" }
|
|
## if given file begins with './' or '../' and dir or file exists relative to curr_dirname
|
|
## just return it.
|
|
if {$found } {
|
|
set tmpfname "${tmpdirname}/$tmpfname"
|
|
if { [file exists "$tmpfname"] } { return "$tmpfname" }
|
|
## if file does not exists but directory does return anyway
|
|
if { [file exists [file dirname "$tmpfname"]] } { return "$tmpfname" }
|
|
}
|
|
## if fname is present in one of the paths paths get the absolute path
|
|
set name {}
|
|
foreach path_elem $paths {
|
|
if { ![string compare $path_elem .] && [info exist curr_dirname]} {
|
|
set path_elem $curr_dirname
|
|
}
|
|
regsub {/*$} $path_elem {/} path_elem
|
|
set fullpath "${path_elem}${fname}"
|
|
if { [file exists $fullpath] } {
|
|
set name $fullpath
|
|
break
|
|
}
|
|
}
|
|
## nothing found -> use current schematic directory
|
|
if {$name eq {} } {
|
|
set name "$curr_dirname/$fname"
|
|
}
|
|
return "$name"
|
|
}
|
|
|
|
proc add_ext {fname ext} {
|
|
return [file rootname $fname]$ext
|
|
}
|
|
|
|
proc swap_compare_schematics {} {
|
|
global compare_sch XSCHEM_TMP_DIR
|
|
set sch1 [xschem get schname]
|
|
set sch2 [xschem get sch_to_compare]
|
|
if { $sch1 eq $sch2} {
|
|
set msg "Swapping with same schematic name on disk. Suggest to cancel to avoid losing/overwriting data"
|
|
set answer [tk_messageBox -message $msg \
|
|
-icon warning -parent [xschem get topwindow] -type okcancel]
|
|
if { $answer ne {ok} } {return}
|
|
}
|
|
puts "swap_compare_schematics:\n sch1=$sch1\n sch2=$sch2"
|
|
if {$sch2 ne {}} {
|
|
xschem load -nofullzoom -gui $sch2
|
|
set current [xschem get schname]
|
|
# Use "file tail" to handle equality of
|
|
# https://raw.githubusercon...tb_reram.sch and /tmp/xschem_web/tb_reram.sch
|
|
if {( [regexp "^${XSCHEM_TMP_DIR}/xschem_web_" $current] && [file tail $current] eq [file tail $sch2] ) ||
|
|
( $current eq $sch2 )} { ;# user did not cancel loading
|
|
puts "swapping..."
|
|
if {$compare_sch} {
|
|
xschem compare_schematics $sch1
|
|
} else {
|
|
xschem set sch_to_compare $sch1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
proc input_line {txt {cmd {}} {preset {}} {w 12}} {
|
|
global wm_fix
|
|
set tctx::retval $preset
|
|
if { [winfo exists .dialog] } {return}
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Input number}
|
|
wm transient .dialog [xschem get topwindow]
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
# 20100203
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
wm geometry .dialog "+$X+$Y"
|
|
frame .dialog.f1
|
|
label .dialog.f1.l -text $txt
|
|
entry .dialog.f1.e -width $w
|
|
entry_replace_selection .dialog.f1.e
|
|
.dialog.f1.e insert 0 $preset
|
|
.dialog.f1.e selection range 0 end
|
|
|
|
pack .dialog.f1.l .dialog.f1.e -side left
|
|
frame .dialog.f2
|
|
|
|
button .dialog.f2.ok -text OK -command "
|
|
if { {$cmd} ne {} } {
|
|
eval $cmd \[.dialog.f1.e get\]
|
|
}
|
|
set tctx::retval \[.dialog.f1.e get\]
|
|
destroy .dialog
|
|
"
|
|
button .dialog.f2.cancel -text Cancel -command { set tctx::retval {}; destroy .dialog }
|
|
pack .dialog.f2.ok -anchor w -side left
|
|
pack .dialog.f2.cancel -anchor e
|
|
pack .dialog.f1
|
|
pack .dialog.f2 -expand yes -fill x
|
|
bind .dialog <Escape> {.dialog.f2.cancel invoke}
|
|
bind .dialog <Return> {.dialog.f2.ok invoke}
|
|
tkwait visibility .dialog
|
|
grab set .dialog
|
|
focus .dialog.f1.e
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $tctx::retval
|
|
}
|
|
|
|
proc launcher {launcher_var {launcher_program {} } } {
|
|
# env, XSCHEM_SHAREDIR and netlist_dir not used directly but useful in paths passed thru launcher_var
|
|
global launcher_default_program env XSCHEM_SHAREDIR netlist_dir OS
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
if { ![string compare $launcher_program {}] } { set launcher_program $launcher_default_program}
|
|
if {$OS == "Windows"} {
|
|
eval exec $launcher_program \"\" {[subst $launcher_var]}
|
|
} else {
|
|
eval exec [subst $launcher_program] {[subst $launcher_var]} &
|
|
}
|
|
}
|
|
|
|
proc reconfigure_layers_button { { topwin {} } } {
|
|
global dark_colorscheme
|
|
set c [xschem get rectcolor]
|
|
$topwin.menubar entryconfigure Layers -background [lindex $tctx::colors $c]
|
|
if { $dark_colorscheme == 1 && $c == 0} {
|
|
$topwin.menubar entryconfigure Layers -foreground white
|
|
} else {
|
|
$topwin.menubar entryconfigure Layers -foreground black
|
|
}
|
|
}
|
|
|
|
proc reconfigure_layers_menu { {topwin {} } } {
|
|
global dark_colorscheme
|
|
set j 0
|
|
foreach i $tctx::colors {
|
|
set ind_bg white
|
|
if { $j == [xschem get backlayer] } {
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg white
|
|
} else {
|
|
set layfg black
|
|
}
|
|
} else {
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg black
|
|
} else {
|
|
set layfg white
|
|
}
|
|
}
|
|
$topwin.menubar.layers entryconfigure $j -activebackground $i \
|
|
-background $i -foreground $layfg -activeforeground $layfg
|
|
incr j
|
|
}
|
|
reconfigure_layers_button $topwin
|
|
}
|
|
|
|
proc get_file_path {ff} {
|
|
global env OS
|
|
# Absolute path ? return as is.
|
|
# Linux Windows
|
|
if { [regexp {^/} $ff] || [regexp {^[a-zA-Z]:} $ff] } { return $ff }
|
|
if {$OS == "Windows"} {
|
|
set mylist [split $env(PATH) \;]
|
|
} else {
|
|
set mylist [split $env(PATH) :]
|
|
}
|
|
foreach i $mylist {
|
|
set ii $i/$ff
|
|
if { [file exists $ii]} {return $ii}
|
|
}
|
|
# nothing found, return $ff as is and hope for the best :-)
|
|
return $ff
|
|
}
|
|
|
|
#
|
|
# Balloon help system, from https://wiki.tcl-lang.org/page/balloon+help
|
|
#
|
|
proc balloon {w help {pos 1} {motion_kill 0} {delay 1000}} {
|
|
bind $w <Enter> "after $delay [list balloon_show %W [list $help] $pos]"
|
|
bind $w <Leave> "after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon"
|
|
if {$motion_kill} {
|
|
bind $w <Motion> "
|
|
if {\[winfo exists %W.balloon\]} {
|
|
after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon
|
|
}"
|
|
}
|
|
bind $w <FocusOut> "after cancel [list balloon_show %W [list $help] $pos]; destroy %W.balloon"
|
|
}
|
|
|
|
### pos:
|
|
## 0: set balloon close to mouse
|
|
## 1: set balloon below related widget
|
|
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 -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 -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]
|
|
set wmy [expr {[winfo rooty $w]+[winfo height $w]}]
|
|
} else {
|
|
set wmx [expr [winfo pointerx $w] + 20]
|
|
set wmy [winfo pointery $w]
|
|
}
|
|
wm geometry $top [winfo reqwidth $top.txt]x[winfo reqheight $top.txt]+$wmx+$wmy
|
|
raise $top
|
|
}
|
|
|
|
proc context_menu { } {
|
|
|
|
set tctx::retval 0
|
|
if {[info tclversion] >= 8.5} {
|
|
set font TkDefaultFont
|
|
# set font {Sans 8 bold}
|
|
} else {
|
|
set font fixed
|
|
}
|
|
set selection [expr {[xschem get lastsel] > 0}]
|
|
toplevel .ctxmenu
|
|
wm overrideredirect .ctxmenu 1
|
|
set x [expr {[winfo pointerx .ctxmenu] - 10}]
|
|
set y [expr {[winfo pointery .ctxmenu] - 10}]
|
|
if { !$selection} {
|
|
button .ctxmenu.b9 -text {Open most recent} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuRecent -compound left \
|
|
-font [subst $font] -command {set tctx::retval 9; destroy .ctxmenu}
|
|
}
|
|
button .ctxmenu.b10 -text {Edit attributes} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuEdit -compound left \
|
|
-font [subst $font] -command {set tctx::retval 10; destroy .ctxmenu}
|
|
button .ctxmenu.b11 -text {Edit attr in editor} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuEdit -compound left \
|
|
-font [subst $font] -command {set tctx::retval 11; destroy .ctxmenu}
|
|
if {$selection} {
|
|
button .ctxmenu.b12 -text {Descend schematic} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuDown -compound left \
|
|
-font [subst $font] -command {set tctx::retval 12; destroy .ctxmenu}
|
|
button .ctxmenu.b13 -text {Descend symbol} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuDownSym -compound left \
|
|
-font [subst $font] -command {set tctx::retval 13; destroy .ctxmenu}
|
|
button .ctxmenu.b18 -text {Delete selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuDelete -compound left \
|
|
-font [subst $font] -command {set tctx::retval 18; destroy .ctxmenu}
|
|
button .ctxmenu.b7 -text {Cut selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuCut -compound left \
|
|
-font [subst $font] -command {set tctx::retval 7; destroy .ctxmenu}
|
|
button .ctxmenu.b15 -text {Copy selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuCopy -compound left \
|
|
-font [subst $font] -command {set tctx::retval 15; destroy .ctxmenu}
|
|
button .ctxmenu.b16 -text {Move selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuMove -compound left \
|
|
-font [subst $font] -command {set tctx::retval 16; destroy .ctxmenu}
|
|
button .ctxmenu.b17 -text {Duplicate selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuDuplicate -compound left \
|
|
-font [subst $font] -command {set tctx::retval 17; destroy .ctxmenu}
|
|
button .ctxmenu.b22 -text {Rotate selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuRotate -compound left \
|
|
-font [subst $font] -command {xschem rotate; destroy .ctxmenu}
|
|
button .ctxmenu.b23 -text {Flip selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuFlip -compound left \
|
|
-font [subst $font] -command {xschem flip; destroy .ctxmenu}
|
|
button .ctxmenu.b24 -text {Rotate in-place sel.} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuRotate -compound left \
|
|
-font [subst $font] -command {xschem rotate_in_place; destroy .ctxmenu}
|
|
button .ctxmenu.b25 -text {Flip in-place sel.} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuFlip -compound left \
|
|
-font [subst $font] -command {xschem flip_in_place; destroy .ctxmenu}
|
|
}
|
|
if {!$selection} {
|
|
button .ctxmenu.b14 -text {Go to upper level} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuUp -compound left \
|
|
-font [subst $font] -command {set tctx::retval 14; destroy .ctxmenu}
|
|
button .ctxmenu.b1 -text {Insert symbol} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuSymbol -compound left \
|
|
-font [subst $font] -command {set tctx::retval 1; destroy .ctxmenu}
|
|
button .ctxmenu.b2 -text {Insert wire} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuWire -compound left \
|
|
-font [subst $font] -command {set tctx::retval 2; destroy .ctxmenu}
|
|
button .ctxmenu.b3 -text {Insert line} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuLine -compound left \
|
|
-font [subst $font] -command {set tctx::retval 3; destroy .ctxmenu}
|
|
button .ctxmenu.b4 -text {Insert box} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuBox -compound left \
|
|
-font [subst $font] -command {set tctx::retval 4; destroy .ctxmenu}
|
|
button .ctxmenu.b5 -text {Insert polygon} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuPoly -compound left \
|
|
-font [subst $font] -command {set tctx::retval 5; destroy .ctxmenu}
|
|
button .ctxmenu.b19 -text {Insert arc} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuArc -compound left \
|
|
-font [subst $font] -command {set tctx::retval 19; destroy .ctxmenu}
|
|
button .ctxmenu.b20 -text {Insert circle} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuCircle -compound left \
|
|
-font [subst $font] -command {set tctx::retval 20; destroy .ctxmenu}
|
|
button .ctxmenu.b6 -text {Insert text} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuText -compound left \
|
|
-font [subst $font] -command {set tctx::retval 6; destroy .ctxmenu}
|
|
button .ctxmenu.b8 -text {Paste clipboard} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuPaste -compound left \
|
|
-font [subst $font] -command {set tctx::retval 8; destroy .ctxmenu}
|
|
}
|
|
button .ctxmenu.b21 -text {Abort command} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuAbort -compound left \
|
|
-font [subst $font] -command {set tctx::retval 21; destroy .ctxmenu}
|
|
|
|
pack .ctxmenu.b21 -fill x -expand true
|
|
if {!$selection} {
|
|
pack .ctxmenu.b9 -fill x -expand true
|
|
}
|
|
pack .ctxmenu.b10 .ctxmenu.b11 -fill x -expand true
|
|
if {$selection} {
|
|
pack .ctxmenu.b12 .ctxmenu.b13 .ctxmenu.b18 -fill x -expand true
|
|
pack .ctxmenu.b22 .ctxmenu.b23 -fill x -expand true
|
|
pack .ctxmenu.b24 .ctxmenu.b25 -fill x -expand true
|
|
}
|
|
if {!$selection} {
|
|
pack .ctxmenu.b14 -fill x -expand true
|
|
pack .ctxmenu.b1 .ctxmenu.b2 .ctxmenu.b3 .ctxmenu.b4 .ctxmenu.b5 -fill x -expand true
|
|
pack .ctxmenu.b19 .ctxmenu.b20 .ctxmenu.b6 -fill x -expand true
|
|
}
|
|
if {$selection} {
|
|
pack .ctxmenu.b7 -fill x -expand true
|
|
pack .ctxmenu.b15 .ctxmenu.b16 .ctxmenu.b17 -fill x -expand true
|
|
}
|
|
if {!$selection} {
|
|
pack .ctxmenu.b8 -fill x -expand true
|
|
}
|
|
wm geometry .ctxmenu "+$x+$y"
|
|
update
|
|
# if window has been destroyed (by mouse pointer exiting) do nothing
|
|
if { ![winfo exists .ctxmenu] } { return 0 }
|
|
|
|
set wx [winfo width .ctxmenu]
|
|
set wy [winfo height .ctxmenu]
|
|
set sx [winfo screenwidth .]
|
|
set sy [winfo screenheight .]
|
|
if { $y + $wy > $sy } {
|
|
set y [expr {$y - ( $y + $wy - $sy )} ]
|
|
}
|
|
if { $x + $wx > $sx } {
|
|
set x [expr {$x - ( $x + $wx - $sx )} ]
|
|
}
|
|
wm geometry .ctxmenu "+$x+$y";# move away from screen edges
|
|
bind .ctxmenu <Leave> {if { {%W} eq {.ctxmenu} } {destroy .ctxmenu}}
|
|
tkwait window .ctxmenu
|
|
# when context menu is destroyed an EnterNotify event is generated in the
|
|
# main xschem window. We want to process this event before taking
|
|
# actions based on $tctx::retval.
|
|
update
|
|
return $tctx::retval
|
|
}
|
|
|
|
proc tab_ctx_cmd {tab_but what} {
|
|
global terminal editor netlist_dir OS has_x
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
# get win_path from tab name
|
|
set win_path [lindex [$tab_but cget -command] 3] ;# xschem new_schematic switch .x1.drw
|
|
set tablist [xschem tab_list]
|
|
set found 0
|
|
foreach {tabname filename} $tablist {
|
|
if {$win_path eq $tabname} {
|
|
set found 1
|
|
break
|
|
}
|
|
}
|
|
if {!$found} { set filename {}}
|
|
if { $filename ne {} } {
|
|
if {$what eq {dir}} {
|
|
if {$OS == "Windows" } {
|
|
set dir [file dirname $filename]
|
|
set command [list {*}[auto_execok start] {}]
|
|
exec {*}$command $dir &
|
|
} else {
|
|
execute 0 xdg-open [file dirname $filename]
|
|
}
|
|
} elseif {$what eq {copy}} {
|
|
clipboard clear
|
|
clipboard append $filename
|
|
} elseif {$what eq {term}} {
|
|
if {$OS == "Windows" } {
|
|
set save [pwd]
|
|
set dir [file dirname $filename]
|
|
cd $dir
|
|
set command [list {*}[auto_execok start] {}]
|
|
exec {*}$command &
|
|
cd $save
|
|
} else {
|
|
set save [pwd]
|
|
cd [file dirname $filename]
|
|
execute 0 $terminal
|
|
cd $save
|
|
}
|
|
} elseif {$what eq {simterm}} {
|
|
if {$OS == "Windows" } {
|
|
set save [pwd]
|
|
cd $netlist_dir
|
|
set command [list {*}[auto_execok start] {}]
|
|
exec {*}$command &
|
|
cd $save
|
|
} else {
|
|
set save [pwd]
|
|
cd $netlist_dir
|
|
execute 0 $terminal
|
|
cd $save
|
|
}
|
|
} elseif {$what eq {edit}} {
|
|
eval execute 0 $editor $filename
|
|
} elseif {$what eq {netlist}} {
|
|
set old [xschem get current_win_path]
|
|
set save [pwd]
|
|
xschem new_schematic switch $win_path {} 0 ;# no draw
|
|
if {[file exists $netlist_dir] && [file exists "$netlist_dir/[xschem get netlist_name fallback]"]} {
|
|
cd $netlist_dir
|
|
eval execute 0 $editor \"[xschem get netlist_name fallback]\"
|
|
cd $save
|
|
} else {
|
|
if {[info exists has_x]} {
|
|
alert_ {Netlist not existing, not yet generated} {} 0 0
|
|
} else {
|
|
puts {Netlist not existing, not yet generated}
|
|
}
|
|
}
|
|
xschem new_schematic switch $old {} 0 ;# no draw
|
|
} elseif {$what eq {save}} {
|
|
set old [xschem get current_win_path]
|
|
xschem new_schematic switch $win_path {} 0 ;# no draw
|
|
xschem save
|
|
xschem new_schematic switch $old {} 0 ;# no draw
|
|
} elseif {$what eq {close}} {
|
|
set old [xschem get current_win_path]
|
|
set ntabs [xschem get ntabs]
|
|
xschem new_schematic switch $win_path {} 0 ;# no draw
|
|
set remaining_tabs [xschem exit]
|
|
if { $old != $win_path || $remaining_tabs == $ntabs} {
|
|
# don't switch if we were on the tab that has been closed.
|
|
xschem new_schematic switch $old {} 1 ;# draw
|
|
}
|
|
} elseif {[regexp {^open } $what]} {
|
|
set counterpart [lindex $what 1]
|
|
set filetype [lindex $what 2]
|
|
|
|
# see if $counterpart already open, in this case switch to it
|
|
set found 0
|
|
foreach {tabname filename} $tablist {
|
|
if {$filename eq $counterpart} {
|
|
set found 1
|
|
break
|
|
}
|
|
}
|
|
if {$found} {
|
|
xschem new_schematic switch $tabname {} 1 ;# draw
|
|
} else {
|
|
xschem new_schematic create {1} $counterpart
|
|
if {$filetype ne {symbol} } { xschem set netlist_type symbol}
|
|
}
|
|
}
|
|
}
|
|
# puts $filename
|
|
}
|
|
|
|
proc tab_context_menu {tab_but} {
|
|
global search_schematic
|
|
|
|
# find filename associated with tab button
|
|
set win_path [lindex [$tab_but cget -command] 3] ;# xschem new_schematic switch .x1.drw
|
|
set tablist [xschem tab_list] ;# .drw filename0 .x1.drw filename1 ...
|
|
set found 0
|
|
foreach {tabname filename} $tablist {
|
|
if {$win_path eq $tabname} {
|
|
set found 1
|
|
break
|
|
}
|
|
}
|
|
if {!$found} { set filename {}}
|
|
set old [xschem get current_win_path]
|
|
xschem new_schematic switch $win_path {} 0 ;# no draw
|
|
set filetype [xschem get netlist_type] ;# symbol or spice or vhdl or tedax or verilog
|
|
xschem new_schematic switch $old {} 0 ;# no draw
|
|
|
|
if {$filetype ne {symbol}} {
|
|
if {$search_schematic == 1} {
|
|
set counterpart [abs_sym_path [xschem get current_name] {.sym}]
|
|
} else {
|
|
set counterpart [abs_sym_path $filename .sym]
|
|
}
|
|
set msg {Open symbol}
|
|
set img CtxmenuSymbol
|
|
} else {
|
|
if {$search_schematic == 1} {
|
|
set counterpart [abs_sym_path [xschem get current_name] {.sch}]
|
|
} else {
|
|
set counterpart [abs_sym_path $filename .sch]
|
|
}
|
|
set msg {Open schematic}
|
|
set img CtxmenuSchematic
|
|
}
|
|
# puts $counterpart
|
|
|
|
# puts $tab_but
|
|
set tctx::retval 0
|
|
if {[info tclversion] >= 8.5} {
|
|
set font {Sans 8 bold}
|
|
} else {
|
|
set font fixed
|
|
}
|
|
toplevel .ctxmenu
|
|
wm overrideredirect .ctxmenu 1
|
|
set x [expr {[winfo pointerx .ctxmenu] - 10}]
|
|
set y [expr {[winfo pointery .ctxmenu] - 10}]
|
|
button .ctxmenu.b0 -text {Tab menu} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-fg black -background white -state disabled -disabledforeground black -font [subst $font]
|
|
button .ctxmenu.b1 -text {Copy filename} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuCopy -compound left \
|
|
-font [subst $font] -command "set tctx::retval 1; tab_ctx_cmd $tab_but copy; destroy .ctxmenu"
|
|
button .ctxmenu.b2 -text {Open directory} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuOpendir -compound left \
|
|
-font [subst $font] -command "set tctx::retval 2; tab_ctx_cmd $tab_but dir; destroy .ctxmenu"
|
|
button .ctxmenu.b3 -text {Open circuit dir. term.} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuTerm -compound left \
|
|
-font [subst $font] -command "set tctx::retval 3; tab_ctx_cmd $tab_but term; destroy .ctxmenu"
|
|
button .ctxmenu.b4 -text {Open sim. dir. term.} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuTerm -compound left \
|
|
-font [subst $font] -command "set tctx::retval 4; tab_ctx_cmd $tab_but simterm; destroy .ctxmenu"
|
|
if {$counterpart ne {}} {
|
|
button .ctxmenu.b6 -text $msg -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image $img -compound left \
|
|
-font [subst $font] \
|
|
-command "set tctx::retval 6; tab_ctx_cmd $tab_but {open {$counterpart} $filetype} ; destroy .ctxmenu"
|
|
}
|
|
if {$filetype ne {symbol}} {
|
|
button .ctxmenu.b5 -text {Edit netlist} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuEdit -compound left \
|
|
-font [subst $font] -command "set tctx::retval 5; tab_ctx_cmd $tab_but netlist; destroy .ctxmenu"
|
|
}
|
|
button .ctxmenu.b7 -text {Save} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuSave -compound left \
|
|
-font [subst $font] -command "set tctx::retval 7; tab_ctx_cmd $tab_but save; destroy .ctxmenu"
|
|
button .ctxmenu.b8 -text {Close tab} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-bg {#d9d9d9} -fg black -activeforeground black -image CtxmenuDelete -compound left \
|
|
-font [subst $font] -command "set tctx::retval 8; tab_ctx_cmd $tab_but close; destroy .ctxmenu"
|
|
|
|
pack .ctxmenu.b0 -fill x -expand true
|
|
pack .ctxmenu.b1 -fill x -expand true
|
|
pack .ctxmenu.b2 -fill x -expand true
|
|
pack .ctxmenu.b3 -fill x -expand true
|
|
pack .ctxmenu.b4 -fill x -expand true
|
|
if {$counterpart ne {}} {
|
|
pack .ctxmenu.b6 -fill x -expand true
|
|
}
|
|
if {$filetype ne {symbol}} {
|
|
pack .ctxmenu.b5 -fill x -expand true
|
|
}
|
|
pack .ctxmenu.b7 -fill x -expand true
|
|
pack .ctxmenu.b8 -fill x -expand true
|
|
wm geometry .ctxmenu "+$x+$y"
|
|
update
|
|
# if window has been destroyed (by mouse pointer exiting) do nothing
|
|
if { ![winfo exists .ctxmenu] } { return 0 }
|
|
|
|
set wx [winfo width .ctxmenu]
|
|
set wy [winfo height .ctxmenu]
|
|
set sx [winfo screenwidth .]
|
|
set sy [winfo screenheight .]
|
|
if { $y + $wy > $sy } {
|
|
set y [expr {$y - ( $y + $wy - $sy )} ]
|
|
}
|
|
if { $x + $wx > $sx } {
|
|
set x [expr {$x - ( $x + $wx - $sx )} ]
|
|
}
|
|
wm geometry .ctxmenu "+$x+$y";# move away from screen edges
|
|
bind .ctxmenu <Leave> {if { {%W} eq {.ctxmenu} } {destroy .ctxmenu}}
|
|
tkwait window .ctxmenu
|
|
return $tctx::retval
|
|
}
|
|
|
|
#
|
|
# toolbar: Public variables that we allow to be overridden
|
|
# Code contributed by Neil Johnson (github: nejohnson)
|
|
#
|
|
proc setup_toolbar {} {
|
|
global toolbar_visible toolbar_horiz toolbar_list XSCHEM_SHAREDIR dark_gui_colorscheme
|
|
global toolbar_icon_zoom ctxmenu_icon_zoom
|
|
set_ne toolbar_visible 1
|
|
set_ne toolbar_horiz 1
|
|
set_ne toolbar_list {
|
|
FileOpen
|
|
FileSave
|
|
FileReload
|
|
---
|
|
EditUndo
|
|
EditRedo
|
|
EditCut
|
|
EditCopy
|
|
EditPaste
|
|
EditDelete
|
|
---
|
|
EditDuplicate
|
|
EditMove
|
|
---
|
|
EditPushSch
|
|
EditPushSym
|
|
EditPop
|
|
---
|
|
ViewRedraw
|
|
ViewToggleColors
|
|
---
|
|
ToolInsertSymbol
|
|
ToolInsertText
|
|
ToolInsertWire
|
|
ToolInsertLine
|
|
ToolInsertRect
|
|
ToolInsertPolygon
|
|
ToolInsertArc
|
|
ToolInsertCircle
|
|
---
|
|
ToolSearch
|
|
---
|
|
ToolJoinTrim
|
|
ToolBreak
|
|
}
|
|
#
|
|
# Pull in the toolbar graphics resources
|
|
#
|
|
source $XSCHEM_SHAREDIR/resources.tcl
|
|
#
|
|
# Separation bar counter
|
|
#
|
|
}
|
|
|
|
#
|
|
# Create a tool button which may be displayed
|
|
#
|
|
proc toolbar_add {name cmd { help "" } {topwin {} } } {
|
|
global dark_gui_colorscheme toolbar_icon_zoom
|
|
|
|
set toolbar_icon_size [expr {$toolbar_icon_zoom * 24}]
|
|
if { $dark_gui_colorscheme ==1} {
|
|
set bg black
|
|
} else {
|
|
set bg white
|
|
}
|
|
if {![winfo exists $topwin.toolbar]} {
|
|
frame $topwin.toolbar -relief raised -bd 0 -background $bg -takefocus 0
|
|
}
|
|
if { ![winfo exists $topwin.toolbar.b$name]} {
|
|
button $topwin.toolbar.b$name -image img$name -relief flat -bd 0 -takefocus 0 \
|
|
-background $bg -fg $bg -height $toolbar_icon_size -padx 0 -pady 0 -command $cmd
|
|
if { $help == "" } { balloon $topwin.toolbar.b$name $name } else { balloon $topwin.toolbar.b$name $help }
|
|
}
|
|
}
|
|
|
|
#
|
|
# Show the toolbar in horizontal or vertical position, parsing the toolbar list and
|
|
# adding any separators as needed.
|
|
#
|
|
proc toolbar_show { { topwin {} } } {
|
|
global toolbar_horiz toolbar_list toolbar_visible tabbed_interface
|
|
|
|
# puts "toolbar_show: $topwin"
|
|
set toolbar_visible 1
|
|
if {![winfo exists $topwin.toolbar]} {
|
|
frame $topwin.toolbar -relief raised -bd 0 -background white -takefocus 0
|
|
}
|
|
if {[winfo ismapped $topwin.toolbar]} {return}
|
|
if { $toolbar_horiz } {
|
|
if {$tabbed_interface} {
|
|
pack $topwin.toolbar -fill x -before $topwin.tabs
|
|
} else {
|
|
pack $topwin.toolbar -fill x -before $topwin.drw
|
|
}
|
|
} else {
|
|
pack $topwin.toolbar -side left -fill y -before $topwin.drw
|
|
}
|
|
set pos "top"
|
|
if { $toolbar_horiz } { set pos "left" }
|
|
set tlist [ winfo children $topwin.toolbar ]
|
|
set toolbar_sepn 0
|
|
foreach b $toolbar_list {
|
|
if { $b == "---" } {
|
|
if { $toolbar_horiz } {
|
|
frame $topwin.toolbar.sep$toolbar_sepn -background lightgrey -width 2 -takefocus 0
|
|
pack $topwin.toolbar.sep$toolbar_sepn -side $pos -padx 1 -pady 0 -fill y
|
|
} else {
|
|
frame $topwin.toolbar.sep$toolbar_sepn -background lightgrey -height 2 -takefocus 0
|
|
pack $topwin.toolbar.sep$toolbar_sepn -side $pos -padx 0 -pady 1 -fill x
|
|
}
|
|
incr toolbar_sepn
|
|
} else {
|
|
if { [ lsearch -exact $tlist "$topwin.toolbar.b$b" ] != -1 } {
|
|
pack $topwin.toolbar.b$b -side $pos
|
|
} else {
|
|
puts "Error: unknown toolbar item \"$b\""
|
|
}
|
|
}
|
|
}
|
|
set pos "bottom"
|
|
if { $toolbar_horiz } { set pos "right" }
|
|
foreach b { Waves Simulate Netlist } {
|
|
pack $topwin.toolbar.b$b -side $pos
|
|
}
|
|
}
|
|
|
|
#
|
|
# Hide the toolbar, unpack the buttons, and remove any separators
|
|
#
|
|
proc toolbar_hide { { topwin {} } } {
|
|
global toolbar_visible
|
|
set toolbar_visible 0
|
|
if {![winfo exists $topwin.toolbar]} {return}
|
|
if {![winfo ismapped $topwin.toolbar]} {return}
|
|
set tlist [ winfo children $topwin.toolbar ]
|
|
foreach b $tlist {
|
|
pack forget $b
|
|
if { [ string match "$topwin.toolbar.sep*" $b ] == 1 } {
|
|
destroy $b
|
|
}
|
|
}
|
|
pack forget $topwin.toolbar
|
|
set toolbar_visible 0
|
|
}
|
|
|
|
|
|
proc add_toolbuttons {{topwin {}}} {
|
|
# toolbar_add FileNew {xschem clear schematic} "New Schematic" $topwin
|
|
# toolbar_add FileNewSym {xschem clear symbol} "New Symbol" $topwin
|
|
toolbar_add FileOpen "xschem load" "Open File" $topwin
|
|
toolbar_add FileSave "xschem save" "Save File" $topwin
|
|
# toolbar_add FileMerge "xschem merge" "Merge File" $topwin
|
|
toolbar_add FileReload {
|
|
if {[alert_ "Are you sure you want to reload?" {} 0 1] == 1} {
|
|
xschem reload
|
|
}
|
|
} "Reload File" $topwin
|
|
toolbar_add EditUndo "xschem undo; xschem redraw" "Undo" $topwin
|
|
toolbar_add EditRedo "xschem redo; xschem redraw" "Redo" $topwin
|
|
toolbar_add EditCut "xschem cut" "Cut" $topwin
|
|
toolbar_add EditCopy "xschem copy" "Copy" $topwin
|
|
toolbar_add EditPaste "xschem paste" "Paste" $topwin
|
|
toolbar_add EditDelete "xschem delete" "Delete" $topwin
|
|
toolbar_add EditDuplicate "xschem copy_objects" "Duplicate objects" $topwin
|
|
toolbar_add EditMove "xschem move_objects" "Move objects" $topwin
|
|
toolbar_add EditPushSch "xschem descend" "Push schematic" $topwin
|
|
toolbar_add EditPushSym "xschem descend_symbol" "Push symbol" $topwin
|
|
toolbar_add EditPop "xschem go_back" "Pop" $topwin
|
|
toolbar_add ViewRedraw "xschem redraw" "Redraw" $topwin
|
|
# toolbar_add ViewZoomIn "xschem zoom_in" "Zoom In" $topwin
|
|
# toolbar_add ViewZoomOut "xschem zoom_out" "Zoom Out" $topwin
|
|
# toolbar_add ViewZoomBox "xschem zoom_box" "Zoom Box" $topwin
|
|
toolbar_add ViewToggleColors {
|
|
xschem toggle_colorscheme
|
|
} "Toggle Color Scheme" $topwin
|
|
toolbar_add ToolInsertSymbol "xschem place_symbol" "Insert Symbol" $topwin
|
|
toolbar_add ToolInsertText "xschem place_text" "Insert Text" $topwin
|
|
toolbar_add ToolInsertWire "xschem wire" "Insert Wire" $topwin
|
|
toolbar_add ToolInsertLine "xschem line" "Insert Line" $topwin
|
|
toolbar_add ToolInsertRect "xschem rect" "Insert Rectangle" $topwin
|
|
toolbar_add ToolInsertPolygon "xschem polygon" "Insert Polygon" $topwin
|
|
toolbar_add ToolInsertArc "xschem arc" "Insert Arc" $topwin
|
|
toolbar_add ToolInsertCircle "xschem circle" "Insert Circle" $topwin
|
|
toolbar_add ToolSearch property_search "Search" $topwin
|
|
toolbar_add ToolJoinTrim "xschem trim_wires" "Join/Trim Wires" $topwin
|
|
toolbar_add ToolBreak "xschem break_wires" "Break wires at selected\ninstance pin intersections" $topwin
|
|
toolbar_add Netlist { xschem netlist -erc } "Create netlist" $topwin
|
|
toolbar_add Simulate "simulate_from_button" "Run simulation" $topwin
|
|
toolbar_add Waves { waves } "View results" $topwin
|
|
}
|
|
|
|
proc pack_tabs {} {
|
|
global toolbar_horiz
|
|
if {[winfo exists .toolbar] && [winfo ismapped .toolbar] } {
|
|
if { $toolbar_horiz == 1 } {
|
|
pack .tabs -fill x -side top -after .toolbar
|
|
} else {
|
|
pack .tabs -fill x -side top -before .toolbar
|
|
}
|
|
} else {
|
|
pack .tabs -fill x -side top -before .drw
|
|
}
|
|
}
|
|
|
|
proc setup_tabbed_interface {} {
|
|
global tabbed_interface toolbar_horiz has_x
|
|
|
|
if { $tabbed_interface } {
|
|
if { [info exists has_x] && ![winfo exists .tabs] } {
|
|
frame .tabs -takefocus 0
|
|
button .tabs.x0 -padx 2 -pady 0 -anchor nw -takefocus 0 \
|
|
-text Main -command "xschem new_schematic switch .drw"
|
|
bind .tabs.x0 <ButtonPress-3> {tab_context_menu %W}
|
|
bind .tabs.x0 <ButtonPress-1> {swap_tabs %X %Y press}
|
|
bind .tabs.x0 <ButtonRelease-1> {swap_tabs %X %Y release}
|
|
button .tabs.add -padx 0 -pady 0 -takefocus 0 -text { + } \
|
|
-command "xschem new_schematic create"
|
|
pack .tabs.x0 .tabs.add -side left
|
|
balloon .tabs.add {Create a new tab}
|
|
pack_tabs
|
|
}
|
|
} else {
|
|
destroy .tabs
|
|
}
|
|
if {$tabbed_interface} {
|
|
set_tab_names
|
|
}
|
|
# update tabbed window close (X) function
|
|
if {$tabbed_interface} {
|
|
wm protocol . WM_DELETE_WINDOW {
|
|
xschem exit closewindow
|
|
}
|
|
# restore non tabbed window close function for main window
|
|
} else {
|
|
wm protocol . WM_DELETE_WINDOW {
|
|
set old [xschem get current_win_path]
|
|
save_ctx $old
|
|
restore_ctx .drw
|
|
housekeeping_ctx
|
|
xschem new_schematic switch .drw
|
|
xschem exit closewindow
|
|
# did not exit (user cancel) ... switch back
|
|
restore_ctx $old
|
|
housekeeping_ctx
|
|
xschem new_schematic switch $old
|
|
}
|
|
}
|
|
}
|
|
|
|
proc delete_tab {path} {
|
|
regsub {\.drw$} $path {} path
|
|
destroy .tabs$path
|
|
}
|
|
|
|
# button press on a tab, drag onto another tab, release button --> swap
|
|
proc swap_tabs {x y what} {
|
|
if {$what eq {press} } {
|
|
# puts "From: [winfo containing $x $y]"
|
|
set tctx::source_swap_tab [winfo containing $x $y]
|
|
# puts $tctx::source_swap_tab
|
|
set cond1 [regexp {\.tabs\.x} $tctx::source_swap_tab]
|
|
if {$cond1} {
|
|
button .tabs.mm -padx 2 -pady 0 -anchor nw -takefocus 0 -text [$tctx::source_swap_tab cget -text]
|
|
bind . <B1-Motion> {
|
|
place .tabs.mm -x [expr {[getmousex .tabs]-[winfo width .tabs.mm]/2 }] -y 0
|
|
# raise .tabs.mm
|
|
}
|
|
}
|
|
} else {
|
|
bind . <B1-Motion> {}
|
|
place forget .tabs.mm
|
|
destroy .tabs.mm
|
|
# puts "To: [winfo containing $x $y]"
|
|
set tctx::dest_swap_tab [winfo containing $x $y]
|
|
if {[info exists tctx::source_swap_tab] && [info exists tctx::dest_swap_tab]} {
|
|
set cond1 [regexp {\.tabs\.x} $tctx::source_swap_tab]
|
|
set cond2 [regexp {\.tabs\.x} $tctx::dest_swap_tab]
|
|
set cond3 [expr { $tctx::source_swap_tab ne $tctx::dest_swap_tab }]
|
|
if { $cond1 && $cond2 && $cond3} {
|
|
# puts "ok for swapping ctx"
|
|
set tablist [pack slaves .tabs]
|
|
set sourceidx [lsearch -exact $tablist $tctx::source_swap_tab]
|
|
set destidx [lsearch -exact $tablist $tctx::dest_swap_tab]
|
|
incr sourceidx
|
|
incr destidx
|
|
set following_source_tab [lindex $tablist $sourceidx]
|
|
set following_dest_tab [lindex $tablist $destidx]
|
|
# puts " $tablist --> $following_source_tab $following_dest_tab"
|
|
pack $tctx::source_swap_tab -side left -before $following_dest_tab
|
|
pack $tctx::dest_swap_tab -side left -before $following_source_tab
|
|
}
|
|
set tctx::source_swap_tab {}
|
|
set tctx::dest_swap_tab {}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc prev_tab {} {
|
|
global tabbed_interface
|
|
if { !$tabbed_interface} { return}
|
|
set currwin [xschem get current_win_path]
|
|
regsub {\.drw} $currwin {} tabname
|
|
if {$tabname eq {}} { set tabname .x0}
|
|
regsub {\.x} $tabname {} number
|
|
set found 0
|
|
set next_tab $number
|
|
set wrap_tab $number
|
|
set highest -10000000
|
|
set highest_all -10000000
|
|
set xcoord [winfo rootx .tabs$tabname]
|
|
for {set i 0} {$i < $tctx::max_new_windows} { incr i} {
|
|
if { $i == $number} { continue}
|
|
if { [winfo exists .tabs.x$i] } {
|
|
set tab_coord [winfo rootx .tabs.x$i]
|
|
if {$tab_coord < $xcoord && $tab_coord > $highest} {
|
|
set found 1
|
|
set next_tab $i
|
|
set highest $tab_coord
|
|
}
|
|
if {$tab_coord > $highest_all} {
|
|
set highest_all $tab_coord
|
|
set wrap_tab $i
|
|
}
|
|
}
|
|
}
|
|
if {$found == 0} { set next_tab $wrap_tab}
|
|
.tabs.x$next_tab invoke
|
|
}
|
|
|
|
proc next_tab {} {
|
|
global tabbed_interface
|
|
if { !$tabbed_interface} {return}
|
|
set currwin [xschem get current_win_path]
|
|
regsub {\.drw} $currwin {} tabname
|
|
if {$tabname eq {}} { set tabname .x0}
|
|
regsub {\.x} $tabname {} number
|
|
set found 0
|
|
set next_tab $number
|
|
set wrap_tab $number
|
|
set lowest 10000000
|
|
set lowest_all 10000000
|
|
set xcoord [winfo rootx .tabs$tabname]
|
|
for {set i 0} {$i < $tctx::max_new_windows} { incr i} {
|
|
if { $i == $number} { continue}
|
|
if { [winfo exists .tabs.x$i] } {
|
|
set tab_coord [winfo rootx .tabs.x$i]
|
|
if {$tab_coord > $xcoord && $tab_coord < $lowest} {
|
|
set found 1
|
|
set next_tab $i
|
|
set lowest $tab_coord
|
|
}
|
|
if {$tab_coord < $lowest_all} {
|
|
set lowest_all $tab_coord
|
|
set wrap_tab $i
|
|
}
|
|
}
|
|
}
|
|
if {$found == 0} { set next_tab $wrap_tab}
|
|
.tabs.x$next_tab invoke
|
|
}
|
|
|
|
proc set_tab_names {{mod {}}} {
|
|
global tabbed_interface has_x dark_gui_colorscheme
|
|
|
|
if {$dark_gui_colorscheme == 0} {
|
|
set tab_color Palegreen
|
|
} else {
|
|
set tab_color DarkGreen
|
|
}
|
|
|
|
if {[info exists has_x] && $tabbed_interface } {
|
|
set currwin [xschem get current_win_path]
|
|
set currsch [xschem get schname]
|
|
regsub {\.drw} $currwin {} tabname
|
|
if {$tabname eq {}} { set tabname .x0}
|
|
.tabs$tabname configure -text [file tail $currsch]$mod -background $tab_color
|
|
# puts ".tabs$tabname --> name=[file tail $currsch]$mod"
|
|
balloon .tabs$tabname $currsch
|
|
for { set i 0} { $i < $tctx::max_new_windows} { incr i} {
|
|
if { [winfo exists .tabs.x$i] && ($tabname ne ".x$i")} {
|
|
.tabs.x$i configure -background $tctx::tab_bg
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc store_geom {win filename} {
|
|
global tabbed_interface USER_CONF_DIR
|
|
|
|
# set geom [winfo width $win]x[winfo height $win]+[winfo rootx $win]+[winfo rooty $win]
|
|
set geom [wm geometry $win]
|
|
# puts "store_geom: geom=$geom"
|
|
set geom_file $USER_CONF_DIR/geometry
|
|
set geom_data {}
|
|
if {$win eq {.} || $tabbed_interface eq 0} {
|
|
if { [file exists $geom_file]} {
|
|
set fd [ open $geom_file]
|
|
while {[gets $fd line] >= 0} {
|
|
if { [llength $line] == 2} {
|
|
lassign $line f g
|
|
set d {0}
|
|
} elseif {[llength $line] == 3} {
|
|
lassign $line f g d
|
|
} else {
|
|
continue
|
|
}
|
|
set geom_array($f) [list $g $d]
|
|
}
|
|
close $fd
|
|
}
|
|
set geom_array($filename) [list $geom [clock seconds]]
|
|
|
|
set geom_data {}
|
|
foreach i [array names geom_array] {
|
|
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 {
|
|
if {$geom_data3 ne {}} {
|
|
if {$j % 3 == 0} {
|
|
append geom_data3 \n
|
|
} else {
|
|
append geom_data3 { }
|
|
}
|
|
}
|
|
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
|
|
}
|
|
}
|
|
|
|
proc set_geom {win {filename {}}} {
|
|
global USER_CONF_DIR initial_geometry fullscreen
|
|
set geom {}
|
|
if {$fullscreen ne 0} {return}
|
|
if {[info exists initial_geometry]} {
|
|
set geom $initial_geometry
|
|
} else {
|
|
# puts "set_geom: $win $filename"
|
|
set geom_file $USER_CONF_DIR/geometry
|
|
if { [file exists $geom_file]} {
|
|
|
|
set fd [open $geom_file]
|
|
while {[gets $fd line] >= 0} {
|
|
if { [llength $line] == 2} {
|
|
lassign $line f g
|
|
set d {}
|
|
} elseif {[llength $line] == 3} {
|
|
lassign $line f g d
|
|
} else {
|
|
continue
|
|
}
|
|
set geom_array($f) [list $g $d]
|
|
}
|
|
close $fd
|
|
|
|
if {$filename ne {} && [info exists geom_array($filename)]} {
|
|
set geom [lindex $geom_array($filename) 0]
|
|
}
|
|
}
|
|
set xmax [winfo screenwidth .]
|
|
set ymax [winfo screenheight .]
|
|
set n [scan $geom {%dx%d+%d+%d} x y dx dy]
|
|
if {$n == 4} {
|
|
# puts "xmax=$xmax, ymax=$ymax, x=$x, y=$y dx=$dx dy=$dy"
|
|
# off screen. do not use.
|
|
if { $dx > $xmax - 100 || $dy > $ymax - 100} {
|
|
set geom {}
|
|
}
|
|
}
|
|
}
|
|
if {$geom ne {}} {
|
|
# puts "set_geom: setting geometry of $win to $geom"
|
|
wm geometry $win $geom
|
|
}
|
|
update
|
|
}
|
|
|
|
proc get_lastclosed {} {
|
|
global USER_CONF_DIR
|
|
|
|
set geom_file $USER_CONF_DIR/geometry
|
|
set ret {}
|
|
if {[file exists $geom_file]} {
|
|
set fd [open $geom_file]
|
|
while {[gets $fd line] >= 0} {
|
|
set ret [lindex $line 0]
|
|
if {$ret eq [abs_sym_path untitled.sch] || $ret eq [abs_sym_path untitled.sym]} {
|
|
continue
|
|
}
|
|
if {[xschem check_loaded $ret] ne {}} {
|
|
continue
|
|
}
|
|
if { $ret ne {}} {
|
|
break
|
|
}
|
|
}
|
|
close $fd
|
|
}
|
|
return $ret
|
|
}
|
|
|
|
proc get_lastopened {} {
|
|
set f {}
|
|
foreach f $tctx::recentfile {
|
|
if {[xschem check_loaded $f] eq {}} {
|
|
break
|
|
}
|
|
}
|
|
return $f
|
|
}
|
|
|
|
proc quit_xschem { {force {}}} {
|
|
global tabbed_interface
|
|
|
|
xschem new_schematic destroy_all $force
|
|
xschem new_schematic switch .drw
|
|
set remaining [xschem exit closewindow $force]
|
|
return $remaining
|
|
}
|
|
|
|
proc raise_dialog {parent window_path } {
|
|
global file_dialog_loadfile component_browser_on_top
|
|
foreach i ".dialog .graphdialog .load" {
|
|
if {!$component_browser_on_top && [info exists file_dialog_loadfile ] &&
|
|
$file_dialog_loadfile == 2 && $i eq {.load} } {
|
|
continue
|
|
}
|
|
if {[winfo exists $i] && [winfo ismapped $i] && [winfo ismapped $parent] &&
|
|
[wm stackorder $i isbelow $parent ]} {
|
|
raise $i $window_path
|
|
}
|
|
}
|
|
}
|
|
|
|
proc set_old_tk_fonts {} {
|
|
if {[info tclversion] <= 8.4} {
|
|
set myfont {-*-helvetica-*-r-*-*-12-*-*-*-*-*-*-*}
|
|
set mymonofont fixed
|
|
option add *Button*font $myfont startupFile
|
|
option add *Menubutton*font $myfont startupFile
|
|
option add *Menu*font $myfont startupFile
|
|
option add *Listbox*font $myfont startupFile
|
|
option add *Entry*font $mymonofont startupFile
|
|
option add *Text*font $mymonofont startupFile
|
|
option add *Label*font $myfont startupFile
|
|
}
|
|
}
|
|
|
|
proc every {interval script} {
|
|
uplevel #0 $script
|
|
after $interval [list every $interval $script]
|
|
}
|
|
|
|
## tcl context switching global namespace
|
|
namespace eval tctx {
|
|
variable tctx
|
|
variable i
|
|
variable global_list
|
|
variable global_array_list
|
|
variable dialog_list
|
|
variable tab_bg
|
|
variable max_new_windows
|
|
variable source_swap_tab
|
|
variable dest_swap_tab
|
|
variable colors
|
|
}
|
|
|
|
## list of dialogs: when open do not perform context switching
|
|
## do not include .infotext as it is always open (in withdrawn mode)
|
|
set tctx::dialog_list { .ctxmenu .alert .sim .dialog .tclcmd .sl .dim }
|
|
|
|
proc no_open_dialogs {} {
|
|
set res 1
|
|
foreach tctx::i $tctx::dialog_list {
|
|
if { [winfo exists $tctx::i] } {
|
|
# puts "$tctx::i dialog open"
|
|
set res 0
|
|
}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
## list of globals to save/restore on context switching
|
|
## EXCEPTIONS, not to be saved/restored:
|
|
## "textwindow_wcounter" should be kept unique as it is the number of open textwindows
|
|
## "viewdata_wcounter" should be kept unique as it is the number of open viewdatas
|
|
## "measure_id" should be kept unique since we allow only one measure tooltip in graphs
|
|
## "tabbed_interface"
|
|
## "open_in_new_window"
|
|
## "case_insensitive" case insensitive symbol lookup (on case insensitive filesystems only!)
|
|
## "dark_colors_save"
|
|
## "light_colors_save" restore default colors
|
|
## "menu_debug_var" there is only a global debug mode
|
|
## "debug_var" there is only a global debug mode
|
|
## "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
|
|
## some file_chooser(...) vars
|
|
|
|
set tctx::global_list {
|
|
INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR PDK PDK_ROOT SKYWATER_MODELS
|
|
SKYWATER_STDCELLS XSCHEM_LIBRARY_PATH add_all_windows_drives auto_hilight
|
|
auto_hilight_graph_nodes autofocus_mainwindow autotrim_wires bespice_listen_port big_grid_points
|
|
bus_replacement_char cadence_compat cadgrid cadlayers cadsnap cairo_font_name cairo_font_scale
|
|
change_lw color_ps compare_sch constr_mv copy_cell crosshair_layer crosshair_size cursor_2_hook
|
|
custom_label_prefix custom_token dark_colors dark_colorscheme dark_gui_colorscheme
|
|
dim_bg dim_value disable_unique_names do_all_inst draw_crosshair draw_grid draw_grid_axes
|
|
draw_window edit_prop_pos edit_prop_size edit_symbol_prop_new_sel editprop_sympath
|
|
en_hilight_conn_inst enable_dim_bg enable_stretch env(PDK) env(PDK_ROOT)
|
|
enter_text_default_geometry erc_open_net_is_error erc_shorted_output_is_error
|
|
file_chooser(regex) file_chooser(action) file_chooser(dirs)
|
|
filetmp
|
|
fix_broken_tiled_fill flat_netlist fullscreen gaw_fd gaw_tcp_address graph_autoload graph_bus
|
|
graph_change_done graph_dialog_default_geometry graph_digital graph_legend graph_linewidth_mult
|
|
graph_logx graph_logy graph_private_cursor graph_rainbow graph_schname graph_sel_color
|
|
graph_sel_wave graph_selected graph_sort graph_unlocked graph_use_ctrl_key hide_empty_graphs
|
|
hide_symbols incr_hilight incremental_select infix_interface infowindow_text intuitive_interface
|
|
keep_symbols launcher_default_program light_colors line_width live_cursor2_backannotate
|
|
local_netlist_dir lvs_ignore lvs_netlist measure_text netlist_dir netlist_show netlist_type
|
|
new_file_browser_depth new_file_browser_ext
|
|
no_ask_save no_ask_simulate no_change_attrs nolist_libs noprint_libs only_probes
|
|
orthogonal_wiring path pathlist persistent_command preserve_unchanged_attrs prev_symbol ps_colors
|
|
ps_paper_size rainbow_colors rotated_text search_case search_exact
|
|
search_found search_schematic search_select search_value select_touch
|
|
show_hidden_texts show_infowindow show_infowindow_after_netlist simconf_default_geometry
|
|
simconf_vpos simulate_bg snap_cursor snap_cursor_size spiceprefix split_files svg_colors
|
|
svg_font_name sym_txt symbol symbol_width tabstop tclcmd_txt tclstop
|
|
tctx::colors tctx::delay_flag tctx::hsize tctx::recentfile
|
|
tctx::selected_mode tctx::old_selected_mode tctx::old_selected_tok tctx::selected_tok
|
|
tctx::rcode tctx::vsize tctx::tctx::retval tctx::retval_orig
|
|
tclcmd_default_geometry text_line_default_geometry text_replace_selection text_tabs_setting
|
|
textwindow_fileid textwindow_filename textwindow_w toolbar_horiz toolbar_list toolbar_visible
|
|
top_is_subckt transparent_svg undo_type unselect_partial_sel_wires uppercase_subckt
|
|
use_cursor_for_selection use_lab_wire use_label_prefix use_tclreadline user_wants_copy_cell
|
|
verilog_2001 verilog_bitblast
|
|
viewdata_fileid viewdata_filename viewdata_w xschem_libs xschem_listen_port zoom_full_center
|
|
}
|
|
|
|
## list of global arrays to save/restore on context switching
|
|
## will be saved as tctx::.drw_dircolor, tctx::.x1.drw_dircolor and so on
|
|
## EXCEPTIONS, not to be saved/restored:
|
|
## execute
|
|
set tctx::global_array_list {
|
|
replace_key dircolor sim enable_layer ngspice::ngspice_data
|
|
}
|
|
|
|
proc delete_ctx {context} {
|
|
global has_x
|
|
if {![info exists has_x]} {return}
|
|
set tctx::tctx $context
|
|
uplevel #0 {
|
|
# puts "delete_ctx $tctx::tctx"
|
|
array unset $tctx::tctx
|
|
foreach tctx::i $tctx::global_array_list {
|
|
regsub {::} $tctx::i {__} arr_name
|
|
if { [array exists ${tctx::tctx}_$arr_name] } {
|
|
array unset ${tctx::tctx}_$tctx::i
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc restore_ctx {context} {
|
|
global has_x
|
|
if {![info exists has_x]} {return}
|
|
# puts "restoring tcl context $context : semaphore=[xschem get semaphore]"
|
|
set tctx::tctx $context
|
|
array unset ::sim
|
|
uplevel #0 {
|
|
if { [ array exists tctx::$tctx::tctx ] } {
|
|
# puts "restore_ctx tctx::$tctx::tctx"
|
|
## Cleanup these vars to avoid side effects from previous ctx
|
|
unset -nocomplain gaw_fd
|
|
foreach tctx::i $tctx::global_list {
|
|
if { [info exists [subst tctx::$tctx::tctx]($tctx::i)] } {
|
|
# puts "restoring: $tctx::i"
|
|
set $tctx::i [set [subst tctx::$tctx::tctx]($tctx::i)]
|
|
}
|
|
}
|
|
}
|
|
foreach tctx::i $tctx::global_array_list {
|
|
unset -nocomplain $tctx::i
|
|
regsub {::} $tctx::i {__} arr_name
|
|
if { [array exists tctx::${tctx::tctx}_$arr_name] } {
|
|
array set $tctx::i [array get [subst tctx::${tctx::tctx}_$arr_name]]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# context is saved in array variable in tctx:: namespace.
|
|
# to get list of array names:
|
|
# array names tctx::.drw
|
|
# array names tctx::.x1.drw
|
|
# .....
|
|
proc save_ctx {context} {
|
|
global has_x
|
|
if {![info exists has_x]} {return}
|
|
# puts "saving tcl context $context : semaphore=[xschem get semaphore]"
|
|
set tctx::tctx $context
|
|
uplevel #0 {
|
|
# puts "save_ctx $tctx::tctx"
|
|
foreach tctx::i $tctx::global_list {
|
|
if { [info exists $tctx::i] } {
|
|
# puts "saving: $tctx::i"
|
|
set [subst tctx::$tctx::tctx]($tctx::i) [set $tctx::i]
|
|
}
|
|
}
|
|
foreach tctx::i $tctx::global_array_list {
|
|
if { [array exists $tctx::i] } {
|
|
regsub {::} $tctx::i {__} arr_name
|
|
array set [subst tctx::${tctx::tctx}_$arr_name] [array get $tctx::i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc housekeeping_ctx {} {
|
|
global has_x simulate_bg show_hidden_texts case_insensitive draw_window hide_symbols
|
|
global netlist_type intuitive_interface file_chooser
|
|
if {![info exists has_x]} {return}
|
|
uplevel #0 {
|
|
}
|
|
# puts "housekeeping_ctx, path: [xschem get current_win_path]"
|
|
xschem set hide_symbols $hide_symbols
|
|
xschem set draw_window $draw_window
|
|
xschem set intuitive_interface $intuitive_interface
|
|
xschem case_insensitive $case_insensitive
|
|
set_sim_netlist_waves_buttons
|
|
.statusbar.7 configure -text $netlist_type
|
|
}
|
|
|
|
# callback that resets simulate button color at end of simulation
|
|
proc set_simulate_button {top_path win_path} {
|
|
global simulate_bg execute has_x
|
|
|
|
if {![info exists has_x]} return
|
|
set current_win [xschem get current_win_path]
|
|
set simvar tctx::${win_path}_simulate
|
|
set sim_button $top_path.menubar
|
|
|
|
# puts "current_win=|$current_win|"
|
|
# puts "simvar=|$simvar|"
|
|
# puts "win_path=|$win_path|"
|
|
# puts "top_path=|$top_path|"
|
|
# puts "sim_button=|$sim_button|"
|
|
# puts "execute(exitcode,last)=|$execute(exitcode,last)|"
|
|
|
|
if {![info exists execute(exitcode,last)]} {
|
|
if { $current_win eq $win_path} {
|
|
catch {$sim_button entryconfigure Simulate -background $simulate_bg}
|
|
}
|
|
set $simvar $simulate_bg
|
|
} elseif { $execute(exitcode,last) == 0} {
|
|
if { $current_win eq $win_path} {
|
|
catch {$sim_button entryconfigure Simulate -background Green}
|
|
}
|
|
set $simvar Green
|
|
} else {
|
|
if { $current_win eq $win_path} {
|
|
catch {$sim_button entryconfigure Simulate -background red}
|
|
}
|
|
set $simvar red
|
|
}
|
|
}
|
|
|
|
|
|
# set simulate and netlist buttons on context change
|
|
proc set_sim_netlist_waves_buttons {} {
|
|
global simulate_bg execute has_x
|
|
|
|
if {![info exists has_x]} {return}
|
|
set win_path [xschem get current_win_path]
|
|
set top_path [xschem get top_path]
|
|
|
|
set netlist_var tctx::${win_path}_netlist
|
|
set sim_var tctx::${win_path}_simulate
|
|
set waves_var tctx::${win_path}_waves
|
|
if {![info exists $netlist_var] || [set $netlist_var] eq $simulate_bg} {
|
|
catch {$top_path.menubar entryconfigure Netlist -background $simulate_bg}
|
|
} else {
|
|
catch {$top_path.menubar entryconfigure Netlist -background [set $netlist_var]}
|
|
}
|
|
|
|
if {![info exists $sim_var] || [set $sim_var] eq $simulate_bg} {
|
|
catch {$top_path.menubar entryconfigure Simulate -background $simulate_bg}
|
|
} else {
|
|
catch {$top_path.menubar entryconfigure Simulate -background [set $sim_var]}
|
|
}
|
|
|
|
if {![info exists $waves_var] || [set $waves_var] eq $simulate_bg} {
|
|
catch {$top_path.menubar entryconfigure Waves -background $simulate_bg}
|
|
} else {
|
|
catch {$top_path.menubar entryconfigure Waves -background [set $waves_var]}
|
|
}
|
|
}
|
|
|
|
# these two routines are workarounds for broken remote desktop connection tools
|
|
# that do not correctly return mouse coordinates (%x, %y) on KeyPress events
|
|
proc getmousex {win} {
|
|
set x [winfo pointerx $win] ;# absolute mouse position in root window
|
|
set originx [winfo rootx $win] ;# absolute position of left window corner in root window
|
|
set relx [expr {$x - $originx}] ;# mouse position relative to window origin
|
|
return $relx
|
|
}
|
|
proc getmousey {win} {
|
|
set y [winfo pointery $win] ;# absolute mouse position in root window
|
|
set originy [winfo rooty $win] ;# absolute position of top window corner in root window
|
|
set rely [expr {$y - $originy}] ;# mouse position relative to window origin
|
|
return $rely
|
|
}
|
|
|
|
proc switch_window {parent topwin event window} {
|
|
# puts "$parent $topwin $event $window"
|
|
raise_dialog $parent $topwin
|
|
|
|
if { $parent eq {.}} {
|
|
if { $window eq $parent} {
|
|
xschem callback .drw $event 0 0 0 0 0 0
|
|
}
|
|
} else {
|
|
if {$window eq $parent} {
|
|
# send a fake event just to force context switching in callback()
|
|
xschem callback $parent.drw $event 0 0 0 0 0 0
|
|
}
|
|
}
|
|
}
|
|
proc show_bindkeys {} {
|
|
global dark_colorscheme dim_value dim_bg
|
|
if {[winfo exists .bk]} {wm deiconify .bk; raise .bk; return}
|
|
toplevel .bk -bg {}
|
|
# wm attributes .bk -fullscreen 1
|
|
wm geometry .bk [winfo width .]x[winfo height .]+[winfo rootx .]+[expr {[winfo rooty .]+30}]
|
|
|
|
# set save $dark_colorscheme
|
|
# set dark_colorscheme 0
|
|
# set dim_value 0.0
|
|
# set dim_bg 0.0
|
|
# xschem build_colors
|
|
|
|
xschem preview_window create .bk
|
|
xschem preview_window draw .bk [abs_sym_path bindkeys_cheatsheet.sym]
|
|
|
|
# set dark_colorscheme $save
|
|
# xschem build_colors
|
|
|
|
bind .bk <ButtonPress> {xschem preview_window destroy .bk}
|
|
bind .bk <KeyPress> {xschem preview_window destroy .bk}
|
|
bind .bk <Expose> {xschem preview_window draw .bk }
|
|
wm protocol .bk WM_DELETE_WINDOW {xschem preview_window destroy .bk}
|
|
}
|
|
|
|
proc set_bindings {topwin} {
|
|
global env has_x OS autofocus_mainwindow
|
|
###
|
|
### Tk event handling
|
|
###
|
|
|
|
if {($OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 ) && [info exists has_x]} {
|
|
set parent [winfo toplevel $topwin]
|
|
# puts "set_binding: topwin=$topwin, parent=$parent"
|
|
|
|
bind $parent <Expose> "if {{%W} eq {$parent}} {raise_dialog $parent $topwin}"
|
|
bind $parent <Visibility> [list raise_dialog $parent $topwin]
|
|
|
|
# Context switch.
|
|
bind $parent <FocusIn> "
|
|
switch_window $parent $topwin %T %W
|
|
# focus $topwin ;# propagate focus to canvas
|
|
"
|
|
|
|
bind $topwin <Leave> "
|
|
if {{%W} eq {$topwin}} {
|
|
xschem callback %W %T %x %y 0 0 0 %s
|
|
graph_show_measure stop
|
|
}
|
|
"
|
|
|
|
bind $topwin <Expose> "if {{%W} eq {$topwin}} {xschem callback %W %T %x %y 0 %w %h %s}"
|
|
|
|
# transform mousewheel events into button4/5 events
|
|
if {[info tclversion] > 8.7} {
|
|
bind $topwin <MouseWheel> {
|
|
if {%D > 0} {
|
|
xschem callback %W 4 %x %y 0 4 0 %s
|
|
} else {
|
|
xschem callback %W 4 %x %y 0 5 0 %s
|
|
}
|
|
}
|
|
}
|
|
|
|
bind $topwin <Double-Button-1> "xschem callback %W -3 %x %y 0 %b 0 %s"
|
|
bind $topwin <Double-Button-2> "xschem callback %W -3 %x %y 0 %b 0 %s"
|
|
bind $topwin <Double-Button-3> "xschem callback %W -3 %x %y 0 %b 0 %s"
|
|
bind $topwin <Configure> "xschem callback %W %T %x %y 0 %w %h 0"
|
|
if {$autofocus_mainwindow} {
|
|
bind $topwin <ButtonPress> "focus $topwin; xschem callback %W %T %x %y 0 %b 0 %s"
|
|
} else {
|
|
bind $topwin <ButtonPress> "focus $topwin; xschem callback %W %T %x %y 0 %b 0 %s"
|
|
}
|
|
bind $topwin <ButtonRelease> "xschem callback %W %T %x %y 0 %b 0 %s"
|
|
|
|
#### test: show keybindings
|
|
bind $topwin <KeyPress> "
|
|
if {{%K} eq {Escape}} { destroy .ctxmenu }
|
|
xschem callback %W %T %x %y %N 0 0 %s"
|
|
bind $topwin <KeyRelease> "xschem callback %W %T %x %y %N 0 0 %s"
|
|
if {$autofocus_mainwindow} {
|
|
bind $topwin <Motion> "focus $topwin; xschem callback %W %T %x %y 0 0 0 %s"
|
|
} else {
|
|
bind $topwin <Motion> "xschem callback %W %T %x %y 0 0 0 %s"
|
|
}
|
|
bind $topwin <Enter> "
|
|
if {{%W} eq {$topwin}} {
|
|
if {\[winfo exists .ins\]} {
|
|
set file_chooser(enter) 1 ;# so first time mouse enters file chooser current file will be shown
|
|
}
|
|
destroy .ctxmenu
|
|
if {\$autofocus_mainwindow} {focus $topwin}
|
|
xschem callback %W %T %x %y 0 0 0 0
|
|
}
|
|
"
|
|
bind $topwin <Unmap> " wm withdraw .infotext; set show_infowindow 0 "
|
|
|
|
# on Windows Alt key mask is reported as 131072 (1<<17) so build masks manually with values passed from C code
|
|
if {$OS == "Windows" } {
|
|
bind $topwin <Mod4-KeyPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$Mod4Mask}]}
|
|
bind $topwin <Shift-Mod4-KeyPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$ShiftMask + $Mod4Mask}]}
|
|
bind $topwin <Control-Mod4-KeyPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$ControlMask + $Mod4Mask}]}
|
|
bind $topwin <Alt-Mod4-KeyPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$Mod1Mask + $Mod4Mask}]}
|
|
bind $topwin <Mod4-KeyPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$Mod4Mask}]}
|
|
bind $topwin <Alt-ButtonPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$Mod1Mask}]}
|
|
bind $topwin <Control-Alt-ButtonPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$ControlMask + $Mod1Mask}]}
|
|
bind $topwin <Shift-Alt-ButtonPress> {xschem callback %W %T %x %y 0 %b 0 [expr {$ShiftMask + $Mod1Mask}]}
|
|
bind $topwin <Alt-Motion> {xschem callback %W %T %x %y 0 0 0 [expr {$Mod1Mask+%s}]}
|
|
bind $topwin <Alt-KeyPress> {xschem callback %W %T %x %y %N 0 0 [expr {$Mod1Mask}]}
|
|
bind $topwin <Control-Alt-KeyPress> {xschem callback %W %T %x %y %N 0 0 [expr {$ControlMask + $Mod1Mask}]}
|
|
bind $topwin <Shift-Alt-KeyPress> {xschem callback %W %T %x %y %N 0 0 [expr {$ShiftMask + $Mod1Mask}]}
|
|
bind $topwin <Shift-Insert> {xschem callback %W %T %x %y %N 0 0 [expr {$ShiftMask}]}
|
|
bind $topwin <MouseWheel> { ;# transform MouseWheel into button 4/5 presses.
|
|
if {%D<0} {
|
|
xschem callback %W 4 %x %y 0 5 0 %s
|
|
} else {
|
|
xschem callback %W 4 %x %y 0 4 0 %s
|
|
}
|
|
}
|
|
}
|
|
|
|
if {$parent eq {.}} { set parent {}}
|
|
bind ${parent}.statusbar.5 <Leave> \
|
|
"focus ${parent}.drw; set cadgrid \[${parent}.statusbar.5 get\]; xschem set cadgrid \$cadgrid"
|
|
bind ${parent}.statusbar.3 <Leave> \
|
|
"focus ${parent}.drw; set cadsnap \[${parent}.statusbar.3 get\]; xschem set cadsnap \$cadsnap"
|
|
|
|
focus ${parent}.drw
|
|
}
|
|
|
|
}
|
|
|
|
## this function sets up all tk windows and binds X events. It is executed by xinit.c after completing
|
|
## all X initialization. This avoids race conditions.
|
|
## In previous flow xschem.tcl was setting up windows and events before X initialization was completed by xinit.c.
|
|
## this could lead to crashes on some (may be slow) systems due to Configure/Expose events being delivered
|
|
## before xschem being ready to handle them.
|
|
proc pack_widgets { { topwin {} } } {
|
|
global env has_x OS tabbed_interface toolbar_visible toolbar_horiz
|
|
# puts "pack_widgets: $topwin"
|
|
if {($OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 ) && [info exists has_x]} {
|
|
pack $topwin.statusbar.2 -side left
|
|
pack $topwin.statusbar.3 -side left
|
|
pack $topwin.statusbar.4 -side left
|
|
pack $topwin.statusbar.5 -side left
|
|
pack $topwin.statusbar.6 -side left
|
|
pack $topwin.statusbar.7 -side left
|
|
pack $topwin.statusbar.10 -side left
|
|
pack $topwin.statusbar.11 -side left
|
|
pack $topwin.statusbar.9 -side left
|
|
pack $topwin.statusbar.8 -side left
|
|
pack $topwin.statusbar.1 -side left -fill x
|
|
pack $topwin.statusbar -side bottom -fill x
|
|
pack $topwin.statusbar.12 -side left
|
|
pack $topwin.drw -side right -fill both -expand true
|
|
setup_tabbed_interface
|
|
if {$toolbar_visible} {toolbar_show $topwin}
|
|
|
|
}
|
|
if {$topwin ne {}} {
|
|
$topwin.menubar.view entryconfigure {Tabbed interface} -state disabled
|
|
}
|
|
}
|
|
|
|
# if undo_type == disk save undo to disk
|
|
# if undo_type == memory keep undo in memory
|
|
# In memory undo is faster but in case of crashes nothing can be recovered
|
|
# On disk undo is slower but can be used to recover state just before a crash
|
|
proc switch_undo {} {
|
|
global undo_type
|
|
if { $undo_type eq {memory} } {
|
|
set res [tk_messageBox -type yesno -parent [xschem get topwindow] \
|
|
-message {Ok to keep undo in memory? Undo will be reset.\
|
|
Memory undo is faster but in case of crashes nothing can be recovered.}]
|
|
if {$res eq {yes} } {
|
|
xschem undo_type $undo_type
|
|
} else {
|
|
set undo_type disk
|
|
}
|
|
} else { ;# disk
|
|
set res [tk_messageBox -type yesno -parent [xschem get topwindow] \
|
|
-message {Ok to save undo on disk? Undo will be reset.\
|
|
Disk undo is slower but in case of crashes previous state can be recovered.}]
|
|
if {$res eq {yes} } {
|
|
xschem undo_type $undo_type
|
|
} else {
|
|
set undo_type memory
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
proc select_raw {{parent {.}}} {
|
|
global has_x netlist_dir
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
set filename $netlist_dir/[file tail [file rootname [xschem get schname]]].raw
|
|
set types {
|
|
{{Raw Files} {.raw} }
|
|
{{All Files} * }
|
|
}
|
|
if {[info exists has_x]} {
|
|
set filename [tk_getOpenFile -title "Select file" -multiple 0 -initialdir $netlist_dir \
|
|
-parent $parent -initialfile [file tail $filename] -filetypes $types]
|
|
}
|
|
return $filename
|
|
}
|
|
|
|
proc load_raw {{type {}}} {
|
|
global netlist_dir has_x
|
|
|
|
regsub {/$} $netlist_dir {} netlist_dir
|
|
if { [xschem raw_query loaded] != -1} { ;# unload existing raw file(s)
|
|
xschem raw_clear
|
|
}
|
|
set filename [select_raw [xschem get topwindow]]
|
|
if {[file exists $filename]} {
|
|
if {$type ne {}} {
|
|
xschem raw_read $filename $type
|
|
} else {
|
|
xschem raw_read $filename
|
|
}
|
|
}
|
|
}
|
|
|
|
## menubuttons not used anymore, but keep this code if needed in the future...
|
|
## modified binding for button-1 clicks on menubuttons. Clicking on posted menu will unpost it
|
|
# proc tk::menubutton1 {w x y} {
|
|
# # puts $w
|
|
# # puts "--> [array get tk::Priv] "
|
|
# if {[winfo ismapped [$w cget -menu ]]} {
|
|
# MenuUnpost {}
|
|
# return
|
|
# }
|
|
# if {$tk::Priv(inMenubutton) ne ""} {
|
|
# tk::MbPost $tk::Priv(inMenubutton) $x $y
|
|
# }
|
|
# }
|
|
#
|
|
# bind Menubutton <Button-1> {tk::menubutton1 %W %X %Y}
|
|
|
|
proc build_widgets { {topwin {} } } {
|
|
global canvas_height canvas_width
|
|
global XSCHEM_SHAREDIR tabbed_interface simulate_bg OS sim
|
|
global dark_gui_colorscheme draw_crosshair grid_point_size
|
|
global 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 cadence_compat
|
|
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
|
|
if { $dark_gui_colorscheme} {
|
|
set selectcolor white
|
|
} else {
|
|
set selectcolor black
|
|
}
|
|
|
|
menu $topwin.menubar -tearoff 0 -borderwidth 0 -takefocus 0
|
|
|
|
$topwin.menubar add cascade -label "File" -menu $topwin.menubar.file
|
|
menu $topwin.menubar.file -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Edit" -menu $topwin.menubar.edit
|
|
menu $topwin.menubar.edit -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Options" -menu $topwin.menubar.option
|
|
menu $topwin.menubar.option -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "View" -menu $topwin.menubar.view
|
|
menu $topwin.menubar.view -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Properties" -menu $topwin.menubar.prop
|
|
menu $topwin.menubar.prop -tearoff 0 -takefocus 0
|
|
|
|
$topwin.menubar add cascade -label "Layers" -menu $topwin.menubar.layers
|
|
menu $topwin.menubar.layers -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Tools" -menu $topwin.menubar.tools
|
|
menu $topwin.menubar.tools -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Symbol" -menu $topwin.menubar.sym
|
|
menu $topwin.menubar.sym -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Highlight" -menu $topwin.menubar.hilight
|
|
menu $topwin.menubar.hilight -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Simulation" -menu $topwin.menubar.simulation
|
|
menu $topwin.menubar.simulation -tearoff 0 -takefocus 0
|
|
$topwin.menubar add cascade -label "Help" -menu $topwin.menubar.help
|
|
menu $topwin.menubar.help -tearoff 0 -takefocus 0
|
|
|
|
if {$topwin eq {}} {
|
|
. configure -menu .menubar
|
|
} else {
|
|
$topwin configure -menu $topwin.menubar
|
|
}
|
|
|
|
## menubuttons not used anymore, but keep code if needed in the future
|
|
## activate menus when hovering the mouse, even without button pressed
|
|
# bind Menubutton <Motion> { tk::MbMotion %W down %X %Y}
|
|
|
|
$topwin.menubar.help add command -label "Help" -command "textwindow \"${XSCHEM_SHAREDIR}/xschem.help\" ro" \
|
|
-accelerator {?}
|
|
$topwin.menubar.help add command -label "Keys" -command "textwindow \"${XSCHEM_SHAREDIR}/keys.help\" ro"
|
|
$topwin.menubar.help add command -label "Show Keybindings" -command "show_bindkeys"
|
|
$topwin.menubar.help add command -label "About XSCHEM" -command "about"
|
|
|
|
$topwin.menubar.file add command -label "Clear Schematic" -accelerator Ctrl+N\
|
|
-command {
|
|
xschem clear schematic
|
|
}
|
|
$topwin.menubar.file add command -label "Clear Symbol" -accelerator Ctrl+Shift+N \
|
|
-command {
|
|
xschem clear symbol
|
|
}
|
|
$topwin.menubar.file add command -label "Component browser" -accelerator {Shift-Ins, Ctrl-I} \
|
|
-command {
|
|
if {$new_file_browser} {
|
|
file_chooser
|
|
} else {
|
|
load_file_dialog {Insert symbol} *.sym INITIALINSTDIR 2
|
|
}
|
|
}
|
|
$topwin.menubar.file add command -label "Open" -command "xschem load" -accelerator {Ctrl+O}
|
|
$topwin.menubar.file add command -label "Open in new window" -command "xschem load_new_window" \
|
|
-accelerator {Alt+O}
|
|
$topwin.menubar.file add command -label "Open last closed" \
|
|
-command {xschem load -gui -lastclosed} -accelerator {Ctrl+Shift+T}
|
|
$topwin.menubar.file add command -label "Open most recent" \
|
|
-command {xschem load -gui -lastopened} -accelerator {Ctrl+Shift+O}
|
|
$topwin.menubar.file add cascade -label "Open recent" -menu $topwin.menubar.file.recent
|
|
menu $topwin.menubar.file.recent -tearoff 0 -takefocus 0
|
|
setup_recent_menu $topwin
|
|
$topwin.menubar.file add command -label {Create new window/tab} -command "xschem new_schematic create" \
|
|
-accelerator {Ctrl+T}
|
|
|
|
$topwin.menubar.file add command -label "Open selected schematic in new window" \
|
|
-command "open_sub_schematic" -accelerator Alt+E
|
|
# -command "xschem schematic_in_new_window" -accelerator Alt+E
|
|
$topwin.menubar.file add command -label "Open selected symbol in new window" \
|
|
-command "xschem symbol_in_new_window" -accelerator Alt+I
|
|
|
|
$topwin.menubar.file add command -label "Delete files" -command "xschem delete_files" -accelerator {Shift-D}
|
|
$topwin.menubar.file add command -label "Save" -command "xschem save" -accelerator {Ctrl+S}
|
|
$topwin.menubar.file add command -label "Merge" -command "xschem merge" -accelerator {B}
|
|
$topwin.menubar.file add command -label "Reload" -accelerator {Alt+S} \
|
|
-command {
|
|
if {[alert_ "Are you sure you want to reload?" {} 0 1] == 1} {
|
|
xschem reload
|
|
}
|
|
}
|
|
$topwin.menubar.file add command -label "Save as" -command "xschem saveas" -accelerator {Ctrl+Shift+S}
|
|
$topwin.menubar.file add command -label "Save as symbol" \
|
|
-command "xschem saveas {} symbol" -accelerator {Ctrl+Alt+S}
|
|
# added svg, png 20171022
|
|
$topwin.menubar.file add cascade -label "Image export" -menu $topwin.menubar.file.im_exp
|
|
menu $topwin.menubar.file.im_exp -tearoff 0 -takefocus 0
|
|
$topwin.menubar.file.im_exp add command -label "EPS Selection Export" -command "xschem print eps"
|
|
$topwin.menubar.file.im_exp add command -label "PDF/PS Export" -command "xschem print pdf" -accelerator {*}
|
|
$topwin.menubar.file.im_exp add command -label "PDF/PS Export Full" -command "xschem print pdf_full"
|
|
$topwin.menubar.file.im_exp add command -label "Hierarchical PDF/PS Export" -command "xschem hier_psprint"
|
|
$topwin.menubar.file.im_exp add command -label "PNG Export" -command "xschem print png" -accelerator {Ctrl+*}
|
|
$topwin.menubar.file.im_exp add command -label "SVG Export" -command "xschem print svg" -accelerator {Alt+*}
|
|
|
|
|
|
$topwin.menubar.file add separator
|
|
$topwin.menubar.file add command -label "Start new Xschem process" -accelerator {X} -command {
|
|
xschem new_process
|
|
}
|
|
$topwin.menubar.file add command -label "Close schematic" -accelerator {Ctrl+W} -command {
|
|
xschem exit
|
|
}
|
|
$topwin.menubar.file add command -label "Quit Xschem" -accelerator {Ctrl+Q} -command {
|
|
quit_xschem
|
|
}
|
|
$topwin.menubar.option add checkbutton -label "Color Postscript/SVG" -variable color_ps \
|
|
-selectcolor $selectcolor -command {
|
|
if { $color_ps==1 } {xschem set color_ps 1} else { xschem set color_ps 0}
|
|
}
|
|
$topwin.menubar.option add checkbutton -selectcolor $selectcolor \
|
|
-label "Transparent SVG background" -variable transparent_svg
|
|
$topwin.menubar.option add checkbutton -label "Debug mode" -variable menu_debug_var \
|
|
-selectcolor $selectcolor -command {
|
|
if { $menu_debug_var==1 } {xschem debug 1} else { xschem debug 0}
|
|
}
|
|
$topwin.menubar.option add checkbutton -selectcolor $selectcolor \
|
|
-label "Undo buffer on Disk" -variable undo_type \
|
|
-onvalue disk -offvalue memory -command {switch_undo}
|
|
$topwin.menubar.option add checkbutton -label "Enable stretch" -variable enable_stretch \
|
|
-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 orthogonal wiring" -variable orthogonal_wiring \
|
|
-selectcolor $selectcolor -accelerator Shift-L
|
|
$topwin.menubar.option add checkbutton -label "Unsel. partial sel. wires after stretch move" \
|
|
-selectcolor $selectcolor -variable unselect_partial_sel_wires
|
|
|
|
$topwin.menubar.option add checkbutton -label "Auto Join/Trim Wires" -variable autotrim_wires \
|
|
-selectcolor $selectcolor -command {
|
|
if {$autotrim_wires == 1} {
|
|
xschem trim_wires
|
|
xschem redraw
|
|
}
|
|
}
|
|
$topwin.menubar.option add checkbutton -selectcolor $selectcolor \
|
|
-label "Persistent wire/line place command" -variable persistent_command
|
|
$topwin.menubar.option add checkbutton -label "Intuitive Click & Drag interface" \
|
|
-variable intuitive_interface -selectcolor $selectcolor \
|
|
-command {xschem set intuitive_interface $intuitive_interface}
|
|
|
|
$topwin.menubar.option add cascade -label "Crosshair" \
|
|
-menu $topwin.menubar.option.crosshair
|
|
menu $topwin.menubar.option.crosshair -tearoff 0 -takefocus 0
|
|
|
|
$topwin.menubar.option.crosshair add checkbutton -label "Draw snap cursor" \
|
|
-variable snap_cursor -selectcolor $selectcolor -accelerator {Alt-Z}
|
|
$topwin.menubar.option.crosshair add checkbutton -label "Draw crosshair" \
|
|
-variable draw_crosshair -selectcolor $selectcolor -accelerator {Alt-X}
|
|
$topwin.menubar.option.crosshair add command -label "Crosshair size" \
|
|
-command {
|
|
input_line "Enter crosshair size (int, 0 = full screen width):" \
|
|
"set crosshair_size" $crosshair_size
|
|
}
|
|
$topwin.menubar.option add command -label "Replace \[ and \] for buses in SPICE netlist" \
|
|
-command {
|
|
input_line "Enter two characters to replace default bus \[\] delimiters:" "set bus_replacement_char"
|
|
}
|
|
$topwin.menubar.option add checkbutton \
|
|
-selectcolor $selectcolor -label "Group bus slices in Verilog instances" -variable verilog_bitblast
|
|
$topwin.menubar.option add checkbutton -label "Draw grid" -variable draw_grid \
|
|
-selectcolor $selectcolor -accelerator {%} \
|
|
-command {
|
|
xschem redraw
|
|
}
|
|
$topwin.menubar.option add command -label "Half Snap Threshold" -accelerator G -command {
|
|
xschem set cadsnap [expr {$cadsnap / 2.0} ]
|
|
}
|
|
$topwin.menubar.option add command -label "Double Snap Threshold" -accelerator Shift-G -command {
|
|
xschem set cadsnap [expr {$cadsnap * 2.0} ]
|
|
}
|
|
$topwin.menubar.option add checkbutton -label "Variable grid point size" -variable big_grid_points \
|
|
-selectcolor $selectcolor -command { xschem redraw }
|
|
$topwin.menubar.option add separator
|
|
|
|
$topwin.menubar.option add checkbutton -label "No XCopyArea drawing model" -variable draw_window \
|
|
-selectcolor $selectcolor -accelerator {Ctrl+$} \
|
|
-command {
|
|
if { $draw_window == 1} { xschem set draw_window 1} else { xschem set draw_window 0}
|
|
}
|
|
|
|
$topwin.menubar.option add checkbutton -label "Fix for GPUs with broken tiled fill" \
|
|
-selectcolor $selectcolor -variable fix_broken_tiled_fill \
|
|
-command {
|
|
if { $fix_broken_tiled_fill == 1} {
|
|
xschem set fix_broken_tiled_fill 1
|
|
} else {
|
|
xschem set fix_broken_tiled_fill 0
|
|
}
|
|
xschem resetwin 1 1 1 0 0
|
|
xschem redraw
|
|
}
|
|
$topwin.menubar.option add checkbutton -label "Fix broken RDP mouse coordinates" \
|
|
-selectcolor $selectcolor -variable fix_mouse_coord -command {xschem set fix_mouse_coord $fix_mouse_coord}
|
|
|
|
$topwin.menubar.option add separator
|
|
|
|
$topwin.menubar.option add cascade -label "Netlist format / Symbol mode" \
|
|
-menu $topwin.menubar.option.netlist
|
|
menu $topwin.menubar.option.netlist -tearoff 0 -takefocus 0
|
|
|
|
$topwin.menubar.option.netlist add checkbutton -label "Flat netlist" -variable flat_netlist \
|
|
-selectcolor $selectcolor -accelerator : \
|
|
-command {
|
|
if { $flat_netlist==1 } {xschem set flat_netlist 1} else { xschem set flat_netlist 0}
|
|
}
|
|
$topwin.menubar.option.netlist add checkbutton -label "Split netlist" -variable split_files \
|
|
-selectcolor $selectcolor -accelerator {}
|
|
$topwin.menubar.option.netlist add radiobutton -label "Spectre netlist"\
|
|
-background grey60 -variable netlist_type -value spectre -accelerator {Ctrl+Shift+V} \
|
|
-selectcolor $selectcolor -command "xschem set netlist_type spectre; xschem redraw"
|
|
$topwin.menubar.option.netlist add radiobutton -label "Spice netlist"\
|
|
-background grey60 -variable netlist_type -value spice -accelerator {Ctrl+Shift+V} \
|
|
-selectcolor $selectcolor -command "xschem set netlist_type spice; xschem redraw"
|
|
$topwin.menubar.option.netlist add radiobutton -label "VHDL netlist"\
|
|
-background grey60 -variable netlist_type -value vhdl -accelerator {Ctrl+Shift+V} \
|
|
-selectcolor $selectcolor -command "xschem set netlist_type vhdl; xschem redraw"
|
|
$topwin.menubar.option.netlist add radiobutton -label "Verilog netlist"\
|
|
-background grey60 -variable netlist_type -value verilog -accelerator {Ctrl+Shift+V} \
|
|
-selectcolor $selectcolor -command "xschem set netlist_type verilog; xschem redraw"
|
|
$topwin.menubar.option.netlist add radiobutton -label "tEDAx netlist" \
|
|
-background grey60 -variable netlist_type -value tedax -accelerator {Ctrl+Shift+V} \
|
|
-selectcolor $selectcolor -command "xschem set netlist_type tedax; xschem redraw"
|
|
$topwin.menubar.option.netlist add radiobutton -label "Symbol global attrs" \
|
|
-background grey60 -variable netlist_type -value symbol -accelerator {Ctrl+Shift+V} \
|
|
-selectcolor $selectcolor -command "xschem set netlist_type symbol; xschem redraw"
|
|
$topwin.menubar.edit add command -label "Undo" -command "xschem undo; xschem redraw" -accelerator U
|
|
$topwin.menubar.edit add command -label "Redo" -command "xschem redo; xschem redraw" -accelerator {Shift+U}
|
|
$topwin.menubar.edit add command -label "Copy" -command "xschem copy" -accelerator Ctrl+C
|
|
$topwin.menubar.edit add command -label "Cut" -command "xschem cut" -accelerator Ctrl+X
|
|
$topwin.menubar.edit add command -label "Paste" -command "xschem paste" -accelerator Ctrl+V
|
|
$topwin.menubar.edit add command -label "Delete" -command "xschem delete" -accelerator Del
|
|
$topwin.menubar.edit add command -label "Select all" -command "xschem select_all" -accelerator Ctrl+A
|
|
$topwin.menubar.edit add command -label "Duplicate objects" -command "xschem copy_objects" -accelerator C
|
|
$topwin.menubar.edit add command -label "Move objects" -command "xschem move_objects" -accelerator M
|
|
$topwin.menubar.edit add command -label "Move objects stretching attached wires" \
|
|
-command "xschem move_objects stretch" -accelerator Control+M
|
|
$topwin.menubar.edit add command -label "Move objects adding wires to connected pins" \
|
|
-command "xschem move_objects kissing" -accelerator Shift+M
|
|
$topwin.menubar.edit add command -label "Horizontal Flip in place selected objects" -state normal \
|
|
-command {xschem flip_in_place} -accelerator {Alt-F}
|
|
$topwin.menubar.edit add command -label "Vertical Flip in place selected objects" -state normal \
|
|
-command {xschem flipv_in_place} -accelerator {Alt-V}
|
|
$topwin.menubar.edit add command -label "Rotate in place selected objects" -state normal \
|
|
-command {xschem rotate_in_place} -accelerator {Alt-R}
|
|
$topwin.menubar.edit add command -label "Vertical Flip selected objects" -state normal \
|
|
-command {xschem flipv} -accelerator {Shift-V}
|
|
$topwin.menubar.edit add command -label "Horizontal Flip selected objects" -state normal \
|
|
-command {xschem flip} -accelerator {Shift-F}
|
|
$topwin.menubar.edit add command -label "Rotate selected objects" -state normal \
|
|
-command {xschem rotate} -accelerator {Shift-R}
|
|
$topwin.menubar.edit add radiobutton -label "Unconstrained move" -variable constr_mv \
|
|
-selectcolor $selectcolor -background grey60 -value 0 -command {xschem set constr_mv 0}
|
|
$topwin.menubar.edit add radiobutton -label "Constrained Horizontal move" -variable constr_mv \
|
|
-selectcolor $selectcolor -background grey60 -value 1 -accelerator H -command {xschem set constr_mv 1}
|
|
$topwin.menubar.edit add radiobutton -label "Constrained Vertical move" -variable constr_mv \
|
|
-selectcolor $selectcolor -background grey60 -value 2 -accelerator V -command {xschem set constr_mv 2}
|
|
$topwin.menubar.edit add command -label "Push schematic" -command "xschem descend" -accelerator E
|
|
$topwin.menubar.edit add command -label "Push symbol" -command "xschem descend_symbol" -accelerator I
|
|
$topwin.menubar.edit add command -label "Pop" -command "xschem go_back" -accelerator Ctrl+E
|
|
|
|
$topwin.menubar add command -label { - } -state disabled
|
|
$topwin.menubar add command -label Netlist -background {#888888} \
|
|
-activebackground orange -command {xschem netlist -erc}
|
|
|
|
$topwin.menubar add command -label Simulate -background green -background {#888888} \
|
|
-activebackground orange -command {
|
|
simulate_from_button
|
|
}
|
|
|
|
$topwin.menubar add cascade -label "Waves" -background {#888888} \
|
|
-activebackground orange -menu $topwin.menubar.waves
|
|
menu $topwin.menubar.waves -tearoff 0 -takefocus 0
|
|
$topwin.menubar.waves add command -label {External viewer} -command {waves external}
|
|
$topwin.menubar.waves add separator
|
|
$topwin.menubar.waves add command -label Clear -command {xschem raw_clear}
|
|
$topwin.menubar.waves add separator
|
|
$topwin.menubar.waves add command -label {Load first analysis found} -command {waves {}}
|
|
$topwin.menubar.waves add command -label {Op Annotate} -command {
|
|
set tctx::retval [select_raw [xschem get topwindow]]
|
|
set show_hidden_texts 1
|
|
if {$tctx::retval ne {}} {
|
|
xschem annotate_op $tctx::retval
|
|
} else {
|
|
xschem annotate_op
|
|
}
|
|
}
|
|
$topwin.menubar.waves add command -label Op -command {waves op}
|
|
$topwin.menubar.waves add command -label Dc -command {waves dc}
|
|
$topwin.menubar.waves add command -label Ac -command {waves ac}
|
|
$topwin.menubar.waves add command -label Tran -command {waves tran}
|
|
$topwin.menubar.waves add command -label Noise -command {waves noise}
|
|
$topwin.menubar.waves add command -label Sp -command {waves ac}
|
|
$topwin.menubar.waves add command -label Spectrum -command {waves ac}
|
|
|
|
set simulate_bg [$topwin.menubar entrycget Simulate -background]
|
|
|
|
# create $topwin.menubar.layers.menu
|
|
create_layers_menu $topwin
|
|
$topwin.menubar.view add command -label "Redraw" -command "xschem redraw" -accelerator Esc
|
|
$topwin.menubar.view add command -label "Fullscreen" \
|
|
-accelerator "\\" -command "
|
|
if {\$fullscreen == 1} {set fullscreen 2} ;# avoid hiding menu in true fullscreen
|
|
xschem fullscreen $topwin.drw
|
|
"
|
|
$topwin.menubar.view add command -label "Zoom Full" -command "xschem zoom_full" -accelerator F
|
|
$topwin.menubar.view add command -label "Zoom In" -command "xschem zoom_in" -accelerator Shift+Z
|
|
$topwin.menubar.view add command -label "Zoom Out" -command "xschem zoom_out" -accelerator Ctrl+Z
|
|
$topwin.menubar.view add command -label "Zoom box" -command "xschem zoom_box" -accelerator Z
|
|
$topwin.menubar.view add command -label "Set snap value" \
|
|
-command {
|
|
input_line "Enter snap value (float):" "xschem set cadsnap" $cadsnap
|
|
}
|
|
$topwin.menubar.view add command -label "Set grid spacing" \
|
|
-command {
|
|
input_line "Enter grid spacing (float):" "xschem set cadgrid" $cadgrid
|
|
}
|
|
$topwin.menubar.view add command -label "Toggle colorscheme" -accelerator {Shift+O} -command {
|
|
xschem toggle_colorscheme
|
|
}
|
|
$topwin.menubar.view add command -label "Dim colors" -accelerator {} -command {
|
|
color_dim
|
|
}
|
|
$topwin.menubar.view add command -label "Change current layer color" -accelerator {} -command {
|
|
change_color
|
|
}
|
|
$topwin.menubar.view add command -label "Reset all colors to default" \
|
|
-accelerator {} -command {
|
|
reset_colors 1
|
|
}
|
|
|
|
$topwin.menubar.view add checkbutton -label "Toggle variable line width" -variable change_lw \
|
|
-selectcolor $selectcolor -accelerator {_}
|
|
$topwin.menubar.view add command -label "Set line width" -accelerator {Alt+-} \
|
|
-command {
|
|
input_line "Enter linewidth (float):" "xschem line_width"
|
|
}
|
|
$topwin.menubar.view add command -label "Set grid point size" \
|
|
-command {
|
|
input_line "Enter Grid point size (int or -1: $grid_point_size)" "set grid_point_size" $grid_point_size
|
|
}
|
|
$topwin.menubar.view add checkbutton -label "Tabbed interface" -variable tabbed_interface \
|
|
-selectcolor $selectcolor -command setup_tabbed_interface
|
|
|
|
$topwin.menubar.view add cascade -label "Show / Hide" \
|
|
-menu $topwin.menubar.view.show
|
|
menu $topwin.menubar.view.show -tearoff 0 -takefocus 0
|
|
|
|
$topwin.menubar.view.show add checkbutton -label "Show ERC Info window" \
|
|
-selectcolor $selectcolor -variable show_infowindow -command {
|
|
if { $show_infowindow != 0 } {wm deiconify .infotext
|
|
} else {wm withdraw .infotext}
|
|
}
|
|
$topwin.menubar.view.show add command -label "Visible layers" -accelerator {} \
|
|
-command {
|
|
select_layers
|
|
xschem redraw
|
|
}
|
|
$topwin.menubar.view.show add checkbutton -label "Symbol text" -variable sym_txt \
|
|
-selectcolor $selectcolor \
|
|
-accelerator {Ctrl+B} -command { xschem set sym_txt $sym_txt; xschem redraw }
|
|
$topwin.menubar.view.show add checkbutton -label "Show Toolbar" -variable toolbar_visible \
|
|
-selectcolor $selectcolor -command "
|
|
if { \$toolbar_visible } \" toolbar_show $topwin\" else \"toolbar_hide $topwin\"
|
|
"
|
|
$topwin.menubar.view.show add checkbutton -label "Horizontal Toolbar" -variable toolbar_horiz \
|
|
-selectcolor $selectcolor -command "
|
|
if { \$toolbar_visible } \" toolbar_hide $topwin; toolbar_show $topwin \"
|
|
"
|
|
$topwin.menubar.view.show add checkbutton -label "Show hidden texts" -variable show_hidden_texts \
|
|
-selectcolor $selectcolor -command {xschem update_all_sym_bboxes; xschem redraw}
|
|
$topwin.menubar.view.show add checkbutton -label "Draw grid axes" -variable draw_grid_axes \
|
|
-selectcolor $selectcolor -command {xschem redraw}
|
|
$topwin.menubar.prop add command -label "Edit" -command "xschem edit_prop" -accelerator Q
|
|
$topwin.menubar.prop add command -label "Edit with editor" -command "xschem edit_vi_prop" -accelerator Shift+Q
|
|
$topwin.menubar.prop add command -label "View" -command "xschem view_prop" -accelerator Ctrl+Shift+Q
|
|
$topwin.menubar.prop add command -label "Toggle *_ignore attribute on selected instances" \
|
|
-command "xschem toggle_ignore" -accelerator Shift+T
|
|
$topwin.menubar.prop add command -label "Change selected object insertion order" \
|
|
-command { xschem change_elem_order -1 } -accelerator Shift+S
|
|
$topwin.menubar.prop add command -label "Edit Header/License text" \
|
|
-command { update_schematic_header } -accelerator Shift+B
|
|
$topwin.menubar.prop add command -background red -label "Edit file (danger!)" \
|
|
-command "xschem edit_file" -accelerator Alt+Q
|
|
|
|
$topwin.menubar.sym add cascade -label "Show symbols" -menu $topwin.menubar.sym.sym
|
|
menu $topwin.menubar.sym.sym -tearoff 0 -takefocus 0
|
|
|
|
$topwin.menubar.sym.sym add radiobutton -label "Show symbol details" \
|
|
-selectcolor $selectcolor -background grey60 -variable hide_symbols -value 0 \
|
|
-command {xschem set hide_symbols $hide_symbols; xschem redraw} -accelerator Alt+B
|
|
$topwin.menubar.sym.sym add radiobutton -label "Show instance Bounding boxes for subcircuit symbols" \
|
|
-selectcolor $selectcolor -background grey60 -variable hide_symbols -value 1 \
|
|
-command {xschem set hide_symbols $hide_symbols; xschem redraw} -accelerator Alt+B
|
|
$topwin.menubar.sym.sym add radiobutton -label "Show instance Bounding boxes for all symbols" \
|
|
-selectcolor $selectcolor -background grey60 -variable hide_symbols -value 2 \
|
|
-command {xschem set hide_symbols $hide_symbols; xschem redraw} -accelerator Alt+B
|
|
|
|
$topwin.menubar.sym add command -label "Set symbol width" \
|
|
-command {
|
|
input_line "Enter Symbol width ($symbol_width)" "set symbol_width" $symbol_width
|
|
}
|
|
$topwin.menubar.sym add command -label "Make symbol from schematic" \
|
|
-command "xschem make_symbol" -accelerator A
|
|
$topwin.menubar.sym add command -label "Make schematic from symbol" \
|
|
-command "xschem make_sch" -accelerator Ctrl+L
|
|
$topwin.menubar.sym add command -label "Make schematic and symbol from selected components" \
|
|
-command "xschem make_sch_from_sel" -accelerator Ctrl+Shift+H
|
|
$topwin.menubar.sym add command -label "Attach net labels to component instance" \
|
|
-command "xschem attach_labels" -accelerator Shift+H
|
|
$topwin.menubar.sym add command -label "Create symbol pins from selected schematic pins" \
|
|
-command "schpins_to_sympins" -accelerator Alt+H
|
|
$topwin.menubar.sym add command -label "Place symbol pin" \
|
|
-command "xschem add_symbol_pin" -accelerator Alt+P
|
|
$topwin.menubar.sym add command -label "Place schematic input port" \
|
|
-command "xschem net_label 2" -accelerator Ctrl+P
|
|
$topwin.menubar.sym add command -label "Place schematic output port" \
|
|
-command "xschem net_label 3" -accelerator Ctrl+Shift+P
|
|
$topwin.menubar.sym add command -label "Place net pin label" \
|
|
-command "xschem net_label 1" -accelerator Alt+L
|
|
$topwin.menubar.sym add command -label "Place net wire label" \
|
|
-command "xschem net_label 0" -accelerator Alt+Shift+L
|
|
$topwin.menubar.sym add command -label "Change selected inst. texts to floaters" \
|
|
-command "xschem floaters_from_selected_inst"
|
|
$topwin.menubar.sym add command -label "Unselect attached floaters" \
|
|
-command "xschem unselect_attached_floaters"
|
|
|
|
|
|
$topwin.menubar.sym add cascade -label "List of nets" -menu $topwin.menubar.sym.list
|
|
menu $topwin.menubar.sym.list -tearoff 0 -takefocus 0
|
|
|
|
$topwin.menubar.sym.list add command -label "Print list of highlight nets" \
|
|
-command "xschem print_hilight_net 1" -accelerator J
|
|
$topwin.menubar.sym.list add command -label "Print list of highlight nets, with buses expanded" \
|
|
-command "xschem print_hilight_net 3" -accelerator Alt-Ctrl-J
|
|
$topwin.menubar.sym.list add command -label "Create labels from highlight nets" \
|
|
-command "xschem print_hilight_net 4" -accelerator Alt-J
|
|
$topwin.menubar.sym.list add command -label "Create labels from highlight nets with 'i' prefix" \
|
|
-command "xschem print_hilight_net 2" -accelerator Alt-Shift-J
|
|
$topwin.menubar.sym.list add command -label "Create pins from highlight nets" \
|
|
-command "xschem print_hilight_net 0" -accelerator Ctrl-J
|
|
|
|
$topwin.menubar.sym add checkbutton \
|
|
-selectcolor $selectcolor \
|
|
-label "Search all search-paths for schematic associated to symbol" -variable search_schematic
|
|
$topwin.menubar.sym add checkbutton -label "Allow duplicated instance names (refdes)" \
|
|
-selectcolor $selectcolor -variable disable_unique_names
|
|
$topwin.menubar.tools add command -label "Insert symbol" -command "xschem place_symbol" -accelerator {Ins, Shift-I}
|
|
$topwin.menubar.tools add command -label "Insert text" -command "xschem place_text" -accelerator T
|
|
$topwin.menubar.tools add command -label "Insert wire" -command "xschem wire" -accelerator W
|
|
$topwin.menubar.tools add command -label "Insert snap wire" -command "xschem snap_wire" -accelerator Shift+W
|
|
$topwin.menubar.tools add command -label "Insert line" -command "xschem line" -accelerator L
|
|
$topwin.menubar.tools add command -label "Insert rect" -command "xschem rect" -accelerator R
|
|
$topwin.menubar.tools add command -label "Insert polygon" -command "xschem polygon" -accelerator P
|
|
$topwin.menubar.tools add command -label "Insert arc" -command "xschem arc" -accelerator Shift+C
|
|
$topwin.menubar.tools add command -label "Insert circle" -command "xschem circle" -accelerator Ctrl+Shift+C
|
|
$topwin.menubar.tools add command -label "Insert JPG/PNG/SVG image" -command "xschem add_image"
|
|
$topwin.menubar.tools add command -label "Grab screen area" -command "xschem grabscreen" \
|
|
-accelerator {Print Scrn}
|
|
$topwin.menubar.tools add command -label "Search" -accelerator Ctrl+F -command property_search
|
|
$topwin.menubar.tools add command -label "Align to Grid" -accelerator Alt+U -command "xschem align"
|
|
$topwin.menubar.tools add command -label "Execute TCL command" -command "tclcmd" -accelerator {=}
|
|
$topwin.menubar.tools add command -label "Join/Trim wires" \
|
|
-command "xschem trim_wires" -accelerator {&}
|
|
$topwin.menubar.tools add command -label "Break wires at selected instance pins" \
|
|
-command "xschem break_wires" -accelerator {!}
|
|
$topwin.menubar.tools add command -label "Remove wires running through selected inst. pins" \
|
|
-command "xschem break_wires 1" -accelerator {Ctrl-!}
|
|
$topwin.menubar.tools add command -label "Break wires at mouse position" \
|
|
-command "xschem wire_cut noalign" -accelerator {Alt-Shift-Right Butt.}
|
|
$topwin.menubar.tools add command -label "Break wires at mouse position, align cut point" \
|
|
-command "xschem wire_cut" -accelerator {Alt-Right Butt.}
|
|
$topwin.menubar.tools add command -label "Select all connected wires/labels/pins" \
|
|
-accelerator {Shift-Right Butt.} \
|
|
-command { xschem connected_nets}
|
|
$topwin.menubar.tools add command -label "Select conn. wires, stop at junctions" \
|
|
-accelerator {Ctrl-Righ Butt.} -command { xschem connected_nets 1 }
|
|
|
|
$topwin.menubar.hilight add command \
|
|
-label {Set schematic to compare and compare with} \
|
|
-command "xschem compare_schematics; set compare_sch 1"
|
|
$topwin.menubar.hilight add command \
|
|
-label {Swap compare schematics} \
|
|
-command "swap_compare_schematics"
|
|
$topwin.menubar.hilight add checkbutton \
|
|
-selectcolor $selectcolor -label {Compare schematics} \
|
|
-command {
|
|
xschem unselect_all
|
|
xschem redraw } \
|
|
-variable compare_sch
|
|
$topwin.menubar.hilight add checkbutton -label "View only Probes" -variable only_probes \
|
|
-selectcolor $selectcolor -accelerator {5} \
|
|
-command { xschem only_probes }
|
|
$topwin.menubar.hilight add command \
|
|
-label {Highlight net-pin mismatches on sel. instances} \
|
|
-command "xschem net_pin_mismatch" \
|
|
-accelerator {Shift-X}
|
|
$topwin.menubar.hilight add command -label {Highlight duplicate instance names} \
|
|
-command "xschem check_unique_names 0" -accelerator {#}
|
|
$topwin.menubar.hilight add command -label {Rename duplicate instance names} \
|
|
-command "xschem check_unique_names 1" -accelerator {Ctrl+#}
|
|
$topwin.menubar.hilight add command -label {Select overlapped instances} \
|
|
-command "xschem warning_overlapped_symbols 1; xschem redraw" -accelerator {}
|
|
$topwin.menubar.hilight add command -label {Propagate Highlight selected net/pins} \
|
|
-command "xschem hilight drill" -accelerator {Ctrl+Shift+K}
|
|
$topwin.menubar.hilight add checkbutton \
|
|
-selectcolor $selectcolor -label "Increment Hilight Color" -variable incr_hilight
|
|
$topwin.menubar.hilight add command -label {Highlight selected net/pins} \
|
|
-command "xschem hilight" -accelerator K
|
|
$topwin.menubar.hilight add command -label {Send selected net/pins to Viewer} \
|
|
-command "xschem send_to_viewer" -accelerator Alt+G
|
|
$topwin.menubar.hilight add command -label {Select hilight nets / pins} \
|
|
-command "xschem select_hilight_net" \
|
|
-accelerator Alt+K
|
|
$topwin.menubar.hilight add command -label {Un-highlight all net/pins} \
|
|
-command "xschem unhilight_all" -accelerator Shift+K
|
|
$topwin.menubar.hilight add command -label {Un-highlight selected net/pins} \
|
|
-command "xschem unhilight" -accelerator Ctrl+K
|
|
# 20160413
|
|
$topwin.menubar.hilight add command -label {Show labels on unconnected instance pins} \
|
|
-command "xschem show_unconnected_pins"
|
|
$topwin.menubar.hilight add checkbutton \
|
|
-selectcolor $selectcolor -label {Auto-highlight net/pins} -variable auto_hilight
|
|
$topwin.menubar.hilight add checkbutton -label {Enable highlight connected instances} \
|
|
-selectcolor $selectcolor -variable en_hilight_conn_inst
|
|
|
|
$topwin.menubar.simulation add command -label "Set netlist Dir" \
|
|
-command {
|
|
set local_netlist_dir 0
|
|
set_netlist_dir 1
|
|
}
|
|
$topwin.menubar.simulation add command -label "Set top level netlist name" \
|
|
-command {
|
|
input_line {Set netlist file name} {xschem set netlist_name} [xschem get netlist_name] 40
|
|
}
|
|
$topwin.menubar.simulation add checkbutton -label "Show netlist after netlist command" \
|
|
-selectcolor $selectcolor -variable netlist_show -accelerator {Shift+A}
|
|
$topwin.menubar.simulation add checkbutton -label "Keep symbols when traversing hierarchy" \
|
|
-selectcolor $selectcolor -variable keep_symbols
|
|
$topwin.menubar.simulation add radiobutton -indicatoron 1 -label "Use netlist directory" \
|
|
-background grey60 -variable local_netlist_dir -value 0 \
|
|
-selectcolor $selectcolor -command {set_netlist_dir 1 }
|
|
$topwin.menubar.simulation add radiobutton -indicatoron 1 -label "Use 'simulation' dir in schematic dir" \
|
|
-background grey60 -variable local_netlist_dir -value 1 \
|
|
-selectcolor $selectcolor -command {set_netlist_dir 1 }
|
|
$topwin.menubar.simulation add radiobutton -indicatoron 1 -label "Use 'simulation/\[schname\]' dir in schematic dir" \
|
|
-background grey60 -variable local_netlist_dir -value 2 \
|
|
-selectcolor $selectcolor -command {set_netlist_dir 1 }
|
|
$topwin.menubar.simulation add command -label {Configure simulators and tools} -command {simconf}
|
|
if {$OS == {Windows}} {
|
|
$topwin.menubar.simulation add command -label {List running sub-processes} -state disabled
|
|
} else {
|
|
$topwin.menubar.simulation add command -label {List running sub-processes} -command {
|
|
list_running_cmds
|
|
}
|
|
}
|
|
$topwin.menubar.simulation add command -label {View last job data} -command {
|
|
if { [info exists execute(data,last)] } {
|
|
viewdata $execute(data,last)
|
|
}
|
|
}
|
|
$topwin.menubar.simulation add command -label {View last job errors} -command {
|
|
if { [info exists execute(error,last)] } {
|
|
viewdata $execute(error,last)
|
|
}
|
|
}
|
|
$topwin.menubar.simulation add command -label {Utile Stimuli Editor (GUI)} -command {
|
|
inutile [xschem get current_dirname]/stimuli.[file rootname [file tail [xschem get schname]]]
|
|
}
|
|
$topwin.menubar.simulation add command -label {Utile Stimuli Translate} -command {
|
|
inutile_translate [xschem get current_dirname]/stimuli.[file rootname [file tail [xschem get schname]]]
|
|
}
|
|
$topwin.menubar.simulation add command -label {Shell [simulation path]} -command {
|
|
if { [set_netlist_dir 0] ne "" } {
|
|
get_shell $netlist_dir
|
|
}
|
|
}
|
|
$topwin.menubar.simulation add command -label {Edit Netlist} \
|
|
-command {edit_netlist [xschem get netlist_name fallback]}
|
|
$topwin.menubar.simulation add command -label {Send highlighted nets to viewer} \
|
|
-command {xschem create_plot_cmd} -accelerator Ctrl+Shift+X
|
|
$topwin.menubar.simulation add command -label {Changelog from current hierarchy} -command {
|
|
viewdata [list_hierarchy]
|
|
}
|
|
$topwin.menubar.simulation add separator
|
|
|
|
|
|
$topwin.menubar.simulation add cascade -label "Graphs" -menu $topwin.menubar.simulation.graph
|
|
menu $topwin.menubar.simulation.graph -tearoff 0 -takefocus 0
|
|
$topwin.menubar.simulation.graph add checkbutton -label {Auto highlight plotted nets} \
|
|
-selectcolor $selectcolor -variable auto_hilight_graph_nodes
|
|
$topwin.menubar.simulation.graph add command -label {Add waveform graph} -command {xschem add_graph}
|
|
$topwin.menubar.simulation.graph add command -label {Add waveform reload launcher} -command {
|
|
xschem place_symbol [find_file_first launcher.sym] "name=h5\ndescr=\"load waves\"
|
|
tclcommand=\"xschem raw_read \$netlist_dir/[file tail [file rootname [xschem get current_name]]].raw tran\"
|
|
"
|
|
}
|
|
$topwin.menubar.simulation.graph add command -label "Annotate Operating Point into schematic" \
|
|
-command {
|
|
set tctx::retval [select_raw [xschem get topwindow]]
|
|
set show_hidden_texts 1
|
|
if {$tctx::retval ne {}} {
|
|
xschem annotate_op $tctx::retval
|
|
} else {
|
|
xschem annotate_op
|
|
}
|
|
}
|
|
$topwin.menubar.simulation.graph add checkbutton -label "Live annotate probes with 'b' cursor" \
|
|
-selectcolor $selectcolor -variable live_cursor2_backannotate
|
|
$topwin.menubar.simulation.graph add checkbutton -label "Hide graphs if no spice data loaded" \
|
|
-selectcolor $selectcolor -variable hide_empty_graphs -command {xschem redraw}
|
|
|
|
|
|
$topwin.menubar.simulation add cascade -label "LVS" -menu $topwin.menubar.simulation.lvs
|
|
menu $topwin.menubar.simulation.lvs -tearoff 0 -takefocus 0
|
|
$topwin.menubar.simulation.lvs add checkbutton -label "LVS netlist + Top level is a .subckt" \
|
|
-selectcolor $selectcolor -variable lvs_netlist
|
|
$topwin.menubar.simulation.lvs add checkbutton -label "Upper case .SUBCKT and .ENDS" \
|
|
-selectcolor $selectcolor -variable uppercase_subckt
|
|
$topwin.menubar.simulation.lvs add checkbutton -label "Top level is a .subckt" \
|
|
-selectcolor $selectcolor -variable top_is_subckt
|
|
|
|
$topwin.menubar.simulation.lvs add checkbutton -label "Set 'lvs_ignore' variable" \
|
|
-selectcolor $selectcolor \
|
|
-variable lvs_ignore -command {xschem rebuild_connectivity; xschem unhilight_all}
|
|
$topwin.menubar.simulation.lvs add checkbutton -label "Use 'spiceprefix' attribute" -variable spiceprefix \
|
|
-selectcolor $selectcolor -command {xschem redraw}
|
|
|
|
|
|
# used to check status of Simulate button later. This variable is constant, never changed
|
|
frame $topwin.drw -background {} -takefocus 1 -width $canvas_width -height $canvas_height
|
|
|
|
if { $topwin == {} } {set rootwin .} else { set rootwin $topwin}
|
|
wm title $rootwin "xschem - "
|
|
wm iconname $rootwin "xschem - "
|
|
$rootwin configure -background {}
|
|
if {$tabbed_interface} {
|
|
wm protocol $rootwin WM_DELETE_WINDOW {
|
|
xschem exit closewindow
|
|
}
|
|
} elseif { $rootwin == {.}} {
|
|
wm protocol $rootwin WM_DELETE_WINDOW {
|
|
set old [xschem get current_win_path]
|
|
save_ctx $old
|
|
restore_ctx .drw
|
|
housekeeping_ctx
|
|
xschem new_schematic switch .drw
|
|
xschem exit closewindow
|
|
# did not exit ... switch back
|
|
restore_ctx $old
|
|
housekeeping_ctx
|
|
xschem new_schematic switch $old
|
|
}
|
|
} else {
|
|
wm protocol $rootwin WM_DELETE_WINDOW "xschem new_schematic destroy $topwin.drw {}"
|
|
}
|
|
|
|
frame $topwin.statusbar -takefocus 0
|
|
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
|
|
|
|
label $topwin.statusbar.10 -activebackground green -text {} ;# DRAW WIRE or DRAW LINE or ...
|
|
label $topwin.statusbar.9 -textvariable enable_stretch
|
|
label $topwin.statusbar.8 -activebackground red -text {} ;# Caps lock, Num lock status
|
|
add_toolbuttons $topwin
|
|
}
|
|
|
|
proc set_initial_dirs {} {
|
|
global INITIALLOADDIR INITIALINSTDIR INITIALPROPDIR pathlist
|
|
foreach i $pathlist {
|
|
if { [file exists $i] } {
|
|
if {![info exists INITIALLOADDIR]} {set INITIALLOADDIR $i}
|
|
if {![info exists INITIALINSTDIR]} {set INITIALINSTDIR $i}
|
|
if {![info exists INITIALPROPDIR]} {set INITIALPROPDIR $i}
|
|
break
|
|
}
|
|
}
|
|
if {![info exists INITIALLOADDIR]} {set INITIALLOADDIR {}}
|
|
if {![info exists INITIALINSTDIR]} {set INITIALINSTDIR {}}
|
|
if {![info exists INITIALPROPDIR]} {set INITIALPROPDIR {}}
|
|
}
|
|
|
|
# called whenever XSCHEM_LUBRARY_PATH changes (see trace command at end)
|
|
proc trace_set_vars {varname idxname op} {
|
|
# puts trace_set_vars
|
|
if {$varname eq {XSCHEM_LIBRARY_PATH} } {
|
|
# puts stderr "executing set_paths after XSCHEM_LIBRARY_PATH change"
|
|
# puts stderr " $::XSCHEM_LIBRARY_PATH"
|
|
uplevel #0 set_paths
|
|
} elseif {$varname eq {new_file_browser_ext}} {
|
|
uplevel #0 {
|
|
if {![info exists file_chooser(old_new_file_browser_ext)] ||
|
|
$file_chooser(old_new_file_browser_ext) ne $new_file_browser_ext} {
|
|
set file_chooser(old_new_file_browser_ext) $new_file_browser_ext
|
|
if {[winfo exists .ins]} {
|
|
.ins.top3.upd invoke
|
|
}
|
|
}
|
|
}
|
|
} elseif {$varname eq {new_file_browser_depth}} {
|
|
uplevel #0 {
|
|
if {![info exists file_chooser(old_new_file_browser_depth)] ||
|
|
$file_chooser(old_new_file_browser_depth) ne $new_file_browser_depth} {
|
|
set file_chooser(old_new_file_browser_depth) $new_file_browser_depth
|
|
if {[winfo exists .ins]} {
|
|
.ins.top3.upd invoke
|
|
}
|
|
}
|
|
}
|
|
} elseif {$varname eq {file_chooser} && idxname eq {dirs}} {
|
|
uplevel #0 {
|
|
if {![info exists file_chooser(old_dirs)] ||
|
|
$file_chooser(old_dirs) ne $file_chooser(dirs)} {
|
|
set file_chooser(old_dirs) $file_chooser(dirs)
|
|
if {[winfo exists .ins]} {
|
|
.ins.top3.upd invoke
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc cleanup_paths {paths} {
|
|
global env
|
|
set path_l {}
|
|
foreach i $paths {
|
|
regsub {^~$} $i ${env(HOME)} i
|
|
regsub {^~/} $i ${env(HOME)}/ i
|
|
regsub -all {/+} $i {/} i
|
|
if {![string compare $i .]} {
|
|
# ...
|
|
} elseif { [regexp {^#} $i] } {
|
|
continue
|
|
} elseif { [regexp {\.\.\/} $i] } {
|
|
set i [file normalize $i]
|
|
}
|
|
if { [file exists $i] } {
|
|
lappend path_l $i
|
|
}
|
|
}
|
|
return $path_l
|
|
}
|
|
|
|
proc set_paths {} {
|
|
global XSCHEM_LIBRARY_PATH pathlist OS add_all_windows_drives
|
|
# puts stderr "caching search paths"
|
|
if { [info exists XSCHEM_LIBRARY_PATH] } {
|
|
if {$OS == "Windows"} {
|
|
set path_l_orig [split $XSCHEM_LIBRARY_PATH \;]
|
|
if {$add_all_windows_drives} {
|
|
set win_vol [file volumes]
|
|
foreach disk $win_vol {
|
|
lappend path_l_orig $disk
|
|
}
|
|
}
|
|
} else {
|
|
set path_l_orig [split $XSCHEM_LIBRARY_PATH :]
|
|
}
|
|
set pathlist [cleanup_paths $path_l_orig]
|
|
}
|
|
if {$pathlist eq {}} { set pathlist [pwd] }
|
|
|
|
set_initial_dirs
|
|
|
|
c_toolbar::clear
|
|
load_recent_file
|
|
}
|
|
|
|
proc print_help_and_exit {} {
|
|
global XSCHEM_SHAREDIR
|
|
if { [xschem get help ]} {
|
|
set fd [open "${XSCHEM_SHAREDIR}/xschem.help" r]
|
|
set helpfile [read $fd]
|
|
puts $helpfile
|
|
close $fd
|
|
}
|
|
}
|
|
|
|
proc set_missing_colors_to_black {} {
|
|
global enable_layer cadlayers svg_colors ps_colors light_colors dark_colors
|
|
## pad missing colors with black
|
|
for {set i 0} { $i<$cadlayers } { incr i} {
|
|
set_ne enable_layer($i) 1
|
|
foreach j { svg_colors ps_colors light_colors dark_colors } {
|
|
if { ![string compare [lindex [set $j] $i] {} ] } {
|
|
if { ![string compare $j {ps_colors} ] || ![string compare $j {svg_colors} ]} {
|
|
lappend $j {0x000000}
|
|
} else {
|
|
lappend $j {#000000}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foreach i {svg_colors ps_colors light_colors dark_colors} {
|
|
if { [llength [set $i]] > $cadlayers} {
|
|
set $i [lrange [set $i] 0 [expr {$cadlayers -1}]]
|
|
}
|
|
}
|
|
}
|
|
|
|
proc create_layers_menu { {topwin {} } } {
|
|
global dark_colorscheme
|
|
if { $dark_colorscheme == 1 } { set txt_color black} else { set txt_color white}
|
|
set j 0
|
|
foreach i $tctx::colors {
|
|
## 20121121
|
|
if { $j == [xschem get pinlayer] } {
|
|
set laylab [format %2d $j]-PIN
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get wirelayer] } {
|
|
set laylab [format %2d $j]-WIRE
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get textlayer] } { ;# 20161206
|
|
set laylab [format %2d $j]-TEXT
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get backlayer] } { ;# 20161206
|
|
set laylab [format %2d $j]-BG
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg white
|
|
} else {
|
|
set layfg black
|
|
}
|
|
} elseif { $j == [xschem get gridlayer] } { ;# 20161206
|
|
set laylab [format %2d $j]-GRID
|
|
set layfg $txt_color
|
|
} else {
|
|
set laylab "[format %2d $j] "
|
|
set layfg $txt_color
|
|
}
|
|
$topwin.menubar.layers add command -label $laylab -activeforeground $layfg \
|
|
-foreground $layfg -background $i -activebackground $i \
|
|
-command "xschem set rectcolor $j; reconfigure_layers_button $topwin"
|
|
if { [expr {$j%10}] == 0 } { $topwin.menubar.layers entryconfigure $j -columnbreak 1 }
|
|
incr j
|
|
}
|
|
}
|
|
|
|
proc set_replace_key_binding { {win_path {.drw}}} {
|
|
global replace_key
|
|
if {[array exists replace_key]} {
|
|
foreach i [array names replace_key] {
|
|
key_binding "$i" "$replace_key($i)" $win_path
|
|
}
|
|
}
|
|
}
|
|
|
|
proc source_user_tcl_files {} {
|
|
set subst_tcl_files [uplevel #0 {subst $tcl_files}]
|
|
foreach i $subst_tcl_files {
|
|
if {[catch "uplevel #0 {[list source $i]}" retval]} {
|
|
puts $retval
|
|
}
|
|
}
|
|
}
|
|
|
|
proc eval_user_startup_commands {} {
|
|
global user_startup_commands
|
|
if {[info exists user_startup_commands]} {
|
|
if {[catch {uplevel #0 $user_startup_commands} res]} {
|
|
puts "executing $user_startup_commands:\n\n$res"
|
|
}
|
|
}
|
|
}
|
|
|
|
proc eval_postinit_commands {} {
|
|
global postinit_commands
|
|
if {[info exists postinit_commands]} {
|
|
if {[catch {uplevel #0 $postinit_commands} res]} {
|
|
puts "executing $postinit_commands:\n\n$res"
|
|
}
|
|
}
|
|
}
|
|
|
|
proc eval_netlist_postprocess {} {
|
|
global netlist_postprocess
|
|
if {[info exists netlist_postprocess]} {
|
|
if {[catch {uplevel #0 $netlist_postprocess} res]} {
|
|
puts "executing $netlist_postprocess:\n\n$res"
|
|
}
|
|
}
|
|
}
|
|
|
|
proc eval_load_file_postprocess {} {
|
|
global load_file_postprocess
|
|
if {[info exists load_file_postprocess]} {
|
|
if {[catch {uplevel #0 $load_file_postprocess} res]} {
|
|
puts "executing $load_file_postprocess:\n\n$res"
|
|
}
|
|
}
|
|
}
|
|
|
|
proc setup_tcp_xschem { {port_number {}} } {
|
|
global xschem_listen_port xschem_server_getdata
|
|
|
|
# if a server socket was already set close it.
|
|
if {[info exists xschem_server_getdata(server)]} { close $xschem_server_getdata(server) }
|
|
if {$port_number ne {}} { set xschem_listen_port $port_number}
|
|
if { [info exists xschem_listen_port] && ($xschem_listen_port ne {}) } {
|
|
if {[catch {socket -server xschem_server $xschem_listen_port} err]} {
|
|
puts "setup_tcp_xschem: problems finding a free TCP port"
|
|
puts $err
|
|
return 0
|
|
} else {
|
|
set chan $err
|
|
set xschem_server_getdata(server) $chan
|
|
# this piece of code deals with automatic port number selection (port_number argument set to 0)
|
|
# tcl will automatically choose a free tcp port.
|
|
set assigned_port [lindex [fconfigure $chan -sockname] end]
|
|
set xschem_listen_port $assigned_port
|
|
return $assigned_port
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
proc setup_tcp_bespice {} {
|
|
global bespice_listen_port bespice_server_getdata
|
|
if { [info exists bespice_listen_port] && ($bespice_listen_port ne {}) } {
|
|
# We will attempt to open port $bespice_listen_port ... $bespice_listen_port + 1000 this should succeed ...
|
|
# We need to make this attempt as several instances of xschem / bespice might be running.
|
|
# Each of these instances needs it's own server listening on a dedicated port.
|
|
# The variable $bespice_listen_port is passed to bespice wave when the application is started
|
|
# in the function "set_sim_defaults()".
|
|
|
|
# if $bespice_listen_port is set to 0 TCL will automatically find a free port
|
|
if {[catch {socket -server bespice_server $bespice_listen_port} err]} {
|
|
# failed
|
|
puts "setup_tcp_bespice: problems finding a free TCP port"
|
|
puts $err
|
|
return 0
|
|
} else {
|
|
# succeded => set $bespice_listen_port and socket connection for communication
|
|
set chan $err
|
|
set bespice_server_getdata(server) $chan
|
|
set assigned_port [lindex [fconfigure $chan -sockname] end]
|
|
set bespice_listen_port $assigned_port
|
|
puts stderr "setup_tcp_bespice: success : listening to TCP port: $bespice_listen_port"
|
|
return 1
|
|
}
|
|
puts "setup_tcp_bespice: problems listening to TCP port: $bespice_listen_port ... $last_port"
|
|
puts $err
|
|
return 0
|
|
}
|
|
# bespice_listen_port not defined, nothing to do
|
|
# puts "setup_tcp_bespice: the functionallity was not set up as the variable \$bespice_listen_port"
|
|
# puts "hasn't been defined in your xschemrc file."
|
|
return 1
|
|
}
|
|
|
|
## this proc must be called for any created entry widgets
|
|
proc entry_replace_selection {w} {
|
|
global text_replace_selection OS
|
|
if {$text_replace_selection && $OS != "Windows"} {
|
|
bind $w <<Paste>> {if {[%W selection present]} {%W delete sel.first sel.last}}
|
|
}
|
|
}
|
|
|
|
###
|
|
### MAIN PROGRAM
|
|
###
|
|
|
|
# This variable is set in xinit.c
|
|
# set running_in_src_dir 0
|
|
# if {[file exists ./systemlib] && [file exists ./xschem.tcl] && [file exists ./xschem]} {
|
|
# set running_in_src_dir 1
|
|
# }
|
|
|
|
# tk_focusFollowsMouse
|
|
|
|
set_ne dark_colorscheme 1
|
|
set_ne dark_gui_colorscheme 0
|
|
if { [info exists has_x]} {
|
|
|
|
# set or get scaling factor
|
|
if { [info exists tk_scaling] } {
|
|
# set scaling
|
|
tk scaling $tk_scaling ;# useful for 4k displays (set bigger widgets)
|
|
} else {
|
|
# get scaling
|
|
set tk_scaling [tk scaling]
|
|
}
|
|
|
|
if { $dark_gui_colorscheme == 0 } { ;# normal GUI
|
|
option add *foreground black startupFile
|
|
option add *activeForeground black startupFile
|
|
option add *background {grey80} startupFile
|
|
option add *activeBackground {#f8f8f8} startupFile
|
|
option add *disabledForeground {grey50} startupFile
|
|
option add *disabledBackground {grey70} startupFile
|
|
option add *readonlyBackground {grey70} startupFile
|
|
option add *highlightBackground {white} startupFile
|
|
option add *highlightThickness 0 startupFile
|
|
option add *highlightColor {grey30} startupFile
|
|
option add *insertBackground {black} startupFile
|
|
option add *selectColor {white} startupFile ;# checkbuttons, radiobuttons
|
|
option add *selectForeground black
|
|
option add *selectBackground grey70
|
|
if { [info tclversion] > 8.4} {
|
|
ttk::style configure TCombobox -fieldbackground grey90
|
|
}
|
|
} else { ;# dark GUI colorscheme
|
|
option add *foreground white startupFile
|
|
option add *activeForeground white startupFile
|
|
option add *background {grey20} startupFile
|
|
option add *activeBackground {grey10} startupFile
|
|
option add *disabledForeground {grey50} startupFile
|
|
option add *disabledBackground {grey20} startupFile
|
|
option add *readonlyBackground {grey20} startupFile
|
|
option add *highlightBackground {black} startupFile
|
|
option add *highlightThickness 0 startupFile
|
|
option add *highlightColor {grey70} startupFile
|
|
option add *insertBackground {white} startupFile
|
|
option add *selectColor {grey10} startupFile ;# checkbuttons, radiobuttons
|
|
option add *selectForeground black
|
|
option add *selectBackground grey70
|
|
if { [info tclversion] > 8.4} {
|
|
ttk::style configure TCombobox -fieldbackground grey20
|
|
}
|
|
}
|
|
}
|
|
|
|
set OS [lindex $tcl_platform(os) 0]
|
|
set env(LC_ALL) C
|
|
# tcl variable XSCHEM_LIBRARY_PATH should already be set in xschemrc
|
|
set_ne add_all_windows_drives 1
|
|
set_paths
|
|
print_help_and_exit
|
|
set_ne text_replace_selection 1
|
|
if {$text_replace_selection && $OS != "Windows"} {
|
|
# deletes selected text when pasting in text widgets, courtesy Wolf-Dieter Busch
|
|
proc tk_textPaste w {
|
|
global tcl_platform
|
|
if {![catch {::tk::GetSelection $w CLIPBOARD} sel]} then {
|
|
set oldSeparator [$w cget -autoseparators]
|
|
if {$oldSeparator} then {
|
|
$w configure -autoseparators 0
|
|
$w edit separator
|
|
}
|
|
foreach {to from} [lreverse [$w tag ranges sel]] {
|
|
$w delete $from $to
|
|
}
|
|
$w insert insert $sel
|
|
if {$oldSeparator} then {
|
|
$w edit separator
|
|
$w configure -autoseparators 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
## allow to unpost menu entries when clicking a posted menu
|
|
|
|
if { [info exists has_x] && [info tclversion] >= 8.6 } {
|
|
bind Menu <Button> {
|
|
if { [%W cget -type] eq "menubar" && [info exists tk::Priv(menuActivated)]} {
|
|
%W activate none
|
|
} else {
|
|
%W activate @%x,%y
|
|
}
|
|
tk::MenuButtonDown %W
|
|
}
|
|
}
|
|
|
|
#####################################################################################
|
|
## Procedures to set the PRIMARY selection of selected listbox elements with listbox
|
|
## created with -exportselection 0. Courtesy Mark G. Saye
|
|
#####################################################################################
|
|
## use with: bind .l <<ListboxSelect>> [list listbox:select %W]
|
|
proc listbox:select {W} {
|
|
selection clear -displayof $W
|
|
selection own -command {} $W
|
|
selection handle -type UTF8_STRING $W [list listbox:handle $W]
|
|
selection handle $W [list listbox:handle $W]
|
|
}
|
|
|
|
proc listbox:handle {W offset maxChars} {
|
|
set list {}
|
|
foreach index [$W curselection] { lappend list [$W get $index] }
|
|
set text [join $list \n]
|
|
return [string range $text $offset [expr {$offset+$maxChars-1}]]
|
|
}
|
|
#####################################################################################
|
|
|
|
# focus the schematic window if mouse goes over it, even if a dialog box is displayed,
|
|
# without needing to click. This allows to move/zoom/pan the schematic while editing attributes.
|
|
set_ne autofocus_mainwindow 0
|
|
if {$OS == "Windows"} {
|
|
set_ne XSCHEM_TMP_DIR [xschem get temp_dir]
|
|
} else {
|
|
set_ne XSCHEM_TMP_DIR {/tmp}
|
|
}
|
|
|
|
# used in C code
|
|
|
|
if {[info exists tk_scaling]} {
|
|
set_ne canvas_width [expr {int(800. * $tk_scaling)}]
|
|
set_ne canvas_height [expr {int(500. * $tk_scaling)}]
|
|
} else {
|
|
set_ne canvas_width 1000
|
|
set_ne canvas_height 700
|
|
}
|
|
set_ne xschem_libs {}
|
|
set_ne noprint_libs {}
|
|
set_ne nolist_libs {}
|
|
set_ne debug_var 0
|
|
set_ne debug_tcleval 0 ;# debug tclpropeval2 (tcleval() in xschem attributes)
|
|
# used to activate debug from menu
|
|
set_ne menu_debug_var 0
|
|
set textwindow_wcounter 1
|
|
set viewdata_wcounter 1
|
|
set tctx::retval ""
|
|
set prev_symbol ""
|
|
set symbol ""
|
|
|
|
# 20100204 flag to enable fix for dialog box positioning, issues with some wm
|
|
set wm_fix 0
|
|
|
|
# 20171010
|
|
set tclcmd_txt {}
|
|
|
|
###
|
|
### user preferences: set default values
|
|
###
|
|
|
|
if { ![info exists dircolor] } {
|
|
set_ne dircolor(/share/xschem/) red
|
|
set_ne dircolor(/share/doc/xschem/) {#338844}
|
|
}
|
|
|
|
set_ne file_dialog_globfilter {*}
|
|
set_ne component_browser_on_top 1
|
|
## list of tcl procedures to load at end of xschem.tcl
|
|
set_ne tcl_files {}
|
|
set_ne download_url_helper {curl -f -s -O -J}
|
|
set_ne netlist_dir "$USER_CONF_DIR/simulations"
|
|
# this global exists only for netlist_type radiobuttons, don't use, use [xschem] subcommand to get/set values
|
|
# it is also used in xschemrc to set initial netlist type.
|
|
set_ne netlist_type spice
|
|
set_ne local_netlist_dir 0 ;# if set use <sch_dir>/simulation for netlist and sims
|
|
set_ne bus_replacement_char {} ;# use {<>} to replace [] with <> in bussed signals
|
|
set_ne lvs_netlist 0
|
|
set_ne top_is_subckt 0
|
|
set_ne uppercase_subckt 0
|
|
set_ne lvs_ignore 0
|
|
set_ne hide_empty_graphs 0 ;# if set to 1 waveform boxes will be hidden if no raw file loaded
|
|
set_ne graph_use_ctrl_key 0;# if set forces to use Control key to operate on graphs
|
|
set_ne spiceprefix 1
|
|
set_ne verilog_2001 1
|
|
set_ne verilog_bitblast 0
|
|
set_ne search_schematic 0
|
|
# if set to 1 search symbols (if not in any of the XSCHEM_LIBRARY_PATH directories) in [pwd]
|
|
# instead of in the directory of currently loaded schematic.
|
|
set_ne split_files 0
|
|
set_ne flat_netlist 0
|
|
set_ne netlist_show 0
|
|
set_ne color_ps 1
|
|
set_ne ps_page_title 1 ;# add a title in the top left page corner
|
|
set_ne draw_crosshair 0
|
|
set_ne crosshair_layer 8 ;# Yellow
|
|
set_ne crosshair_size 0
|
|
set_ne snap_cursor_size 6
|
|
set_ne ps_paper_size {a4 842 595}
|
|
set_ne transparent_svg 0
|
|
set_ne only_probes 0 ; # 20110112
|
|
set_ne fullscreen 0
|
|
set_ne unzoom_nodrift 0
|
|
set_ne zoom_full_center 0
|
|
set_ne change_lw 1
|
|
set_ne line_width 0
|
|
set_ne live_cursor2_backannotate 1
|
|
set_ne cursor_2_hook {}
|
|
set_ne draw_window 0
|
|
set_ne show_hidden_texts 0
|
|
set_ne incr_hilight 1
|
|
set_ne enable_stretch 0
|
|
set_ne constr_mv 0
|
|
set_ne unselect_partial_sel_wires 0
|
|
set_ne load_file_dialog_fullpath 1
|
|
set_ne file_dialog_others {} ;# contains 2nd, 3rd, ... selected filenames on mult. selections in load file
|
|
|
|
# if set show selected elements while dragging the selection rectangle.
|
|
# once selected these can not be unselected by retracting the selection rectangle
|
|
# if not set show selected items at end of drag.
|
|
set_ne incremental_select 1
|
|
set_ne select_touch 1
|
|
|
|
set_ne draw_grid 1
|
|
set_ne big_grid_points 0
|
|
set_ne grid_point_size -1 ;# grid point size (>=0) or unspecified (-1)
|
|
set_ne draw_grid_axes 1
|
|
set_ne persistent_command 0
|
|
set_ne intuitive_interface 1
|
|
set_ne use_cursor_for_selection 0
|
|
set_ne autotrim_wires 0
|
|
set_ne cadence_compat 0
|
|
set_ne infix_interface 1
|
|
set_ne snap_cursor 0
|
|
set_ne orthogonal_wiring 0
|
|
set_ne compare_sch 0
|
|
set_ne disable_unique_names 0
|
|
set_ne sym_txt 1
|
|
set_ne show_infowindow 0
|
|
set_ne show_infowindow_after_netlist onerror
|
|
set_ne no_ask_save 0 ;# if set to 1 ctrl-s (save) will not ask to save
|
|
set_ne no_ask_simulate 0 ;# if set to 1 no confirmation for simulation ('s')
|
|
set_ne erc_open_net_is_error 0;# if set to 1 turn warnings into errors
|
|
set_ne erc_shorted_output_is_error 0;# if set to 1 turn warnings into errors
|
|
set_ne symbol_width 150
|
|
set_ne editor {gvim -f}
|
|
set_ne rainbow_colors 0
|
|
set_ne edit_symbol_prop_new_sel {}
|
|
if {$OS == "Windows"} {
|
|
set_ne launcher_default_program [auto_execok start]
|
|
} else {
|
|
set_ne launcher_default_program {xdg-open}
|
|
}
|
|
set_ne auto_hilight 0
|
|
set_ne auto_hilight_graph_nodes 0
|
|
set_ne use_tclreadline 1
|
|
set_ne en_hilight_conn_inst 0
|
|
## xpm to png conversion
|
|
set_ne to_png {gm convert}
|
|
## ps to pdf conversion
|
|
set_ne to_pdf {ps2pdf}
|
|
## tab stop position
|
|
set_ne tabstop 8
|
|
if { [info tclversion] > 8.4 } {
|
|
set text_tabs_setting {-tabs "[expr {$tabstop * [font measure TkFixedFont 0]}] left" -tabstyle wordprocessor}
|
|
} else {
|
|
set text_tabs_setting {-tabs "[expr {$tabstop * [font measure TkFixedFont 0]}] left"}
|
|
}
|
|
|
|
# selected graph user is editing attributes with graph GUI
|
|
set_ne graph_bus 0
|
|
set_ne graph_private_cursor 0
|
|
set_ne graph_logx 0
|
|
set_ne graph_logy 0
|
|
set_ne graph_rainbow 0
|
|
set_ne graph_selected {}
|
|
set_ne graph_schname {}
|
|
set_ne graph_change_done 0 ;# used to push undo only once when editing graphs
|
|
set_ne graph_linewidth_mult 1.4 ;# default multiplier (w.r.t. xschem lines) for line width in graphs
|
|
# user clicked this wave
|
|
set_ne graph_sel_wave {}
|
|
# flag to force simulation stop (Esc key pressed)
|
|
set_ne tclstop 0
|
|
## undo_type: disk or memory
|
|
set_ne undo_type disk
|
|
|
|
## show tab bar (tabbed interface)
|
|
set_ne tabbed_interface 1
|
|
|
|
## File->Open will open in a new window/tab instead of replacing content in current one
|
|
## if enabled.
|
|
set_ne open_in_new_window 0
|
|
|
|
## case insensitive symbol lookup (on case insensitive filesystems only!)
|
|
set_ne case_insensitive 0
|
|
|
|
## 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 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 {*}
|
|
|
|
#### toolbar icons are bitmaps. Their size is 24x24. This can be changed to
|
|
#### accommodate UHD displays.
|
|
#### the zoom factor is an integer that can be used to enlarge these icons
|
|
#### Default value: 1
|
|
set_ne toolbar_icon_zoom 1
|
|
#### context menu icons are 16 x 16. they can be enlarged by the following integer
|
|
#### default value: 1
|
|
set_ne ctxmenu_icon_zoom 1
|
|
|
|
## remember edit_prop widget size
|
|
set_ne edit_prop_size 80x12
|
|
set_ne text_line_default_geometry {}
|
|
set_ne enter_text_default_geometry {}
|
|
set_ne graph_dialog_default_geometry {}
|
|
set_ne terminal xterm
|
|
|
|
# xschem tcp port number (listen to port and execute commands from there if set)
|
|
# set a port number in xschemrc if you want accept remote connections.
|
|
set_ne xschem_listen_port {}
|
|
|
|
# server for bespice waveform connection (listen to port and send commands to bespice if set)
|
|
# set a port number in xschemrc if you want xschem to be able to cross-probe to bespice
|
|
set_ne bespice_listen_port {}
|
|
|
|
set_ne keep_symbols 0 ;# if set loaded symbols will not be purged when descending/netlisting.
|
|
|
|
# hide instance details (show only bbox)
|
|
set_ne hide_symbols 0
|
|
# gaw tcp {host port}
|
|
set_ne gaw_tcp_address {localhost 2020}
|
|
|
|
## cairo stuff 20171112
|
|
set_ne cairo_font_scale 1.0
|
|
set_ne nocairo_font_xscale .85
|
|
set_ne nocairo_font_yscale .88
|
|
set_ne cairo_font_line_spacing 1.0
|
|
set_ne cairo_vert_correct 0
|
|
set_ne nocairo_vert_correct 0
|
|
|
|
# Arial, Monospace Sans-Serif; default font to use if unspecified in text elements
|
|
set_ne cairo_font_name {Sans-Serif}
|
|
set_ne svg_font_name {Sans-Serif}
|
|
|
|
# has_cairo set by c program if cairo enabled
|
|
set has_cairo 0
|
|
set rotated_text {} ;#20171208
|
|
set_ne enable_dim_bg 0
|
|
set_ne dim_bg 0.0
|
|
set_ne dim_value 0.0
|
|
set_ne fix_broken_tiled_fill 1 ;# set to 1 on some broken X11 drivers / GPUs that show garbage on screen */
|
|
# this fix uses an alternative method for getting mouse coordinates on KeyPress/KeyRelease
|
|
# events. Some remote connection softwares do not generate the correct coordinates
|
|
# on such events */
|
|
set_ne fix_mouse_coord 0
|
|
|
|
##### set colors
|
|
if {!$rainbow_colors} {
|
|
set_ne cadlayers 22
|
|
## 20171113
|
|
set_ne light_colors {
|
|
"#ffffff" "#0099cc" "#aaaaaa" "#222222" "#229900"
|
|
"#bb2200" "#0066cc" "#ff0000" "#888800" "#00aaaa"
|
|
"#880088" "#00ff00" "#0000cc" "#666600" "#557755"
|
|
"#aa2222" "#7ccc40" "#00ffcc" "#ce0097" "#d2d46b"
|
|
"#ef6158" "#fdb200"}
|
|
set_ne dark_colors {
|
|
"#000000" "#00ddff" "#4f4f4f" "#cccccc" "#88dd00"
|
|
"#bb2200" "#00aaff" "#ff0000" "#ffff00" "#ffffff"
|
|
"#ff00ff" "#00ff00" "#0044ff" "#aaaa00" "#aaccaa"
|
|
"#ff7777" "#bfff81" "#00ffcc" "#ce0097" "#d2d46b"
|
|
"#ef6158" "#fdb200"}
|
|
} else {
|
|
# rainbow colors for bitmapping
|
|
# skip if colors defined in ~/.xschem 20121110
|
|
set_ne cadlayers 35
|
|
#20171113
|
|
set_ne light_colors {
|
|
"#000000" "#00ccee" "#aaaaaa" "#ffffff" "#88dd00"
|
|
"#bb2200" "#0000e0" "#2000e0" "#4000e0" "#6000e0"
|
|
"#8000e0" "#a000e0" "#c000e0" "#e000e0" "#e000c0"
|
|
"#e000a0" "#e00080" "#e00060" "#e00040" "#e00020"
|
|
"#e00000" "#e02000" "#e04000" "#e06000" "#e08000"
|
|
"#e0a000" "#e0c000" "#e0e000" "#e0e020" "#e0e040"
|
|
"#e0e060" "#e0e080" "#e0e0a0" "#e0e0c0" "#e0e0e0"
|
|
}
|
|
set_ne dark_colors {
|
|
"#000000" "#00ccee" "#3f3f3f" "#ffffff" "#88dd00"
|
|
"#bb2200" "#0000e0" "#2000e0" "#4000e0" "#6000e0"
|
|
"#8000e0" "#a000e0" "#c000e0" "#e000e0" "#e000c0"
|
|
"#e000a0" "#e00080" "#e00060" "#e00040" "#e00020"
|
|
"#e00000" "#e02000" "#e04000" "#e06000" "#e08000"
|
|
"#e0a000" "#e0c000" "#e0e000" "#e0e020" "#e0e040"
|
|
"#e0e060" "#e0e080" "#e0e0a0" "#e0e0c0" "#e0e0e0"
|
|
}
|
|
}
|
|
|
|
|
|
# every 0x#### hex data represents one 16 bit row of the 16x16 bit fill bitmap
|
|
# of the specified layer number.
|
|
set_ne pixdata(0) {
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
}
|
|
set_ne pixdata(1) {
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
}
|
|
set_ne pixdata(2) {
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(3) {
|
|
0x5555 0x0000 0xaaaa 0x0000 0x5555 0x0000 0xaaaa 0x0000
|
|
0x5555 0x0000 0xaaaa 0x0000 0x5555 0x0000 0xaaaa 0x0000
|
|
}
|
|
set_ne pixdata(4) {
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
}
|
|
set_ne pixdata(5) {
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
}
|
|
set_ne pixdata(6) {
|
|
0x0101 0x0000 0x0000 0x0000 0x1010 0x0000 0x0000 0x0000
|
|
0x0101 0x0000 0x0000 0x0000 0x1010 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(7) {
|
|
0x0000 0x8000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0200
|
|
0x0000 0x0080 0x0000 0x0000 0x0000 0x0000 0x0000 0x0002
|
|
}
|
|
set_ne pixdata(8) {
|
|
0x1111 0x0000 0x0000 0x0000 0x1111 0x0000 0x0000 0x0000
|
|
0x1111 0x0000 0x0000 0x0000 0x1111 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(9) {
|
|
0x0441 0x0000 0x1004 0x0000 0x4110 0x0000 0x0441 0x0000
|
|
0x1004 0x0000 0x4110 0x0000 0x0441 0x0000 0x1004 0x0000
|
|
}
|
|
set_ne pixdata(10) {
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff 0xffff
|
|
}
|
|
set_ne pixdata(11) {
|
|
0x1111 0x0000 0x4444 0x0000 0x1111 0x0000 0x4444 0x0000
|
|
0x1111 0x0000 0x4444 0x0000 0x1111 0x0000 0x4444 0x0000
|
|
}
|
|
set_ne pixdata(12) {
|
|
0x0404 0x0202 0x0101 0x8080 0x4040 0x2020 0x1010 0x0808
|
|
0x0404 0x0202 0x0101 0x8080 0x4040 0x2020 0x1010 0x0808
|
|
}
|
|
set_ne pixdata(13) {
|
|
0x1111 0x2222 0x4444 0x8888 0x1111 0x2222 0x4444 0x8888
|
|
0x1111 0x2222 0x4444 0x8888 0x1111 0x2222 0x4444 0x8888
|
|
}
|
|
set_ne pixdata(14) {
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(15) {
|
|
0x4444 0x0000 0x0000 0x0000 0x4444 0x0000 0x0000 0x0000
|
|
0x4444 0x0000 0x0000 0x0000 0x4444 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(16) {
|
|
0x1111 0x0000 0x0000 0x0000 0x2222 0x0000 0x0000 0x0000
|
|
0x4444 0x0000 0x0000 0x0000 0x8888 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(17) {
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(18) {
|
|
0x5555 0xaaaa 0x5555 0xaaaa 0x5555 0xaaaa 0x5555 0xaaaa
|
|
0x5555 0xaaaa 0x5555 0xaaaa 0x5555 0xaaaa 0x5555 0xaaaa
|
|
}
|
|
set_ne pixdata(19) {
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(20) {
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
}
|
|
set_ne pixdata(21) {
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
|
|
}
|
|
|
|
|
|
# for svg and pdf draw 20121108
|
|
regsub -all {"} $dark_colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
regsub -all {"} $light_colors {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
set_missing_colors_to_black
|
|
# read-only vars to store defaults (so we can switch to default colors)
|
|
set dark_colors_save $dark_colors
|
|
set light_colors_save $light_colors
|
|
|
|
set_ne tctx::colors $dark_colors
|
|
##### end set colors
|
|
|
|
|
|
# 20111005 added missing initialization of globals...
|
|
set_ne no_change_attrs 0
|
|
set_ne preserve_unchanged_attrs 0
|
|
set search_select 0
|
|
|
|
# 20111106 these vars are overwritten by caller with mktemp file names
|
|
if {$OS == "Windows"} {
|
|
set filetmp $env(windir)/.tmp2
|
|
} else {
|
|
set filetmp [pwd]/.tmp2
|
|
}
|
|
|
|
# flag bound to a checkbutton in symbol editprop form
|
|
# if set cell is copied when renaming it
|
|
set_ne copy_cell 0
|
|
|
|
load_recent_file
|
|
# schematic to preload in new windows 20090708
|
|
set_ne XSCHEM_START_WINDOW {}
|
|
|
|
set custom_token {lab}
|
|
set search_value {}
|
|
set search_exact 0
|
|
set search_case 1
|
|
|
|
# 20171005
|
|
set custom_label_prefix {}
|
|
|
|
###
|
|
### build Tk widgets
|
|
###
|
|
if { ( $OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 ) && [info exists has_x]} {
|
|
setup_toolbar
|
|
# for hyperlink in about dialog
|
|
eval font create Underline-Font [ font actual TkDefaultFont ]
|
|
font configure Underline-Font -underline true -size 24
|
|
. configure -cursor left_ptr
|
|
set_old_tk_fonts ;# for xschem compiled with old tcl-tk libs
|
|
set infowindow_text {}
|
|
infowindow
|
|
|
|
build_widgets {}
|
|
|
|
##
|
|
## packing top windows (pack instructions) and event binding (bind instructions) done in proc pack_widgets
|
|
## executed by xinit.c after finalizing X initialization. This avoid potential race conditions
|
|
## like Configure or Expose events being generated before xschem being ready to handle them.
|
|
##
|
|
|
|
# allow user to modify key bindings
|
|
set_replace_key_binding
|
|
|
|
# update
|
|
# xschem windowid . ;# set icon for window
|
|
} ;# end if {[exists has_x]}
|
|
|
|
# read custom colors
|
|
if { [file exists ${USER_CONF_DIR}/colors] } {
|
|
source ${USER_CONF_DIR}/colors
|
|
}
|
|
|
|
if { [llength $dark_colors] < $cadlayers || [llength $light_colors] < $cadlayers } {
|
|
puts stderr { Warning: wrong number of configured layers in light_colors or dark_colors variables.}
|
|
}
|
|
if { $dark_colorscheme == 1} {
|
|
set tctx::colors $dark_colors
|
|
} else {
|
|
set tctx::colors $light_colors
|
|
}
|
|
regsub -all {"} $light_colors {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
regsub -all {"} $tctx::colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
|
|
if { $show_infowindow } { wm deiconify .infotext }
|
|
|
|
# xschem listen and bespice listen
|
|
setup_tcp_xschem
|
|
setup_tcp_bespice
|
|
|
|
# automatically build pathlist whenever XSCHEM_LIBRARY_PATH changes
|
|
trace add variable XSCHEM_LIBRARY_PATH write trace_set_vars
|
|
# trigger file_chooser update
|
|
trace add variable new_file_browser_depth write trace_set_vars
|
|
trace add variable new_file_browser_ext write trace_set_vars
|
|
|