}
end
+def cmd_show_ortep
+ mol = self
+ tmp = create_temp_dir("ortep", mol.name)
+ tepexe = "#{ResourcePath}/ortep3/ortep3"
+ if $platform == "win"
+ tepexe += ".exe"
+ end
+ tepdata = []
+ tepbounds = [0, 0, 400, 400]
+ Dialog.new("Show ORTEP:" + mol.name, nil, nil, :resizable=>true, :has_close_box=>true) {
+ tepview = nil # Forward declaration
+ on_update_ortep = lambda { |it|
+ # Create ORTEP input in the temporary directory
+ open(tmp + "/TEP.IN", "w") { |fp| mol.export_ortep(fp) }
+ # Run ORTEP
+ cwd = Dir.pwd
+ Dir.chdir(tmp)
+ if FileTest.exist?("TEP001.PRN")
+ File.unlink("TEP001.PRN")
+ end
+ pid = call_subprocess(tepexe, "Running ORTEP", nil, "NUL", "NUL")
+ if FileTest.exist?("TEP001.PRN")
+ File.rename("TEP001.PRN", "TEP001.ps")
+ end
+ Dir.chdir(cwd)
+ if pid != 0
+ msg = "ORTEP execution in #{tmp} failed with status #{pid}."
+ message_box(msg, "ORTEP Failed", :ok, :warning)
+ else
+ open(tmp + "/TEP001.ps", "r") { |fp|
+ tepdata.clear
+ tepbounds = [100000, 100000, -100000, -100000]
+ fp.each_line { |ln|
+ ln.chomp!
+ x, y, c = ln.split
+ x = x.to_i
+ y = y.to_i
+ if c == "m"
+ tepdata.push([x, y])
+ elsif c == "l"
+ tepdata[-1].push(x, y)
+ else
+ next
+ end
+ tepbounds[0] = x if x < tepbounds[0]
+ tepbounds[1] = y if y < tepbounds[1]
+ tepbounds[2] = x if x > tepbounds[2]
+ tepbounds[3] = y if y > tepbounds[3]
+ }
+ }
+ tepview.refresh_rect(tepview[:frame])
+ end
+ }
+ on_draw_ortep = lambda { |it|
+ clear
+ frame = it[:frame]
+ rx = (frame[2] - 10.0) / (tepbounds[2] - tepbounds[0])
+ ry = (frame[3] - 10.0) / (tepbounds[3] - tepbounds[1])
+ rx = ry if rx > ry
+ dx = (frame[2] - (tepbounds[2] - tepbounds[0]) * rx) * 0.5
+ dy = (frame[3] + (tepbounds[3] - tepbounds[1]) * rx) * 0.5
+ tepdata.each { |d|
+ x0 = (dx + (d[0] - tepbounds[0]) * rx).to_i
+ y0 = (dy - (d[1] - tepbounds[1]) * rx).to_i
+ (d.length / 2 - 1).times { |i|
+ x1 = (dx + (d[i * 2 + 2] - tepbounds[0]) * rx).to_i
+ y1 = (dy - (d[i * 2 + 3] - tepbounds[1]) * rx).to_i
+ draw_line(x0, y0, x1, y1)
+ x0 = x1
+ y0 = y1
+ }
+ }
+ }
+ @on_close = lambda { |*d|
+ puts "#{self}: on_close invoked"
+ cleanup_temp_dir(tmp)
+ tmp = nil
+ true
+ }
+ layout(1,
+ item(:view, :width=>400, :height=>400, :tag=>"ortep", :on_paint=>on_draw_ortep, :flex=>[0,0,0,0,1,1]),
+ layout(2,
+ item(:button, :title=>"Refresh", :action=>on_update_ortep, :align=>:left),
+ -1,
+ :flex=>[0,1,0,0,1,0]),
+ :flex=>[0,0,0,0,1,1])
+ tepview = item_with_tag("ortep")
+ listen(mol, "documentWillClose", :close )
+ on_update_ortep.call(nil)
+ show
+ }
+end
+
if lookup_menu("Best-fit Planes...") < 0
register_menu("", "")
register_menu("Best-fit Planes...", :cmd_plane)
return Dir.mkdir(path)
end
end
+ def create_temp_dir(tag, name = nil)
+ # Create a temporary directory like HomeDirectory/Molby/tag/name.xxxxxx
+ name ||= "temp"
+ base = $home_directory + "/Molby/" + tag
+ mkdir_recursive(base)
+ 10000.times { |n|
+ p = sprintf("%s/%s.%05d", base, name, n)
+ if !FileTest.exist?(p)
+ Dir.mkdir(p)
+ return p
+ end
+ }
+ raise "Cannot create temporary directory in #{base}"
+ end
+ def rm_recursive(path)
+ if FileTest.directory?(path)
+ Dir.foreach(path) { |en|
+ next if en == "." || en == ".."
+ rm_recursive(path + "/" + en)
+ }
+ Dir.rmdir(path)
+ else
+ File.unlink(path)
+ end
+ end
+ def cleanup_temp_dir(path, option = nil)
+ # Clean-up temporary directories
+ # If option is nil, then the directory at path is removed
+ # If option is a number, then the directories that are in the same parent directory as path
+ # are removed except for the newest ones
+ if path.index($home_directory + "/Molby/") != 0
+ raise "Bad cleanup_temp_dir call: the path does not begin with $HOME/Molby/ (#{path})"
+ end
+ if !FileTest.directory?(path)
+ raise "Bad cleanup_temp_dir call: the path is not a directory (#{path})"
+ end
+ option = option.to_i
+ if option <= 0
+ rm_recursive(path)
+ else
+ base = File.dirname(path)
+ ent = Dir.entries.sort_by { |en| File.mtime("#{base}/#{en}").to_i * (-1) } - [".", ".."]
+ if $platform == "mac"
+ ent -= [".DS_Store"]
+ end
+ ent[0, option] = [] # Remove newest #{option} entries
+ # Mark this directory to be ready to remove (see below)
+ open("#{path}/.done", "w") { |fp| }
+ # Remove the older directories
+ ent.each { |en|
+ # Check the existence of ".done" file (otherwise, we may accidentarily remove a directory
+ # that is still in use in other threads)
+ if File.exist?("#{base}/#{en}/.done")
+ rm_recursive("#{base}/#{en}")
+ end
+ }
+ end
+ end
end
class IO