OSDN Git Service

ee4c7abfbf0093b6a00f8ce857b141b909a7e889
[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                         end
399                         mo_ao_items.push(name2)
400                         mo_ao_keys.push(key2)
401                   end
402                 }
403           end
404           mult = (motype == "UHF" ? 2 : 1)
405           mo_menu = ["1000 (-00.00000000)"]  #  Dummy entry; create later
406           tabvals = []
407           coeffs = nil
408           a_idx_old = -1
409           occ = nil
410           ncomps.times { |i|
411             a_idx, s_idx, label = mol.get_gaussian_component_info(i)
412                 if a_idx_old != a_idx
413                   a_idx_old = a_idx
414                   a = a_idx.to_s
415                   n = mol.atoms[a_idx].name
416                 else
417                   a = n = ""
418                 end
419                 tabvals.push([a, n, label, a_idx])
420           }
421           on_update_attr = lambda {
422             tags.each { |tag|
423                   surface_dialog_attr[tag] = item_with_tag(tag)[:value]
424                 }
425                 it = item_with_tag("hide")
426                 case surface_dialog_attr["hidden"]
427                 when -1
428                   it[:title] = "Hide"
429                   it[:enabled] = false
430                 when 0
431                   it[:title] = "Hide"
432                   it[:enabled] = true
433                 when 1
434                   it[:title] = "Show"
435                   it[:enabled] = true
436                 end
437           }
438           on_get_value = lambda { |it, row, col|
439             if col < 3
440                   tabvals[row][col]
441                 else
442                   if coeffs == nil
443                     if mo_ao == 0
444                       coeffs = mol.get_mo_coefficients(mo_index)
445                     elsif mo_ao == 1
446                       coeffs = (0...ncomps).map { |i| (i == mo_index ? 1.0 : 0.0) }
447                         else
448                           coeffs = nbo["AO/" + mo_ao_keys[mo_ao]].column(mo_index).to_a[0]
449                         end
450                   end
451                   sprintf("%.6f", coeffs[row])
452                 end
453           }
454           h = {"mo"=>nil, "color"=>nil, "opacity"=>nil, "threshold"=>nil, "expand"=>nil, "grid"=>nil}
455           should_update = true
456           on_action = lambda { |it|
457             tag = it[:tag]
458                 value = it[:value]
459                 if tag == "color" || tag == "opacity"
460                   opac = value("opacity").to_f
461                   opac = 0.0 if opac < 0.0
462                   opac = 1.0 if opac > 1.0
463                   col = value("color")
464                   color = coltable[col] + [opac]
465                   color0 = [1,1,1,opac]
466                   mol.set_surface_attr(:color=>color, :color0=>color0)
467                   h[tag] = value
468                 elsif tag == "threshold"
469               thres = it[:value].to_f
470                   thres = 0.001 if thres >= 0.0 && thres < 0.001
471                   thres = -0.001 if thres <= 0.0 && thres > -0.001
472                   mol.set_surface_attr(:thres=>thres)
473                   h[tag] = value
474                 else
475               should_update = false
476               h.each_key { |key|
477                     val = value(key)
478                     if val && h[key] != val
479                       should_update = true
480                       break
481                     end
482                   }
483                   item_with_tag("update")[:enabled] = should_update
484                 end
485                 on_update_attr.call
486           }
487           on_mo_action = lambda { |it|
488             mo = it[:value]
489                 if mo_ao == 0
490                   if motype == "UHF"
491                     mo_index = (mo / 2) + (mo % 2 == 1 ? ncomps : 0) + 1
492                         if mo_index <= alpha || (mo_index > ncomps && mo_index <= ncomps + beta)
493                           occ_new = 1
494                         else
495                           occ_new = 0
496                         end
497                   else
498                     mo_index = mo + 1
499                         if mo_index <= alpha && mo_index <= beta
500                           occ_new = 1
501                         elsif mo_index <= alpha || mo_index <= beta
502                           occ_new = -1
503                         else
504                           occ_new = 0
505                         end
506                   end
507                 else
508                   mo_index = mo
509                   occ_new = occ
510                 end
511                 coeffs = nil
512                 if occ_new != occ
513                   #  Set default color
514                   col = (occ_new == 0 ? 1 : (occ_new == -1 ? 2 : 0))
515                   set_value("color", col)
516                   h["color"] = col
517                   occ = occ_new
518                 end
519                 item_with_tag("table")[:refresh] = true
520             on_action.call(it)
521                 on_update_attr.call
522           }
523           on_set_action = lambda { |it|
524             if mo_ao != it[:value]
525                   mo_ao = it[:value]
526                   if mo_ao == 0
527                     mo_menu = (1..(ncomps * mult)).map { |n|
528                   if motype == "UHF"
529                         i1 = (n - 1) / 2 + 1
530                         i2 = n % 2
531                         c1 = (i2 == 0 ? "B" : "A")
532                         c2 = (i1 > (i2 == 0 ? beta : alpha) ? "*" : "")
533                       else
534                         i1 = n
535                         i2 = 1
536                         c1 = ""
537                                 if i1 > beta && i1 > alpha
538                                   c2 = "*"
539                                 elsif i1 > beta || i1 > alpha
540                                   c2 = "S"
541                                 else
542                                   c2 = ""
543                                 end
544                       end
545                       en = mol.get_mo_energy(i1 + (i2 == 0 ? ncomps : 0))
546                       sprintf("%d%s%s (%.8f)", i1, c1, c2, en)
547                         }
548                   elsif mo_ao == 1
549                     mo_menu = []
550                     ncomps.times { |i|
551                           mo_menu[i] = sprintf("AO%d: %s (%s)", i + 1, tabvals[i][2], mol.atoms[tabvals[i][3]].name)
552                         }
553                   else
554                     mo_menu = []
555                         key = mo_ao_keys[mo_ao]
556                         labels = nbo[key + "_L"]
557                         if labels == nil && key[0] == ?P
558                           labels = nbo[key[1..-1] + "_L"]
559                         end
560                         ncomps.times { |i|
561                           lab = sprintf("%s%d", key, i + 1)
562                           if labels
563                             lab += ":" + labels[i]
564                           end
565                           mo_menu[i] = lab
566                         }
567                   end
568                   it0 = item_with_tag("mo")
569                   it0[:subitems] = mo_menu
570                   it0[:value] = 0
571                   h["mo"] = nil  # "Update" button is forced to be enabled
572                   on_mo_action.call(it0)
573                 end
574                 on_update_attr.call
575           }
576           on_update = lambda { |it|
577             h.each_key { |key|
578                   h[key] = value(key)
579                 }
580                 opac = h["opacity"].to_f
581                 opac = 0.0 if opac < 0.0
582                 opac = 1.0 if opac > 1.0
583                 color = coltable[h["color"]] + [opac]
584                 color0 = [1, 1, 1, opac]
585                 thres = h["threshold"].to_f
586                 thres = 0.001 if thres >= 0.0 && thres < 0.001
587                 thres = -0.001 if thres <= 0.0 && thres > -0.001
588                 expand = h["expand"].to_f
589                 expand = 0.01 if expand < 0.01
590                 expand = 10.0 if expand > 10.0
591                 grid = h["grid"].to_i
592                 if grid > 10000000
593                   grid = 10000000
594                 end
595                 if mo_ao == 0
596                   idx = mo_index
597                 else
598                   idx = 0
599                   mol.set_mo_coefficients(0, 0.0, coeffs)
600                 end
601                 if it[:tag] == "create_cube"
602                   basename = File.basename(mol.path || mol.name, ".*")
603               fname1 = Dialog.save_panel("Cube file name", mol.dir || Dir.pwd, basename + ".cube", "Gaussian cube file (*.cube)|*.cube")
604                   if fname1
605                     mol.cubegen(fname1, idx, grid, true)
606                   end
607                 else
608                   mol.create_surface(idx, :npoints=>grid, :color=>color, :thres=>thres, :expand=>expand, :color0=>color0)
609                   mol.show_surface
610                   on_action.call(it)
611                   surface_dialog_attr["hidden"] = 0
612                   on_update_attr.call
613                 end
614           }
615           layout(1,
616             layout(2,
617                   item(:text, :title=>"Orbital Set"),
618                   item(:popup, :tag=>"mo_ao", :subitems=>mo_ao_items, :action=>on_set_action),
619               item(:text, :title=>"Select"),
620               item(:popup, :tag=>"mo", :subitems=>mo_menu, :action=>on_mo_action)),
621                 layout(4,
622                   item(:text, :title=>"Color"),
623                   item(:popup, :tag=>"color", :subitems=>["blue", "red", "green", "yellow", "cyan", "magenta", "black"], :action=>on_action),
624                   item(:text, :title=>"Opacity"),
625                   item(:textfield, :tag=>"opacity", :width=>80, :value=>"0.8", :action=>on_action),
626                   item(:text, :title=>"Threshold"),
627                   item(:textfield, :tag=>"threshold", :width=>80, :value=>"0.05", :action=>on_action),
628                   item(:text, :title=>"Box Limit"),
629                   item(:textfield, :tag=>"expand", :width=>80, :value=>"1.0", :action=>on_action)),
630                 layout(2,
631                   item(:text, :title=>"Number of Grid Points"),
632                   item(:textfield, :tag=>"grid", :width=>120, :value=>"512000", :action=>on_action)),
633             item(:table, :width=>300, :height=>300, :tag=>"table",
634                   :columns=>[["Atom", 60], ["Name", 60], ["Label", 60], ["Coeff", 120]],
635                   :on_count=> lambda { |it| tabvals.count },
636                   :on_get_value=>on_get_value,
637                   :flex=>[0,0,0,0,1,1]),
638                 layout(3,
639                   item(:button, :tag=>"update", :title=>"Update", :action=>on_update),
640                   item(:button, :tag=>"clear", :title=>"Clear", :action=>lambda { |it|
641                     mol.clear_surface
642                         item_with_tag("update")[:enabled] = true
643                         surface_dialog_attr["hidden"] = -1
644                         on_update_attr.call
645                     } ),
646                   item(:button, :tag=>"hide", :title=>"Hide", :action=>lambda { |it|
647                     case surface_dialog_attr["hidden"]
648                         when 0
649                           surface_dialog_attr["hidden"] = 1
650                           mol.hide_surface
651                         when 1
652                           surface_dialog_attr["hidden"] = 0
653                           mol.show_surface
654                         end
655                         on_update_attr.call
656                         } ),
657                   item(:button, :tag=>"create_cube", :title=>"Create Cube", :action=>on_update),
658                   :flex=>[0,1,0,0,0,0]),
659                 :flex=>[0,0,0,0,1,1]
660           )
661           tags.each { |tag|
662             if (val = surface_dialog_attr[tag]) != nil
663                   item_with_tag(tag)[:value] = val
664                 end
665           }
666           mo_idx = surface_dialog_attr["mo"]
667           on_update_attr.call
668           on_set_action.call(item_with_tag("mo_ao"))
669           item_with_tag("mo")[:value] = surface_dialog_attr["mo"] = mo_idx
670           size = self.size
671           set_min_size(size[0], 250)
672           item_with_tag("table")[:refresh] = true
673           show
674     }
675   end
676
677   def ask_graphic_export_scale
678     scale = get_global_settings("global.export_graphic_scale")
679         scale = (scale ? scale.to_i - 1 : 3)
680         bg_color = get_global_settings("global.export_background_color")
681         bg_color = (bg_color ? bg_color.to_i + 1 : 0)
682     hash = Dialog.run("Set Export Properties") {
683           layout(2,
684                 item(:text, :title=>"Resolution:"),
685                 item(:popup, :subitems=>["Screen", "Screenx2", "Screenx3", "Screenx4", "Screenx5"], :tag=>"resolution", :value=>scale),
686                 item(:text, :title=>"Background color:"),
687                 item(:popup, :subitems=>["Same as Screen", "Transparent", "Black", "White"], :tag=>"bg_color", :value=>bg_color))
688         }
689         if hash[:status] == 0
690           set_global_settings("global.export_graphic_scale", (hash["resolution"] + 1).to_s)
691           set_global_settings("global.export_background_color", (hash["bg_color"] - 1).to_s)
692           return 0
693         else
694           return -1
695         end
696   end
697   
698   #  DEBUG
699   def cmd_test
700     $test_dialog = Dialog.new("Test") { item(:text, :title=>"test"); show }
701   end
702   
703 end
704
705 module Kernel
706   def ask_scratch_dir
707     sdir = get_global_settings("global.scratch_dir")
708         while 1
709       p = Dialog.open_panel("Please select scratch directory", sdir, nil, true)
710           if p
711             if p =~ / /
712                   error_message_box("Please avoid path containing a white space.\n" + p.sub(/ /, "<!> <!>"))
713                   sdir = p
714                   next
715                 else
716                   set_global_settings("global.scratch_dir", p)
717                   return p
718             end
719           else
720             return nil
721           end
722         end
723   end
724 end
725
726 register_menu("Assign residue...", :cmd_assign_residue, :non_empty)
727 register_menu("Offset residue...", :cmd_offset_residue, :non_empty)
728 register_menu("Sort by residue", :cmd_sort_by_residue, :non_empty)
729 register_menu("", "")
730 register_menu("Delete Frames...", :cmd_delete_frames, lambda { |m| m && m.nframes > 1 } )
731 register_menu("Reverse Frames...", :cmd_reverse_frames, lambda { |m| m && m.nframes > 1 } )
732 register_menu("Concatenate Frames...", :cmd_concat_frames, lambda { |m| m && m.nframes > 1 } )
733 register_menu("", "")
734 register_menu("Show Energy Window...", :cmd_show_energy, lambda { |m| m && m.property_names.include?("energy") } )
735 register_menu("Show MO Surface...", :cmd_create_surface, lambda { |m| m && m.get_mo_info(:type) != nil } )
736 #register_menu("cmd test", :cmd_test)
737