246 lines
7.1 KiB
Python
246 lines
7.1 KiB
Python
import sys, os
|
|
BASE = os.environ['LINUXCNC_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(("update_ok", args), file=sys.stderr)
|
|
|
|
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("<Escape>", lambda evt: bc.invoke())
|
|
app.bind("<Return>", 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")
|