/ lib / python / gladevcp / hal_actions.py
hal_actions.py
  1  #!/usr/bin/env python
  2  # vim: sts=4 sw=4 et
  3  # GladeVcp actions
  4  #
  5  # Copyright (c) 2010  Pavel Shramov <shramov@mexmat.net>
  6  #
  7  # This program is free software: you can redistribute it and/or modify
  8  # it under the terms of the GNU General Public License as published by
  9  # the Free Software Foundation, either version 2 of the License, or
 10  # (at your option) any later version.
 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  import gobject
 18  import gtk
 19  import os
 20  import time
 21  import re, string
 22  
 23  from hal_widgets import _HalWidgetBase
 24  import linuxcnc
 25  from hal_glib import GStat
 26  
 27  _ = lambda x: x
 28  
 29  class _EMCStaticHolder:
 30      def __init__(self):
 31          # Delay init...
 32          self.linuxcnc = None
 33          self.stat = None
 34          self.gstat = None
 35  
 36      def get(self):
 37          if not self.linuxcnc:
 38              self.linuxcnc = linuxcnc.command()
 39          if not self.gstat:
 40              self.gstat = GStat()
 41          return self.linuxcnc, self.gstat.stat, self.gstat
 42  
 43  class _EMCStatic:
 44      holder = _EMCStaticHolder()
 45      def get(self):
 46          return self.holder.get()
 47  
 48  class _EMC_ActionBase(_HalWidgetBase):
 49      _gproperties = {'name': (gobject.TYPE_STRING, 'Name', 'Action name', "",
 50                               gobject.PARAM_READWRITE|gobject.PARAM_CONSTRUCT)
 51                     }
 52  
 53      linuxcnc_static = _EMCStatic()
 54  
 55      def _hal_init(self):
 56          self.linuxcnc, self.stat, self.gstat = self.linuxcnc_static.get()
 57          self._stop_emission = False
 58          # if 'NO_FORCE_HOMING' is true, MDI  commands are allowed before homing.
 59          inifile = os.environ.get('INI_FILE_NAME', '/dev/null')
 60          ini = linuxcnc.ini(inifile)
 61          self.no_f_home = int(ini.find("TRAJ", "NO_FORCE_HOMING") or 0)
 62  
 63      def machine_on(self):
 64          self.stat.poll()
 65          return self.stat.task_state > linuxcnc.STATE_OFF
 66  
 67      def is_auto_mode(self):
 68          self.stat.poll()
 69          print self.stat.task_mode, linuxcnc.MODE_AUTO
 70          return self.stat.task_mode == linuxcnc.MODE_AUTO
 71  
 72      def is_file_loaded(self):
 73          self.stat.poll()
 74          print "file name:",self.stat.file
 75          if self.stat.file:
 76              return True
 77          else:
 78              return False
 79  
 80      def is_all_homed(self):
 81          self.stat.poll()
 82          homed_count = 0
 83          for i,h in enumerate(self.stat.homed):
 84              #Don't worry about joint to axis mapping
 85              if h: homed_count +=1
 86          print self.stat.joints
 87          if homed_count == self.stat.joints:
 88              return True
 89          return False
 90  
 91      def no_home_required(self):
 92          return self.no_f_home
 93  
 94      def safe_handler(self, f):
 95          def _f(self, *a, **kw):
 96              if self._stop_emission:
 97                  return
 98              return f(self, *a, **kw)
 99          return _f
100  
101      def set_active_safe(self, active):
102          self._stop_emission = True
103          self.set_active(active)
104          self._stop_emission = False
105  
106      def do_get_property(self, property):
107          name = property.name.replace('-', '_')
108  
109          if name == 'name':
110              return self.get_name()
111          elif name == 'label':
112              return self.get_label()
113          elif name == 'tooltip':
114              return self.get_tooltip()
115          elif name == 'stock_id':
116              return self.get_stock_id()
117          else:
118              raise AttributeError("Unknown property: %s" % property.name)
119  
120      def do_set_property(self, property, value):
121          name = property.name.replace('-', '_')
122  
123          if name == 'name':
124              if value:
125                  self.set_name(value)
126          elif name == 'label':
127              self.set_label(value)
128          elif name == 'tooltip':
129              self.set_tooltip(value)
130          elif name == 'stock_id':
131              self.set_stock_id(value)
132          else:
133              raise AttributeError("Unknown property: %s" % property.name)
134          return True
135  
136  class _EMC_Action(gtk.Action, _EMC_ActionBase):
137      __gproperties__ = _EMC_ActionBase._gproperties
138      def __init__(self, name=None):
139          gtk.Action.__init__(self, None, None, None, None)
140          self._stop_emission = False
141          self.connect('activate', self.safe_handler(self.on_activate))
142  
143      def set_active_safe(self, a): return #XXX: Override set_active with nop
144  
145      def on_activate(self, w):
146          return True
147  
148  class _EMC_ToggleAction(gtk.ToggleAction, _EMC_ActionBase):
149      __gproperties__ = _EMC_ActionBase._gproperties
150      def __init__(self, name=None):
151          gtk.ToggleAction.__init__(self, None, None, None, None)
152          self._stop_emission = False
153          self.connect('toggled', self.safe_handler(self.on_toggled))
154  
155      # XXX: Override nop in _EMC_Action
156      set_active_safe = _EMC_ActionBase.set_active_safe
157  
158      def on_toggled(self, w):
159          return True
160  
161  class _EMC_RadioAction(gtk.RadioAction, _EMC_ToggleAction):
162      __gproperties__ = _EMC_ToggleAction._gproperties
163      def __init__(self, name=None):
164          gtk.RadioAction.__init__(self, None, None, None, None, 0)
165          self._stop_emission = False
166          self.connect('toggled', self.safe_handler(self.on_toggled))
167  
168      def on_toggled(self, w):
169          if not w.get_active():
170              return
171          return self.on_activate(w)
172  
173  class EMC_Stat(GStat, _EMC_ActionBase):
174      __gtype_name__ = 'EMC_Stat'
175      def __init__(self):
176          stat = self.linuxcnc_static.get()[1]
177          GStat.__init__(self, stat)
178  
179      def _hal_init(self):
180          pass
181  
182  def _action(klass, f, *a, **kw):
183      class _C(_EMC_Action):
184          __gtype_name__ = klass
185          def on_activate(self, w):
186              print klass
187              f(self, *a, **kw)
188      return _C
189  
190  EMC_Action_ESTOP = _action('EMC_Action_ESTOP', lambda s: s.linuxcnc.state(linuxcnc.STATE_ESTOP))
191  EMC_Action_ESTOP_RESET = _action('EMC_Action_ESTOP_RESET', lambda s: s.linuxcnc.state(linuxcnc.STATE_ESTOP_RESET))
192  EMC_Action_ON    = _action('EMC_Action_ON', lambda s: s.linuxcnc.state(linuxcnc.STATE_ON))
193  EMC_Action_OFF   = _action('EMC_Action_OFF', lambda s: s.linuxcnc.state(linuxcnc.STATE_OFF))
194  
195  class EMC_ToggleAction_ESTOP(_EMC_ToggleAction):
196      __gtype_name__ = 'EMC_ToggleAction_ESTOP'
197      def _hal_init(self):
198          _EMC_ToggleAction._hal_init(self)
199  
200          self.set_active_safe(True)
201  
202          self.gstat.connect('state-estop', lambda w: self.set_active_safe(True))
203          self.gstat.connect('state-estop-reset', lambda w: self.set_active_safe(False))
204  
205      def on_toggled(self, w):
206          if self.get_active():
207              print 'Issuing ESTOP'
208              self.linuxcnc.state(linuxcnc.STATE_ESTOP)
209          else:
210              print 'Issuing ESTOP RESET'
211              self.linuxcnc.state(linuxcnc.STATE_ESTOP_RESET)
212  
213  class EMC_ToggleAction_Power(_EMC_ToggleAction):
214      __gtype_name__ = 'EMC_ToggleAction_Power'
215      def _hal_init(self):
216          _EMC_ToggleAction._hal_init(self)
217  
218          self.set_active_safe(False)
219          self.set_sensitive(False)
220  
221          self.gstat.connect('state-on',  lambda w: self.set_active_safe(True))
222          self.gstat.connect('state-off', lambda w: self.set_active_safe(False))
223          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
224          self.gstat.connect('state-estop-reset', lambda w: self.set_sensitive(True))
225  
226      def on_toggled(self, w):
227          if self.get_active():
228              print 'Issuing ON'
229              self.linuxcnc.state(linuxcnc.STATE_ON)
230          else:
231              print 'Issuing OFF'
232              self.linuxcnc.state(linuxcnc.STATE_OFF)
233  
234  class EMC_RadioAction_ESTOP(_EMC_RadioAction):
235      __gtype_name__ = 'EMC_RadioAction_ESTOP'
236      def _hal_init(self):
237          _EMC_RadioAction._hal_init(self)
238  
239          self.set_active_safe(True)
240  
241          self.gstat.connect('state-estop', lambda w: self.set_active_safe(True))
242  
243      def on_activate(self, w):
244          self.linuxcnc.state(linuxcnc.STATE_ESTOP)
245  
246  class EMC_RadioAction_ESTOP_RESET(_EMC_RadioAction):
247      __gtype_name__ = 'EMC_RadioAction_ESTOP_RESET'
248      def _hal_init(self):
249          _EMC_RadioAction._hal_init(self)
250  
251          self.set_active_safe(False)
252  
253          self.gstat.connect('state-estop-reset', lambda w: self.set_active_safe(True))
254  
255      def on_activate(self, w):
256          self.linuxcnc.state(linuxcnc.STATE_ESTOP_RESET)
257  
258  class EMC_RadioAction_ON(_EMC_RadioAction):
259      __gtype_name__ = 'EMC_RadioAction_ON'
260      def _hal_init(self):
261          _EMC_RadioAction._hal_init(self)
262  
263          self.set_active_safe(True)
264  
265          self.gstat.connect('state-on',  lambda w: self.set_active_safe(True))
266          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
267          self.gstat.connect('state-estop-reset', lambda w: self.set_sensitive(True))
268  
269      def on_activate(self, w):
270          self.linuxcnc.state(linuxcnc.STATE_ON)
271  
272  class EMC_RadioAction_OFF(_EMC_RadioAction):
273      __gtype_name__ = 'EMC_RadioAction_OFF'
274      def _hal_init(self):
275          _EMC_RadioAction._hal_init(self)
276  
277          self.set_active_safe(False)
278  
279          self.gstat.connect('state-off', lambda w: self.set_active_safe(True))
280          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
281          self.gstat.connect('state-estop-reset', lambda w: self.set_sensitive(True))
282  
283      def on_activate(self, w):
284          self.linuxcnc.state(linuxcnc.STATE_OFF)
285  
286  def running(s, do_poll=True):
287      if do_poll: s.poll()
288      return s.task_mode == linuxcnc.MODE_AUTO and s.interp_state != linuxcnc.INTERP_IDLE
289  
290  def ensure_mode(s, c, *modes):
291      s.poll()
292      if not modes: return False
293      if s.task_mode in modes: return True
294      if running(s, do_poll=False): return False
295      c.mode(modes[0])
296      c.wait_complete()
297      return True
298  
299  class EMC_Action_Python(_EMC_Action):
300      __gtype_name__ = 'EMC_Action_Python'
301      command = gobject.property(type=str, default='', nick='Python Command')
302      is_homed = gobject.property(type=bool, default=True, nick='Must Be Homed',
303                                      blurb='Machine Must be homed for widgets to be sensitive to input')
304      is_on = gobject.property(type=bool, default=True, nick='Must Be On',
305                                      blurb='Machine Must be On for widgets to be sensitive to input')
306      is_idle = gobject.property(type=bool, default=True, nick='Must Be Idle',
307                                      blurb='Machine Must be Idle for widgets to be sensitive to input')
308      requires_manual = gobject.property(type=bool, default=False, nick='Preset Manual Mode',
309                                      blurb='Preset Manual Mode before command')
310      requires_mdi = gobject.property(type=bool, default=False, nick='Preset MDI Mode',
311                                      blurb='Preset MDI Mode before command')
312      requires_auto = gobject.property(type=bool, default=False, nick='Preset Auto Mode',
313                                      blurb='Preset Auto Mode before command')
314  
315      def _hal_init(self):
316          _EMC_Action._hal_init(self)
317          self.set_sensitive(False)
318          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
319          if self.is_on:
320              self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
321          if self.is_homed:
322              self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on() and ( self.is_all_homed() or self.no_home_required() ) ))
323          else:
324              self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on()) )
325          if self.is_idle:
326              self.gstat.connect('interp-run', lambda w: self.set_sensitive(False))
327          if self.is_homed:
328              self.gstat.connect('all-homed', lambda w: self.set_sensitive(self.machine_on()))
329  
330      def on_activate(self, w):
331          self._globalParameter = { 'EXT':self._panel_instance.get_handler_obj(),
332                                    'GSTAT':self.gstat,'CMD':self.linuxcnc,'STAT':self.stat}
333          self._localsParameter = {'dir': dir, 'self': self,'linuxcnc':linuxcnc}
334          if self.requires_manual:
335              ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_MAN)
336          elif self.requires_mdi:
337              ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_MDI)
338          elif self.requires_auto:
339              ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_AUTO)
340          exec(self.command, self._globalParameter, self._localsParameter)
341  
342  class EMC_Action_Run(_EMC_Action):
343      __gtype_name__ = 'EMC_Action_Run'
344      program_start_line = gobject.property(type=int, default=0, minimum=0, nick='Restart line',
345                                      blurb='Restart line number-Usually 0 - program start')
346      reset_line = gobject.property(type=int, default=0, minimum=0, nick='Restart line after restarting once',
347                                      blurb='Line number that will be set afterthe next restart. -usually 0 - program start')
348  
349      def set_restart_line(self,line,resetline=0):
350          self.program_start_line = line
351          self.reset_line = resetline
352  
353      def on_activate(self, w):
354          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_AUTO)
355          self.linuxcnc.auto(linuxcnc.AUTO_RUN, self.program_start_line)
356          self.program_start_line = self.reset_line
357  
358  class EMC_Action_Step(_EMC_Action):
359      __gtype_name__ = 'EMC_Action_Step'
360      def _hal_init(self):
361          _EMC_Action._hal_init(self)
362  
363          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
364          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
365          self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on()))
366  
367      def on_activate(self, w):
368          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_AUTO)
369          self.linuxcnc.auto(linuxcnc.AUTO_STEP)
370  
371  class EMC_Action_Pause(_EMC_Action):
372      __gtype_name__ = 'EMC_Action_Pause'
373      def on_activate(self, w):
374          self.stat.poll()
375          if self.stat.task_mode != linuxcnc.MODE_AUTO or\
376                  self.stat.interp_state not in (linuxcnc.INTERP_READING, linuxcnc.INTERP_WAITING):
377              return
378          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_AUTO)
379          self.linuxcnc.auto(linuxcnc.AUTO_PAUSE)
380  
381  class EMC_Action_Resume(_EMC_Action):
382      __gtype_name__ = 'EMC_Action_Resume'
383      def on_activate(self, w):
384          print "RESUME"
385          self.stat.poll()
386          if not self.stat.paused:
387              return
388          if self.stat.task_mode not in (linuxcnc.MODE_AUTO, linuxcnc.MODE_MDI):
389              return
390          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_AUTO, linuxcnc.MODE_MDI)
391          self.linuxcnc.auto(linuxcnc.AUTO_RESUME)
392  
393  class EMC_Action_Stop(_EMC_Action):
394      __gtype_name__ = 'EMC_Action_Stop'
395      def on_activate(self, w):
396          self.linuxcnc.abort()
397          self.linuxcnc.wait_complete()
398  
399  class EMC_ToggleAction_Run(_EMC_ToggleAction, EMC_Action_Run):
400      __gtype_name__ = 'EMC_ToggleAction_Run'
401      program_start_line = gobject.property(type=int, default=0, minimum=0, nick='Restart line',
402                                      blurb='Restart line number-Usually 0 - program start')
403      reset_line = gobject.property(type=int, default=0, minimum=0, nick='Restart line after restarting once',
404                                      blurb='Line number that will be set afterthe next restart. -usually 0 - program start')
405      def _hal_init(self):
406          _EMC_ToggleAction._hal_init(self)
407  
408          self.set_active_safe(False)
409          self.set_sensitive(False)
410  
411          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
412          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
413  
414          self.gstat.connect( 'interp-idle', lambda w: self.set_sensitive( self.machine_on() and ( self.is_all_homed() or self.no_home_required() ) and self.is_file_loaded() ) )
415          self.gstat.connect('interp-idle', lambda w: self.set_active_safe(False))
416          self.gstat.connect('interp-run', lambda w: self.set_sensitive(False))
417          self.gstat.connect('interp-run', lambda w: self.set_active_safe(True))
418          self.gstat.connect('all-homed', lambda w: self.set_sensitive( self.machine_on() and self.is_file_loaded() ))
419          self.gstat.connect('file-loaded', self.file_loaded_check)
420  
421      def file_loaded_check(self,widget,filename):
422          self.set_sensitive( self.machine_on() and (self.is_all_homed() or self.no_home_required()) )
423  
424      def set_restart_line(self,line,resetline=0):
425          self.program_start_line = line
426          self.reset_line = resetline
427  
428      def on_toggled(self, w):
429          if self.get_active():
430              return self.on_activate(w)
431  
432  class EMC_ToggleAction_Stop(_EMC_ToggleAction, EMC_Action_Stop):
433      __gtype_name__ = "EMC_ToggleAction_Stop"
434      def _hal_init(self):
435          _EMC_ToggleAction._hal_init(self)
436  
437          self.set_active_safe(True)
438          self.set_sensitive(False)
439  
440          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
441          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
442  
443          self.gstat.connect('interp-idle', lambda w: self.set_sensitive(False))
444          self.gstat.connect('interp-idle', lambda w: self.set_active_safe(True))
445          self.gstat.connect('interp-run', lambda w: self.set_sensitive(self.machine_on()))
446          self.gstat.connect('interp-run', lambda w: self.set_active_safe(False))
447  
448      def on_toggled(self, w):
449          if self.get_active():
450              return self.on_activate(w)
451  
452  class EMC_ToggleAction_Pause(_EMC_ToggleAction, EMC_Action_Pause):
453      __gtype_name__ = "EMC_ToggleAction_Pause"
454      def _hal_init(self):
455          _EMC_ToggleAction._hal_init(self)
456  
457          self.resume = EMC_Action_Resume()
458          self.resume._hal_init()
459  
460          self.set_active_safe(True)
461          self.set_sensitive(False)
462  
463          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
464          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
465  
466          self.gstat.connect('interp-idle', lambda w: self.set_sensitive(False))
467          self.gstat.connect('interp-idle', lambda w: self.set_active_safe(False))
468          self.gstat.connect('interp-run', lambda w: self.set_sensitive(self.machine_on()))
469          self.gstat.connect('interp-run', lambda w: self.set_active_safe(False))
470          self.gstat.connect('interp-paused', lambda w: self.set_active_safe(True))
471          self.gstat.connect('interp-waiting', lambda w: self.set_active_safe(False))
472  
473      def on_toggled(self, w):
474          if self.get_active():
475              return self.on_activate(w)
476          else:
477              return self.resume.on_activate(self.resume)
478  
479  class HalTemplate(string.Template):
480      idpattern = '[_a-z][-._a-z0-9]*'
481  
482  class FloatComp:
483      def __init__(self, comp):
484          self.comp = comp
485      def __getitem__(self, k):
486          v = float(self.comp[k])
487          return "%f" % v
488  
489  class EMC_Action_MDI(_EMC_Action):
490      __gtype_name__ = 'EMC_Action_MDI'
491      command = gobject.property(type=str, default='', nick='MDI Command')
492  
493      def _hal_init(self):
494          _EMC_Action._hal_init(self)
495          self.set_sensitive(False)
496          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
497          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
498          self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on() and ( self.is_all_homed() or self.no_home_required() ) ))
499          self.gstat.connect('interp-run', lambda w: self.set_sensitive(False))
500          self.gstat.connect('all-homed', lambda w: self.set_sensitive(self.machine_on()))
501  
502      def on_activate(self, w):
503          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_MDI)
504          template = HalTemplate(self.command)
505          cmd = template.substitute(FloatComp(self.hal))
506          self.linuxcnc.mdi(cmd)
507  
508  class EMC_ToggleAction_MDI(_EMC_ToggleAction, EMC_Action_MDI):
509      __gtype_name__ = 'EMC_ToggleAction_MDI'
510      __gsignals__ = {
511          'mdi-command-start': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),
512          'mdi-command-stop':  (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),
513      }
514      command = gobject.property(type=str, default='', nick='MDI Command')
515  
516      def _hal_init(self):
517          _EMC_ToggleAction._hal_init(self)
518          EMC_Action_MDI._hal_init(self)
519  
520      def on_toggled(self, w):
521          if not self.get_active():
522              return
523          self.set_sensitive(False)
524          self.emit('mdi-command-start')
525          self.on_activate(w)
526          gobject.timeout_add(100, self.wait_complete)
527  
528      def wait_complete(self):
529          if self.linuxcnc.wait_complete(0) in [-1, linuxcnc.RCS_EXEC]:
530              return True
531          self.emit('mdi-command-stop')
532          self.set_active_safe(False)
533          self.set_sensitive(self.machine_on())
534          return False
535  
536  class EMC_Action_UnHome(_EMC_Action):
537      __gtype_name__ = 'EMC_Action_Unhome'
538      axis = gobject.property(type=int, default=-1, minimum=-1, nick='Axis',
539                                      blurb='Axis to unhome. -1 to unhome all')
540      def _hal_init(self):
541          _EMC_Action._hal_init(self)
542          self.set_sensitive(False)
543          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
544          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
545          self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on()))
546          self.gstat.connect('interp-run', lambda w: self.set_sensitive(False))
547  
548      def on_activate(self, w):
549          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_MANUAL)
550          self.linuxcnc.teleop_enable(False)
551          self.linuxcnc.unhome(self.axis)
552  
553  def prompt_areyousure(type, message, secondary=None):
554      dialog = gtk.MessageDialog(None, 0, type, gtk.BUTTONS_YES_NO, message)
555      if secondary:
556          dialog.format_secondary_text(secondary)
557      r = dialog.run()
558      dialog.destroy()
559      return r == gtk.RESPONSE_YES
560  
561  class EMC_Action_Home(_EMC_Action):
562      __gtype_name__ = 'EMC_Action_Home'
563      axis = gobject.property(type=int, default=-1, minimum=-1, nick='Axis',
564                                      blurb='Axis to home. -1 to home all')
565      confirm_homed = gobject.property(type=bool, default=False, nick='Confirm rehoming',
566                                       blurb='Ask user if axis is already homed')
567      def _hal_init(self):
568          _EMC_Action._hal_init(self)
569          self.set_sensitive(False)
570          self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
571          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
572          self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on()))
573          self.gstat.connect('interp-run', lambda w: self.set_sensitive(False))
574  
575      def homed(self):
576          if self.axis != -1:
577              return self.stat.homed[self.axis]
578          for i,h in enumerate(self.stat.homed):
579              if h and self.stat.axis_mask & (1<<i):
580                  return True
581  
582      def on_activate(self, w):
583          #if not manual_ok(): return
584          ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_MANUAL)
585          if self.confirm_homed and self.homed():
586              if not prompt_areyousure(gtk.MESSAGE_WARNING,
587                              _("Axis is already homed, are you sure you want to re-home?")):
588                  return
589          self.linuxcnc.teleop_enable(False)
590          self.linuxcnc.home(self.axis)
591  
592  
593  class State_Sensitive_Table(gtk.Table, _EMC_ActionBase):
594      __gtype_name__ = "State_Sensitive_Table"
595      is_homed = gobject.property(type=bool, default=True, nick='Must Be Homed',
596                                      blurb='Machine Must be homed for widgets to be sensitive to input')
597      is_on = gobject.property(type=bool, default=True, nick='Must Be On',
598                                      blurb='Machine Must be On for widgets to be sensitive to input')
599      is_idle = gobject.property(type=bool, default=True, nick='Must Be Idle',
600                                      blurb='Machine Must be Idle for widgets to be sensitive to input')
601  
602      def _hal_init(self):
603          _EMC_ActionBase._hal_init(self)
604          self.set_sensitive(False)
605          self.gstat.connect('state-estop', lambda w: self.set_sensitive(False))
606          if self.is_on:
607              self.gstat.connect('state-off', lambda w: self.set_sensitive(False))
608          if self.is_homed:
609              self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on() and ( self.is_all_homed() or self.no_home_required() ) ))
610          else:
611              self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on()) )
612          if self.is_idle:
613              self.gstat.connect('interp-run', lambda w: self.set_sensitive(False))
614          if self.is_homed:
615              self.gstat.connect('all-homed', lambda w: self.set_sensitive(self.machine_on()))