macro_widget.py
1 #!/usr/bin/env python 2 # vim: sts=4 sw=4 et 3 # GladeVcp Macro widget 4 # 5 # Based on hal MDI history widget 6 # Copyright (c) 2011 Pavel Shramov <shramov@mexmat.net> 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, either version 2 of the License, or 11 # (at your option) any later version. 12 # 13 # This program is distributed in the hope that it will be useful, 14 # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 # GNU General Public License for more details. 17 18 import os, time, string 19 20 import gobject, gtk 21 22 from hal_widgets import _HalWidgetBase 23 import linuxcnc 24 from hal_glib import GStat 25 from hal_actions import _EMC_ActionBase, ensure_mode 26 # path to TCL for external programs eg. halshow 27 try: 28 TCLPATH = os.environ['LINUXCNC_TCL_DIR'] 29 except: 30 pass 31 32 class MacroSelect(gtk.VBox, _EMC_ActionBase): 33 __gtype_name__ = 'MacroSelect' 34 __gsignals__ = { 35 'macro-submitted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,gobject.TYPE_STRING,)), 36 } 37 38 def __init__(self, *a, **kw): 39 gtk.VBox.__init__(self, *a, **kw) 40 self.gstat = GStat() 41 # if 'NO_FORCE_HOMING' is true, MDI commands are allowed before homing. 42 try: 43 inifile = os.environ.get('INI_FILE_NAME', '/dev/null') 44 self.ini = linuxcnc.ini(inifile) 45 no_home_required = int(self.ini.find("TRAJ", "NO_FORCE_HOMING") or 0) 46 macros = self.inifile.findall("MACROS", "MACRO") 47 sub_path = self.inifile.find("RS274NGC", "SUBROUTINE_PATH")or '~/linuxcnc/nc_files/macros' 48 except: 49 no_home_required = 1 50 macros = None 51 sub_path = '~/linuxcnc/nc_files/macros' 52 53 #path = self.ini.find('DISPLAY', 'MDI_HISTORY_FILE') or '~/.axis_mdi_history' 54 self.foldername = os.path.expanduser(sub_path) 55 56 self.model = gtk.ListStore(str) 57 58 self.tv = gtk.TreeView() 59 self.tv.set_model(self.model) 60 self.cell = gtk.CellRendererText() 61 62 self.col = gtk.TreeViewColumn("Macro Commands") 63 self.col.pack_start(self.cell, True) 64 self.col.add_attribute(self.cell, 'text', 0) 65 66 self.tv.append_column(self.col) 67 self.tv.set_search_column(0) 68 self.tv.set_reorderable(False) 69 self.tv.set_headers_visible(True) 70 71 scroll = gtk.ScrolledWindow() 72 scroll.add(self.tv) 73 scroll.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC 74 scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC 75 76 self.entry = gtk.Entry() 77 self.entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, 'gtk-ok') 78 79 self.entry.connect('activate', self.submit) 80 self.entry.connect('icon-press', self.submit) 81 self.tv.connect('cursor-changed', self.select) 82 self.tv.connect('key_press_event', self.on_key_press_event) 83 self.tv.connect('button_press_event', self.on_button_press_event) 84 85 self.pack_start(scroll, True) 86 self.pack_start(self.entry, False) 87 self.gstat.connect('state-off', lambda w: self.set_sensitive(False)) 88 self.gstat.connect('state-estop', lambda w: self.set_sensitive(False)) 89 self.gstat.connect('interp-idle', lambda w: self.set_sensitive(self.machine_on() and ( self.is_all_homed() or no_home_required ) )) 90 self.gstat.connect('interp-run', lambda w: self.set_sensitive(not self.is_auto_mode())) 91 self.gstat.connect('all-homed', lambda w: self.set_sensitive(self.machine_on())) 92 self.reload() 93 self.show_all() 94 95 def reload(self): 96 self.model.clear() 97 files = [] 98 try: 99 for f in os.listdir(self.foldername): 100 if f.endswith('.ngc'): 101 with open(os.path.join(self.foldername, f), 'r') as temp: 102 first_line = temp.readline().strip() 103 print first_line 104 if 'MACROCOMMAND' in first_line: 105 files.append(first_line.strip('; MACROCOMMAND=')) 106 except: 107 pass 108 lines = filter(bool, files) 109 for l in lines: 110 self.model.append((l,)) 111 path = (len(lines)-1,) 112 self.tv.scroll_to_cell(path) 113 self.tv.set_cursor(path) 114 self.entry.set_text('') 115 116 def submit(self, *a): 117 cmd = self.entry.get_text() 118 if cmd == 'HALMETER': 119 self.load_halmeter() 120 return 121 elif cmd == 'STATUS': 122 self.load_status() 123 return 124 elif cmd == 'HALSHOW': 125 self.load_halshow() 126 return 127 if not cmd: 128 return 129 #ensure_mode(self.stat, self.linuxcnc, linuxcnc.MODE_MDI) 130 name = cmd.split() 131 path = self.foldername+ "/" + name[0] + ".ngc" 132 self.emit('macro-submitted',path,cmd) 133 134 #self.linuxcnc.mdi(cmd) 135 136 self.entry.set_text('') 137 self.entry.grab_focus() 138 139 def select(self, w): 140 self.entry.set_text('') 141 142 def on_key_press_event(self,w,event): 143 idx = w.get_cursor()[0] 144 if idx is None: 145 return True 146 if gtk.gdk.keyval_name(event.keyval) == 'Return': 147 self.entry.set_text(self.model[idx][0]) 148 self.entry.grab_focus() 149 return True 150 151 def on_button_press_event(self,w,event): 152 idx = w.get_cursor()[0] 153 if idx is None: 154 return True 155 self.entry.set_text(self.model[idx][0]) 156 157 def load_halmeter(self): 158 p = os.popen("halmeter &") 159 def load_status(self): 160 p = os.popen("linuxcnctop > /dev/null &","w") 161 def load_halshow(self): 162 try: 163 p = os.popen("tclsh %s/bin/halshow.tcl &" % (TCLPATH)) 164 except: 165 self.entry.set_text('ERROR loading halshow') 166 167 # for testing without glade editor: 168 # Must linuxcnc running to see anything 169 def main(filename = None): 170 def macro_callback(widget,path,cmd): 171 print cmd,path 172 173 window = gtk.Dialog("Macro Test dialog", 174 None, 175 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, 176 (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, 177 gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) 178 widget = MacroSelect() 179 widget.connect("macro-submitted",macro_callback) 180 window.vbox.add(widget) 181 window.connect("destroy", gtk.main_quit) 182 window.show_all() 183 response = window.run() 184 if response == gtk.RESPONSE_ACCEPT: 185 print "True" 186 else: 187 print "False" 188 189 if __name__ == "__main__": 190 main() 191