import sys, os BASE = os.environ['EMC2_HOME'] sys.path.insert(0, os.path.join(BASE, "lib", "python")) import math def _(s): return s def ui(): import Tkinter import pickle import nf import rs274.options import os app = Tkinter.Tk() rs274.options.install(app) app.tk.call("source", os.path.join(BASE, "share", "axis", "tcl", "combobox.tcl")) app.wm_title(_("Circular Holes")) app.wm_iconname(_("Circular Holes")) prev = Tkinter.Canvas(app, width=200, height=200) f = Tkinter.Frame(app) b = Tkinter.Frame(app) prev.grid(row=0, column=0, sticky="nw") f.grid(row=0, column=1, sticky="nw") b.grid(row=1, column=0, columnspan=2, sticky="ne") validate_float = "expr {[regexp {^-?([0-9]+(\.[0-9]*)?|\.[0-9]+|)$} %P]}" validate_int = "expr {[regexp {^-?([0-9]+|)$} %P]}" validate_posfloat = "expr {[regexp {^?([0-9]+(\.[0-9]*)?|\.[0-9]+|)$} %P]}" validate_posint = "expr {[regexp {^([0-9]+|)$} %P]}" def posfloatentry(f, v): var = Tkinter.DoubleVar(f) var.set(v) w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_posfloat, validate="all", width=10) return w, var def floatentry(f, v): var = Tkinter.DoubleVar(f) var.set(v) w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_float, validate="all", width=10) return w, var def posintentry(f, v): var = Tkinter.IntVar(f) var.set(v) w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_posint, validate="all", width=10) return w, var def intentry(f, v): var = Tkinter.IntVar(f) var.set(v) w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_int, validate="all", width=10) return w, var def checkbutton(k, v): var = Tkinter.BooleanVar(f) var.set(v) g = Tkinter.Frame(f) w = Tkinter.Checkbutton(g, variable=var, text="Yes") w.pack(side="left") return g, var def intscale(k, v, min=1, max = 100): var = Tkinter.IntVar(f) var.set(v) g = Tkinter.Frame(f, borderwidth=0) w = Tkinter.Scale(g, orient="h", variable=var, from_=min, to=max, showvalue=False) l = Tkinter.Label(g, textvariable=var, width=3) l.pack(side="left") w.pack(side="left", fill="x", expand=1) return g, var def optionmenu(k, v, *options): options = list(options) def trace(*args): try: var.set(options.index(svar.get())) except ValueError: pass try: opt = options[v] except (TypeError, IndexError): v = 0 opt = options[0] var = Tkinter.IntVar(f) var.set(v) svar = Tkinter.StringVar(f) svar.set(options[v]) svar.trace("w", trace) wp = f._w.rstrip(".") + ".c" + svar._name f.tk.call("combobox::combobox", wp, "-editable", 0, "-width", max(len(opt) for opt in options)+3, "-textvariable", svar._name, "-background", "white") f.tk.call(wp, "list", "insert", "end", *options) w = nf.makewidget(f, Tkinter.Widget, wp) return w, var rc = os.path.expanduser("~/.holecirclerc") constructors = [ ("units", lambda f, v: optionmenu(f, v, _("G20 (in)"), _("G21 (mm)"))), ("cx", floatentry), ("cy", floatentry), ("th0", floatentry), ("inc", floatentry), ("rad", posfloatentry), ("count", posintentry), ("feedrate", posfloatentry), ("depth", floatentry), ("dwell", posfloatentry), ("retract", floatentry), ] defaults = dict( cx = 0, cy = 0, th0 = 0, inc = 15, count = 6, feedrate = 8, depth=-.1, retract=.1, units=0, dwell=0, rad=1 ) texts = dict( units=_("Units"), rad=_("Radius"), cx=_("Center X"), cy=_("Center Y"), th0=_("Start Angle"), inc=_("Increment Angle"), count=_("Hole Count"), feedrate=_("Feed Rate"), depth=_("Hole Depth"), retract=_("Retract Height"), dwell=("Dwell (0=no dwell)"), ) try: defaults.update(pickle.load(open(rc, "rb"))) except (IOError, pickle.PickleError): pass vars = {} widgets = {} for j, (k, con) in enumerate(constructors): v = defaults[k] text = texts.get(k, k.replace("_", " ")) lab = Tkinter.Label(f, text=text) widgets[k], vars[k] = con(f, v) lab.grid(row=j, column=0, sticky="w") widgets[k].grid(row=j, column=1, sticky="ew") def update_preview(*args): prev.delete("all") try: count = vars['count'].get() th0 = vars['th0'].get() inc = vars['inc'].get() except ValueError: return for i in range(count): th = (th0 + i * inc) * math.pi / 180 x = 100 + 75 * math.cos(th) y = 100 - 75 * math.sin(th) prev.create_oval((x-4,y-4,x+4,y+4), fill='black') def update_ok(*args): result = True for i in vars.values(): try: i.get() except ValueError: result = False break if result: bb.configure(state="normal") else: bb.configure(state="disabled") # This line creates an error when you load holecircle twice # from inside linuxcnc eg. gladevcp filechooser or AXIS GUI #print >>sys.stderr, "update_ok", args vars['count'].trace('w', update_preview) vars['inc'].trace('w', update_preview) vars['th0'].trace('w', update_preview) for i in vars.values(): i.trace('w', update_ok) update_preview() status = Tkinter.IntVar() bb = Tkinter.Button(b, text=_("OK"), command=lambda:status.set(1), width=8, default="active") bb.pack(side="left", padx=4, pady=4) bc = Tkinter.Button(b, text=_("Cancel"), command=lambda:status.set(-1), width=8, default="normal") bc.pack(side="left", padx=4, pady=4) app.bind("", lambda evt: bc.invoke()) app.bind("", lambda evt: bb.invoke()) app.wm_protocol("WM_DELETE_WINDOW", lambda: bc.invoke()) app.wm_resizable(0,0) app.wait_visibility() app.tk.call("after", "idle", ("after", "idle", "focus [tk_focusNext .]")) #app.tk_focusNext().focus() app.wait_variable(status) if status.get() == -1: raise SystemExit(1) for k, v in vars.items(): defaults[k] = v.get() app.destroy() pickle.dump(defaults, open(rc, "wb")) return defaults unitcodes = ['G20', 'G21'] u = ui() print unitcodes[u['units']] print "F%.1f" % u['feedrate'] count = u['count'] th0 = u['th0'] inc = u['inc'] depth = u['depth'] retract = u['retract'] cx = u['cx'] cy = u['cy'] rad = u['rad'] if u['dwell']: cycle = "G82 P% 8.4f" % u['dwell'] else: cycle = "G81" for i in range(count): th = (th0 + i * inc) * math.pi / 180 x = cx + rad * math.cos(th) y = cy + rad * math.sin(th) print "%s X% 8.4f Y% 8.4f Z% 8.4f R% 8.4f" % (cycle, x, y, depth, retract) print "M2"