OSDN Git Service

Start implementing JANPA integration with Psi4
[molby/Molby.git] / Scripts / commands.rb
1 # coding: utf-8
2 #
3 #  commands.rb
4 #
5 #  Created by Toshi Nagata on 2008/06/28.
6 #  Copyright 2008 Toshi Nagata. All rights reserved.
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation version 2 of the License.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16
17 class Molecule
18
19   def cmd_assign_residue
20     sel = self.selection
21         if sel.length == 0
22           sel = self.atom_group
23         end
24         atoms = sel.inspect.sub!("IntGroup[", "").sub!("]", "")
25     hash = Dialog.run("Assign Residue") {
26           layout(2,
27                 item(:text, :title=>"New residue name/number\n(like \"RES.1\")\nfor atoms #{atoms}"),
28             item(:textfield, :width=>120, :tag=>"residue"))
29     }
30     if hash[:status] == 0
31           residue = hash["residue"]
32           assign_residue(sel, residue)
33         end
34   end
35
36   def cmd_offset_residue
37     sel = self.selection
38         if sel.length == 0
39           sel = self.atom_group
40         end
41         atoms = sel.inspect.sub!("IntGroup[", "").sub!("]", "")
42     hash = Dialog.run("Offset Residues") {
43           layout(2,
44                 item(:text, :title=>"Offset residue number:\nfor atoms #{atoms}"),
45             item(:textfield, :width=>120, :tag=>"offset"))
46     }
47         if hash[:status] == 0
48           offset = hash["offset"].to_i
49           offset_residue(sel, offset)
50         end
51   end
52    
53   def cmd_sort_by_residue
54     sel = self.selection
55         if sel.length == 0
56           sel = self.atom_group
57         end
58         sorted = sel.sort_by { |i| [self.atoms[i].res_seq, i] }
59         ary = []
60         j = 0
61         (0...natoms).each { |i|
62           if sel.include?(i)
63             ary << sorted[j]
64                 j += 1
65                 break if j >= sorted.length
66           else
67             ary << i
68           end
69         }
70         self.renumber_atoms(ary)
71   end
72
73   def cmd_delete_frames
74     n = nframes
75     return if n == 0
76         hash = Dialog.run("Delete Frames") {
77           layout(2,
78             item(:text, :title=>"Start"),
79             item(:textfield, :width=>120, :tag=>"start", :value=>"0"),
80                 item(:text, :title=>"End"),
81                 item(:textfield, :width=>120, :tag=>"end", :value=>(n - 1).to_s),
82                 item(:text, :title=>"Keeping frames every..."),
83                 -1,
84                 item(:text, :title=>"Step"),
85                 item(:textfield, :width=>120, :tag=>"step", :value=>"0"))
86         }
87         if hash[:status] == 0
88           sframe = Integer(hash["start"])
89           eframe = Integer(hash["end"])
90           step = Integer(hash["step"])
91           return if sframe > eframe
92           eframe = n - 1 if eframe >= n
93           fgroup = IntGroup[sframe..eframe]
94           if step > 0
95             while sframe <= eframe
96                   fgroup.delete(sframe)
97                   sframe += step
98                 end
99           end
100           remove_frames(fgroup)
101         end
102   end
103
104   def cmd_reverse_frames
105     n = nframes
106     return if n == 0
107         hash = Dialog.run("Reverse Frames") {
108           layout(2,
109             item(:text, :title=>"Start"),
110             item(:textfield, :width=>120, :tag=>"start", :value=>"0"),
111                 item(:text, :title=>"End"),
112                 item(:textfield, :width=>120, :tag=>"end", :value=>(n - 1).to_s))
113         }
114         if hash[:status] == 0
115           sframe = Integer(hash["start"])
116           eframe = Integer(hash["end"])
117           return if sframe > eframe
118           eframe = n - 1 if eframe >= n
119           frames = (0...sframe).to_a + (sframe..eframe).to_a.reverse + ((eframe + 1)...n).to_a
120           reorder_frames(frames)
121         end
122   end
123
124   def cmd_concat_frames
125       n = nframes
126       return if n == 0
127       if Molecule.list.length == 1
128           message_box("No other molecule.", "", :ok)
129           return
130       end
131       ls = (0...Molecule.list.length).select { |i|
132           m = Molecule[i]
133           if m == self || m.natoms != self.natoms
134               false
135               else
136               if nil != (0...m.natoms).find { |n| m.atoms[n].atomic_number != self.atoms[n].atomic_number }
137                   false
138                   else
139                   true
140               end
141           end
142       }
143       if ls.length == 0
144           message_box("No molecule has the same atomic sequence as the present one.", "", :ok)
145           return
146       end
147       labels = []
148       label_hash = Hash.new   #  Check if documents with the same name are present
149       ls.each_with_index { |i, idx|  #  i is an index to Molecule, idx is an index to ls
150           m = Molecule[i]
151           label = m.name
152           idx_h = label_hash[label]  #  If non-nil, then duplicate name
153           label_hash[label] = idx
154           if idx_h
155               if labels[idx_h] == label
156                   labels[idx_h] = label + " (" + Molecule[ls[idx_h]].dir + ")"
157               end
158               label = label + " (" + Molecule[i].dir + ")"
159           end
160           labels.push(label)
161       }
162       nf = Molecule[ls[0]].nframes
163       hash = Dialog.run("Concatenate Frames") {
164           layout(2,
165                  item(:text, :title=>"From Molecule:"),
166                  item(:popup, :subitems=>labels, :tag=>"mol", :width=>240,
167                       :action=>lambda { |it|
168                       nf = Molecule[ls[it[:value]]].nframes
169                       set_attr("start_title", :title=>"Start (0-#{nf})")
170                       set_attr("end_title", :title=>"End (0-#{nf})")
171                       }),
172                  item(:radio, :title=>"All Frames", :tag=>"all_frames", :value=>1,
173                       :action=>lambda { |it|
174                       flag = (it[:value] == 0)
175                       set_attr("start_frame", :enabled=>flag)
176                       set_attr("end_frame", :enabled=>flag)
177                       }), -1,
178                  item(:radio, :title=>"Select Frames", :tag=>"select_frames",
179                       :action=>lambda { |it|
180                       flag = (it[:value] != 0)
181                       set_attr("start_frame", :enabled=>flag)
182                       set_attr("end_frame", :enabled=>flag)
183                       }), -1,
184                  item(:text, :title=>"Start (0-#{nf})", :tag=>"start_title"),
185                  item(:textfield, :value=>"0", :tag=>"start_frame", :enabled=>false),
186                  item(:text, :title=>"End (0-#{nf})", :tag=>"end_title"),
187                  item(:textfield, :value=>"0", :tag=>"end_frame", :enabled=>false))
188                  radio_group("all_frames", "select_frames")
189       }
190       if hash[:status] == 0
191           idx_h = Integer(hash["mol"])
192           m = Molecule[ls[idx_h]]
193           f = m.frame  #  Save the current frame number
194           nf = m.nframes
195           if hash["all_frame"] != 0
196               f1 = 0
197               f2 = nf - 1
198               else
199               f1 = Integer(hash["start_frame"])
200               f2 = Integer(hash["end_frame"])
201               f1 = 0 if f1 < 0
202               f1 = nf - 1 if f1 > nf - 1
203               f2 = 0 if f2 < 0
204               f2 = nf - 1 if f2 > nf - 1
205           end
206           if f1 <= f2
207               a = (f1..f2).to_a
208               else
209               a = (f2..f1).to_a.reverse
210           end
211           prop = m.property_names
212           na = m.natoms
213           a.each { |n|
214               self.create_frame()
215               m.select_frame(n)
216               na.times { |i|
217                   self.atoms[i].r = m.atoms[i].r
218               }
219               prop.each { |pr|
220                   self.set_property(pr, m.get_property(pr))
221               }
222           }
223       end
224   end
225
226   def cmd_extra_properties
227     mol = self
228         get_count = lambda { |it| mol.nframes }
229         get_value = lambda { |it, row, col|
230           if col == 0
231             row.to_s
232           else
233             sprintf("%.8f", mol.get_property(col - 1, row)) rescue ""
234           end
235     }
236     mol.open_auxiliary_window("Extra Props", :resizable=>true, :has_close_box=>true) {
237           names = nil
238           @on_document_modified = lambda { |m|
239             if (n = m.property_names) != names
240                   names = n
241                   col = [["frame", 40]] + names.map { |nn| [nn, 120] }
242                   item_with_tag("table")[:columns] = col
243                 end
244                 item_with_tag("table")[:refresh] = true
245           }
246           layout(1,
247                 item(:table, :width=>320, :height=>300, :flex=>[0,0,0,0,1,1], :tag=>"table",
248                   :on_count=>get_count,
249                   :on_get_value=>get_value),
250             :flex=>[0,0,0,0,1,1]
251           )
252           set_min_size(320, 200)
253           # listen(mol, "documentModified", on_document_modified)
254           # listen(mol, "documentWillClose", lambda { |m| close } )
255           @on_document_modified.call(mol)
256           show
257         }
258   end
259   
260   def cmd_show_energy
261     wave = [0.0, 0.0]
262     cur = 0
263     mol = self
264     wave_min = lambda { m = 1e8; wave.each { |x| if x != 0.0 && x < m; m = x; end }; m }
265     wave_max = lambda { m = -1e8; wave.each { |x| if x != 0.0 && x > m; m = x; end }; m }
266     d = open_auxiliary_window("Energy", :resizable=>true, :has_close_box=>true) {
267     graph_item = nil   #  Forward declaration
268     target_mol = nil
269     draw_graph = lambda { |it|
270       clear
271       f = graph_item[:frame]
272       draw_rectangle(0, 0, f[2], f[3])
273       width = f[2] - 25
274       height = f[3] - 25
275       draw_line(16, 0, 16, height + 12, width + 20, height + 12)
276       xx = yy = nil
277       min = wave_min.call
278       max = wave_max.call
279       h = max - min
280       h = (h == 0.0 ? 1.0 : height / h)
281       c = wave.count
282       if c == 0
283         w = 1.0
284       elsif c == 1
285         w = Float(width)
286       else
287         w = Float(width) / (c - 1)
288       end
289       lines = []
290       a = []
291       #  Skip the points that have exactly 0.0 value
292       wave.each_with_index { |d, i|
293         if d != 0.0
294           a.push(i * w + 16)
295           a.push(height - (d - min) * h + 12)
296         end
297         if d == 0.0 || i == wave.length - 1
298           #  End of this curve fragment
299           if a.length == 0
300             #  Do nothing
301           else
302             if a.length == 2
303               if wave.count == 1
304                 #  If wave has only one point, then draw a horizontal line
305                 a.push(a[0] + 16)
306                 a.push(a[1])
307               else
308                 #  Otherwise, draw a zero-length line
309                 a.push(a[0])
310                 a.push(a[1])
311               end
312             end
313             lines.push(a)  #  Store this line fragment
314             a = []
315           end
316         end
317       }
318       lines.each { |a|
319         draw_line(a)
320       }
321       brush(:color=>[0.2, 0.2, 1.0])
322       y = wave[cur] || 0.0
323       if y < min
324         y = min
325       elsif y > max
326         y = max
327       end
328       xx = cur * w + 16
329       yy = height - (y - min) * h + 12
330       draw_ellipse(cur * w + 16, height - (y - min) * h + 12, 6)
331     }
332           @on_document_modified = lambda { |m|
333                 cur = mol.frame
334                 wave.clear
335                 if mol.nframes < 2
336                   wave = [mol.get_property("energy", 0)] * 2
337                 else
338                   wave = (0...mol.nframes).map { |i| mol.get_property("energy", i) }
339                 end
340                 f = graph_item[:frame]
341                 item_with_tag("energy")[:title] = sprintf("Energy = %.10f hartree, Frame = %d", mol.get_property("energy", cur), cur)
342                 graph_item.refresh_rect([0, 0, f[2], f[3]])
343           }
344           layout(1,
345                 item(:text, :title=>"Energy =                 ", :tag=>"energy"),
346                 item(:view, :frame=>[0, 0, 320, 240], :tag=>"graph", :on_paint=>draw_graph, :flex=>[0,0,0,0,1,1]),
347         #       item(:button, :title=>"Update", :action=>doc_modified, :align=>:center, :flex=>[1,1,1,0,0,0]),
348         #       item(:button, :title=>"Close", :action=>proc { hide }, :align=>:center, :flex=>[1,1,1,0,0,0]),
349                 :flex=>[0,0,0,0,1,1]
350           )
351           graph_item = item_with_tag("graph")
352           size = self.size
353           set_min_size(size)
354           set_size(500, 300)
355           @on_document_modified.call(mol)
356           show
357         }
358         self
359   end
360   
361   def cmd_create_surface
362     if @surface_dialog_attr == nil
363           @surface_dialog_attr = Hash.new
364           @surface_dialog_attr["hidden"] = -1
365         end
366     surface_dialog_attr = @surface_dialog_attr
367     mol = self
368         mol.open_auxiliary_window("MO Surface", :resizable=>true, :has_close_box=>true) {
369           tags = ["mo_ao", "mo", "color", "opacity", "threshold", "expand", "grid"]
370           motype = mol.get_mo_info(:type)
371           alpha = mol.get_mo_info(:alpha)
372           beta = mol.get_mo_info(:beta)
373           ncomps = mol.get_mo_info(:ncomps)
374           mo_index = 1
375           mo_ao = nil
376           coltable = [[0,0,1], [1,0,0], [0,1,0], [1,1,0], [0,1,1], [1,0,1], [0,0,0]]
377           mo_ao_items = ["Molecular Orbitals", "Atomic Orbitals"]
378           mo_ao_keys = ["MO", "AO"]
379       if (nbo = mol.instance_eval { @nbo }) != nil
380             nbo.keys.each { |key|
381                   if key[0..2] == "AO/"
382                     key2 = key[3..-1]
383                         name2 = key2
384                         if key2 == "NAO"
385                           name2 = "Natural Atomic Orbitals"
386                         elsif key2 == "NBO"
387                           name2 = "Natural Bond Orbitals"
388                         elsif key2 == "NHO"
389                           name2 = "Natural Hybrid Orbitals"
390                         elsif key2 == "NLMO"
391                           name2 = "Natural Localized Molecular Orbitals"
392                         elsif key2 == "PNAO"
393                           name2 = "Pre-orthogonal Natural Atomic Orbitals"
394                         elsif key2 == "PNHO"
395                           name2 = "Pre-orthogonal Natural Hybrid Orbitals"
396                         elsif key2 == "PNBO"
397                           name2 = "Pre-orthogonal Natural Bond Orbitals"
398       elsif key2 == "AHO"
399         name2 = "Atomic Hybrid Orbitals"
400       elsif key2 == "LHO"
401         name2 = "Localized Hybrid Orbitals"
402       elsif key2 == "LPO"
403         name2 = "Localized Property-optimized Orbitals"
404       elsif key2 == "CLPO"
405         name2 = "Chemist's Localized Property-optimized Orbitals"
406                         end
407                         mo_ao_items.push(name2)
408                         mo_ao_keys.push(key2)
409                   end
410                 }
411           end
412           mult = (motype == "UHF" ? 2 : 1)
413           mo_menu = ["1000 (-00.00000000)"]  #  Dummy entry; create later
414           tabvals = []
415           coeffs = nil
416           a_idx_old = -1
417           occ = nil
418           ncomps.times { |i|
419             a_idx, s_idx, label = mol.get_gaussian_component_info(i)
420                 if a_idx_old != a_idx
421                   a_idx_old = a_idx
422                   a = a_idx.to_s
423                   n = mol.atoms[a_idx].name
424                 else
425                   a = n = ""
426                 end
427                 tabvals.push([a, n, label, a_idx])
428           }
429           on_update_attr = lambda {
430             tags.each { |tag|
431                   surface_dialog_attr[tag] = item_with_tag(tag)[:value]
432                 }
433                 it = item_with_tag("hide")
434                 case surface_dialog_attr["hidden"]
435                 when -1
436                   it[:title] = "Hide"
437                   it[:enabled] = false
438                 when 0
439                   it[:title] = "Hide"
440                   it[:enabled] = true
441                 when 1
442                   it[:title] = "Show"
443                   it[:enabled] = true
444                 end
445           }
446           on_get_value = lambda { |it, row, col|
447             if col < 3
448                   tabvals[row][col]
449                 else
450                   if coeffs == nil
451                     if mo_ao == 0
452                       coeffs = mol.get_mo_coefficients(mo_index)
453                     elsif mo_ao == 1
454                       coeffs = (0...ncomps).map { |i| (i == mo_index ? 1.0 : 0.0) }
455                         else
456                           coeffs = nbo["AO/" + mo_ao_keys[mo_ao]].column(mo_index).to_a[0]
457                         end
458                   end
459                   sprintf("%.6f", coeffs[row])
460                 end
461           }
462           h = {"mo"=>nil, "color"=>nil, "opacity"=>nil, "threshold"=>nil, "expand"=>nil, "grid"=>nil}
463           should_update = true
464           on_action = lambda { |it|
465             tag = it[:tag]
466                 value = it[:value]
467                 if tag == "color" || tag == "opacity"
468                   opac = value("opacity").to_f
469                   opac = 0.0 if opac < 0.0
470                   opac = 1.0 if opac > 1.0
471                   col = value("color")
472                   color = coltable[col] + [opac]
473                   color0 = [1,1,1,opac]
474                   mol.set_surface_attr(:color=>color, :color0=>color0)
475                   h[tag] = value
476                 elsif tag == "threshold"
477               thres = it[:value].to_f
478                   thres = 0.001 if thres >= 0.0 && thres < 0.001
479                   thres = -0.001 if thres <= 0.0 && thres > -0.001
480                   mol.set_surface_attr(:thres=>thres)
481                   h[tag] = value
482                 else
483               should_update = false
484               h.each_key { |key|
485                     val = value(key)
486                     if val && h[key] != val
487                       should_update = true
488                       break
489                     end
490                   }
491                   item_with_tag("update")[:enabled] = should_update
492                 end
493                 on_update_attr.call
494           }
495           on_mo_action = lambda { |it|
496             mo = it[:value]
497                 if mo_ao == 0
498                   if motype == "UHF"
499                     mo_index = (mo / 2) + (mo % 2 == 1 ? ncomps : 0) + 1
500                         if mo_index <= alpha || (mo_index > ncomps && mo_index <= ncomps + beta)
501                           occ_new = 1
502                         else
503                           occ_new = 0
504                         end
505                   else
506                     mo_index = mo + 1
507                         if mo_index <= alpha && mo_index <= beta
508                           occ_new = 1
509                         elsif mo_index <= alpha || mo_index <= beta
510                           occ_new = -1
511                         else
512                           occ_new = 0
513                         end
514                   end
515                 else
516                   mo_index = mo
517                   occ_new = occ
518                 end
519                 coeffs = nil
520                 if occ_new != occ
521                   #  Set default color
522                   col = (occ_new == 0 ? 1 : (occ_new == -1 ? 2 : 0))
523                   set_value("color", col)
524                   h["color"] = col
525                   occ = occ_new
526                 end
527                 item_with_tag("table")[:refresh] = true
528             on_action.call(it)
529                 on_update_attr.call
530           }
531           on_set_action = lambda { |it|
532             if mo_ao != it[:value]
533                   mo_ao = it[:value]
534                   if mo_ao == 0
535                     mo_menu = (1..(ncomps * mult)).map { |n|
536                   if motype == "UHF"
537                         i1 = (n - 1) / 2 + 1
538                         i2 = n % 2
539                         c1 = (i2 == 0 ? "B" : "A")
540                         c2 = (i1 > (i2 == 0 ? beta : alpha) ? "*" : "")
541                       else
542                         i1 = n
543                         i2 = 1
544                         c1 = ""
545                                 if i1 > beta && i1 > alpha
546                                   c2 = "*"
547                                 elsif i1 > beta || i1 > alpha
548                                   c2 = "S"
549                                 else
550                                   c2 = ""
551                                 end
552                       end
553                       en = mol.get_mo_energy(i1 + (i2 == 0 ? ncomps : 0))
554                       sprintf("%d%s%s (%.8f)", i1, c1, c2, en)
555                         }
556                   elsif mo_ao == 1
557                     mo_menu = []
558                     ncomps.times { |i|
559                           mo_menu[i] = sprintf("AO%d: %s (%s)", i + 1, tabvals[i][2], mol.atoms[tabvals[i][3]].name)
560                         }
561                   else
562                     mo_menu = []
563                         key = mo_ao_keys[mo_ao]
564                         labels = nbo[key + "_L"]
565                         if labels == nil && key[0] == ?P
566                           labels = nbo[key[1..-1] + "_L"]
567                         end
568                         ncomps.times { |i|
569                           lab = sprintf("%s%d", key, i + 1)
570                           if labels
571                             lab += ":" + labels[i]
572                           end
573                           mo_menu[i] = lab
574                         }
575                   end
576                   it0 = item_with_tag("mo")
577                   it0[:subitems] = mo_menu
578                   it0[:value] = 0
579                   h["mo"] = nil  # "Update" button is forced to be enabled
580                   on_mo_action.call(it0)
581                 end
582                 on_update_attr.call
583           }
584           on_update = lambda { |it|
585             h.each_key { |key|
586                   h[key] = value(key)
587                 }
588                 opac = h["opacity"].to_f
589                 opac = 0.0 if opac < 0.0
590                 opac = 1.0 if opac > 1.0
591                 color = coltable[h["color"]] + [opac]
592                 color0 = [1, 1, 1, opac]
593                 thres = h["threshold"].to_f
594                 thres = 0.001 if thres >= 0.0 && thres < 0.001
595                 thres = -0.001 if thres <= 0.0 && thres > -0.001
596                 expand = h["expand"].to_f
597                 expand = 0.01 if expand < 0.01
598                 expand = 10.0 if expand > 10.0
599                 grid = h["grid"].to_i
600                 if grid > 10000000
601                   grid = 10000000
602                 end
603                 if mo_ao == 0
604                   idx = mo_index
605                 else
606                   idx = 0
607                   mol.set_mo_coefficients(0, 0.0, coeffs)
608                 end
609                 if it[:tag] == "create_cube"
610                   basename = File.basename(mol.path || mol.name, ".*")
611               fname1 = Dialog.save_panel("Cube file name", mol.dir || Dir.pwd, basename + ".cube", "Gaussian cube file (*.cube)|*.cube")
612                   if fname1
613                     mol.cubegen(fname1, idx, grid, true)
614                   end
615                 else
616                   mol.create_surface(idx, :npoints=>grid, :color=>color, :thres=>thres, :expand=>expand, :color0=>color0)
617                   mol.show_surface
618                   on_action.call(it)
619                   surface_dialog_attr["hidden"] = 0
620                   on_update_attr.call
621                 end
622           }
623           layout(1,
624             layout(2,
625                   item(:text, :title=>"Orbital Set"),
626                   item(:popup, :tag=>"mo_ao", :subitems=>mo_ao_items, :action=>on_set_action),
627               item(:text, :title=>"Select"),
628               item(:popup, :tag=>"mo", :subitems=>mo_menu, :action=>on_mo_action)),
629                 layout(4,
630                   item(:text, :title=>"Color"),
631                   item(:popup, :tag=>"color", :subitems=>["blue", "red", "green", "yellow", "cyan", "magenta", "black"], :action=>on_action),
632                   item(:text, :title=>"Opacity"),
633                   item(:textfield, :tag=>"opacity", :width=>80, :value=>"0.8", :action=>on_action),
634                   item(:text, :title=>"Threshold"),
635                   item(:textfield, :tag=>"threshold", :width=>80, :value=>"0.05", :action=>on_action),
636                   item(:text, :title=>"Box Limit"),
637                   item(:textfield, :tag=>"expand", :width=>80, :value=>"1.0", :action=>on_action)),
638                 layout(2,
639                   item(:text, :title=>"Number of Grid Points"),
640                   item(:textfield, :tag=>"grid", :width=>120, :value=>"512000", :action=>on_action)),
641             item(:table, :width=>300, :height=>300, :tag=>"table",
642                   :columns=>[["Atom", 60], ["Name", 60], ["Label", 60], ["Coeff", 120]],
643                   :on_count=> lambda { |it| tabvals.count },
644                   :on_get_value=>on_get_value,
645                   :flex=>[0,0,0,0,1,1]),
646                 layout(3,
647                   item(:button, :tag=>"update", :title=>"Update", :action=>on_update),
648                   item(:button, :tag=>"clear", :title=>"Clear", :action=>lambda { |it|
649                     mol.clear_surface
650                         item_with_tag("update")[:enabled] = true
651                         surface_dialog_attr["hidden"] = -1
652                         on_update_attr.call
653                     } ),
654                   item(:button, :tag=>"hide", :title=>"Hide", :action=>lambda { |it|
655                     case surface_dialog_attr["hidden"]
656                         when 0
657                           surface_dialog_attr["hidden"] = 1
658                           mol.hide_surface
659                         when 1
660                           surface_dialog_attr["hidden"] = 0
661                           mol.show_surface
662                         end
663                         on_update_attr.call
664                         } ),
665                   item(:button, :tag=>"create_cube", :title=>"Create Cube", :action=>on_update),
666                   :flex=>[0,1,0,0,0,0]),
667                 :flex=>[0,0,0,0,1,1]
668           )
669           tags.each { |tag|
670             if (val = surface_dialog_attr[tag]) != nil
671                   item_with_tag(tag)[:value] = val
672                 end
673           }
674           mo_idx = surface_dialog_attr["mo"]
675           on_update_attr.call
676           on_set_action.call(item_with_tag("mo_ao"))
677           item_with_tag("mo")[:value] = surface_dialog_attr["mo"] = mo_idx
678           size = self.size
679           set_min_size(size[0], 250)
680           item_with_tag("table")[:refresh] = true
681           show
682     }
683   end
684
685   def ask_graphic_export_scale
686     scale = get_global_settings("global.export_graphic_scale")
687         scale = (scale ? scale.to_i - 1 : 3)
688         bg_color = get_global_settings("global.export_background_color")
689         bg_color = (bg_color ? bg_color.to_i + 1 : 0)
690     hash = Dialog.run("Set Export Properties") {
691           layout(2,
692                 item(:text, :title=>"Resolution:"),
693                 item(:popup, :subitems=>["Screen", "Screenx2", "Screenx3", "Screenx4", "Screenx5"], :tag=>"resolution", :value=>scale),
694                 item(:text, :title=>"Background color:"),
695                 item(:popup, :subitems=>["Same as Screen", "Transparent", "Black", "White"], :tag=>"bg_color", :value=>bg_color))
696         }
697         if hash[:status] == 0
698           set_global_settings("global.export_graphic_scale", (hash["resolution"] + 1).to_s)
699           set_global_settings("global.export_background_color", (hash["bg_color"] - 1).to_s)
700           return 0
701         else
702           return -1
703         end
704   end
705   
706   #  DEBUG
707   def cmd_test
708     $test_dialog = Dialog.new("Test") { item(:text, :title=>"test"); show }
709   end
710   
711 end
712
713 module Kernel
714   def ask_scratch_dir
715     sdir = get_global_settings("global.scratch_dir")
716         while 1
717       p = Dialog.open_panel("Please select scratch directory", sdir, nil, true)
718           if p
719             if p =~ / /
720                   error_message_box("Please avoid path containing a white space.\n" + p.sub(/ /, "<!> <!>"))
721                   sdir = p
722                   next
723                 else
724                   set_global_settings("global.scratch_dir", p)
725                   return p
726             end
727           else
728             return nil
729           end
730         end
731   end
732 end
733
734 register_menu("Assign residue...", :cmd_assign_residue, :non_empty)
735 register_menu("Offset residue...", :cmd_offset_residue, :non_empty)
736 register_menu("Sort by residue", :cmd_sort_by_residue, :non_empty)
737 register_menu("", "")
738 register_menu("Delete Frames...", :cmd_delete_frames, lambda { |m| m && m.nframes > 1 } )
739 register_menu("Reverse Frames...", :cmd_reverse_frames, lambda { |m| m && m.nframes > 1 } )
740 register_menu("Concatenate Frames...", :cmd_concat_frames, lambda { |m| m && m.nframes > 1 } )
741 register_menu("", "")
742 register_menu("Show Energy Window...", :cmd_show_energy, lambda { |m| m && m.property_names.include?("energy") } )
743 register_menu("Show MO Surface...", :cmd_create_surface, lambda { |m| m && m.get_mo_info(:type) != nil } )
744 #register_menu("cmd test", :cmd_test)
745