kopia lustrzana https://github.com/AfBu/k40whisperer_turbo
6315 wiersze
283 KiB
Python
6315 wiersze
283 KiB
Python
#!/usr/bin/python
|
|
"""
|
|
K40 Whisperer
|
|
|
|
Copyright (C) <2017-2023> <Scorch>
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
version = '0.64 TURBO'
|
|
title_text = "K40 Whisperer V"+version
|
|
|
|
import sys
|
|
from math import *
|
|
from egv import egv
|
|
from nano_library import K40_CLASS
|
|
from dxf import DXF_CLASS
|
|
from svg_reader import SVG_READER
|
|
from svg_reader import SVG_TEXT_EXCEPTION
|
|
from svg_reader import SVG_PXPI_EXCEPTION
|
|
from g_code_library import G_Code_Rip
|
|
from interpolate import interpolate
|
|
from ecoords import ECoord
|
|
from convex_hull import hull2D
|
|
from embedded_images import K40_Whisperer_Images
|
|
from http.server import (HTTPServer, BaseHTTPRequestHandler, ThreadingHTTPServer, SimpleHTTPRequestHandler)
|
|
import threading
|
|
import json
|
|
|
|
import inkex
|
|
import simplestyle
|
|
import simpletransform
|
|
import cubicsuperpath
|
|
import cspsubdiv
|
|
import traceback
|
|
import struct
|
|
|
|
DEBUG = False
|
|
|
|
if DEBUG:
|
|
import inspect
|
|
|
|
VERSION = sys.version_info[0]
|
|
LOAD_MSG = ""
|
|
|
|
if VERSION == 3:
|
|
from tkinter import *
|
|
from tkinter.filedialog import *
|
|
import tkinter.messagebox
|
|
MAXINT = sys.maxsize
|
|
|
|
else:
|
|
from Tkinter import *
|
|
from tkFileDialog import *
|
|
import tkMessageBox
|
|
MAXINT = sys.maxint
|
|
|
|
if VERSION < 3 and sys.version_info[1] < 6:
|
|
def next(item):
|
|
#return item.next()
|
|
return item.__next__()
|
|
|
|
try:
|
|
import psyco
|
|
psyco.full()
|
|
LOAD_MSG = LOAD_MSG+"\nPsyco Loaded\n"
|
|
except:
|
|
pass
|
|
|
|
import math
|
|
from time import time
|
|
import os
|
|
import re
|
|
import binascii
|
|
import getopt
|
|
import operator
|
|
import webbrowser
|
|
from PIL import Image
|
|
from PIL import ImageOps
|
|
from PIL import ImageFilter
|
|
|
|
try:
|
|
Image.warnings.simplefilter('ignore', Image.DecompressionBombWarning)
|
|
except:
|
|
pass
|
|
try:
|
|
from PIL import ImageTk
|
|
from PIL import _imaging
|
|
except:
|
|
pass #Don't worry everything will still work
|
|
|
|
PYCLIPPER=True
|
|
try:
|
|
import pyclipper
|
|
except:
|
|
print("Unable to load Pyclipper library (Offset trace outline will not work without it)")
|
|
PYCLIPPER = False
|
|
|
|
try:
|
|
os.chdir(os.path.dirname(__file__))
|
|
except:
|
|
pass
|
|
|
|
QUIET = False
|
|
|
|
################################################################################
|
|
class Application(Frame):
|
|
def __init__(self, master):
|
|
self.trace_window = toplevel_dummy()
|
|
Frame.__init__(self, master)
|
|
self.w = 780
|
|
self.h = 490
|
|
frame = Frame(master, width= self.w, height=self.h)
|
|
self.master = master
|
|
self.x = -1
|
|
self.y = -1
|
|
self.createWidgets()
|
|
self.micro = False
|
|
|
|
def resetPath(self):
|
|
self.RengData = ECoord()
|
|
self.VengData = ECoord()
|
|
self.VcutData = ECoord()
|
|
self.GcodeData = ECoord()
|
|
self.SCALE = 1
|
|
self.Design_bounds = (0,0,0,0)
|
|
self.UI_image = None
|
|
#if self.HomeUR.get():
|
|
self.move_head_window_temporary([0.0,0.0])
|
|
#else:
|
|
# self.move_head_window_temporary([0.0,0.0])
|
|
|
|
self.pos_offset=[0.0,0.0]
|
|
|
|
def createWidgets(self):
|
|
self.initComplete = 0
|
|
self.stop=[True]
|
|
|
|
self.k40 = None
|
|
self.run_time = 0
|
|
|
|
self.master.bind("<Configure>", self.Master_Configure)
|
|
self.master.bind('<Enter>', self.bindConfigure)
|
|
self.master.bind('<F1>', self.KEY_F1)
|
|
self.master.bind('<F2>', self.KEY_F2)
|
|
self.master.bind('<F3>', self.KEY_F3)
|
|
self.master.bind('<F4>', self.KEY_F4)
|
|
self.master.bind('<F5>', self.KEY_F5)
|
|
self.master.bind('<F6>', self.KEY_F6)
|
|
self.master.bind('<Home>', self.Home)
|
|
|
|
#self.master.bind('<Control-R>', self.Raster_Eng)
|
|
#self.master.bind('<Control-V>', self.Vector_Eng)
|
|
#self.master.bind('<Control-C>', self.Vector_Cut)
|
|
#self.master.bind('<Control-G>', self.Gcode_Cut)
|
|
|
|
self.master.bind('<Control-Left>' , self.Move_Left)
|
|
self.master.bind('<Control-Right>' , self.Move_Right)
|
|
self.master.bind('<Control-Up>' , self.Move_Up)
|
|
self.master.bind('<Control-Down>' , self.Move_Down)
|
|
|
|
self.master.bind('<Control-Home>' , self.Move_UL)
|
|
self.master.bind('<Control-Prior>' , self.Move_UR)
|
|
self.master.bind('<Control-Next>' , self.Move_LR)
|
|
self.master.bind('<Control-End>' , self.Move_LL)
|
|
self.master.bind('<Control-Clear>' , self.Move_CC)
|
|
|
|
self.master.bind('<Control-Key-4>' , self.Move_Left)
|
|
self.master.bind('<Control-6>' , self.Move_Right)
|
|
self.master.bind('<Control-8>' , self.Move_Up)
|
|
self.master.bind('<Control-Key-2>' , self.Move_Down)
|
|
|
|
self.master.bind('<Control-7>' , self.Move_UL)
|
|
self.master.bind('<Control-9>' , self.Move_UR)
|
|
self.master.bind('<Control-Key-3>' , self.Move_LR)
|
|
self.master.bind('<Control-Key-1>' , self.Move_LL)
|
|
self.master.bind('<Control-Key-5>' , self.Move_CC)
|
|
|
|
#####
|
|
|
|
self.master.bind('<Alt-Control-Left>' , self.Move_Arb_Left)
|
|
self.master.bind('<Alt-Control-Right>', self.Move_Arb_Right)
|
|
self.master.bind('<Alt-Control-Up>' , self.Move_Arb_Up)
|
|
self.master.bind('<Alt-Control-Down>' , self.Move_Arb_Down)
|
|
|
|
self.master.bind('<Alt-Control-Key-4>', self.Move_Arb_Left)
|
|
self.master.bind('<Alt-Control-6>' , self.Move_Arb_Right)
|
|
self.master.bind('<Alt-Control-8>' , self.Move_Arb_Up)
|
|
self.master.bind('<Alt-Control-Key-2>', self.Move_Arb_Down)
|
|
|
|
|
|
self.master.bind('<Alt-Left>' , self.Move_Arb_Left)
|
|
self.master.bind('<Alt-Right>', self.Move_Arb_Right)
|
|
self.master.bind('<Alt-Up>' , self.Move_Arb_Up)
|
|
self.master.bind('<Alt-Down>' , self.Move_Arb_Down)
|
|
|
|
self.master.bind('<Alt-Key-4>', self.Move_Arb_Left)
|
|
self.master.bind('<Alt-6>' , self.Move_Arb_Right)
|
|
self.master.bind('<Alt-8>' , self.Move_Arb_Up)
|
|
self.master.bind('<Alt-Key-2>', self.Move_Arb_Down)
|
|
|
|
#####
|
|
self.master.bind('<Control-i>' , self.Initialize_Laser)
|
|
self.master.bind('<Control-f>' , self.Unfreeze_Laser)
|
|
self.master.bind('<Control-o>' , self.menu_File_Open_Design)
|
|
self.master.bind('<Control-l>' , self.menu_Reload_Design)
|
|
self.master.bind('<Control-h>' , self.Home)
|
|
self.master.bind('<Control-u>' , self.Unlock)
|
|
self.master.bind('<Escape>' , self.Stop)
|
|
self.master.bind('<Control-t>' , self.TRACE_Settings_Window)
|
|
|
|
self.master.bind('<Alt-Return>', self.Toggle_Fullscreen)
|
|
|
|
self.include_Reng = BooleanVar()
|
|
self.include_Rpth = BooleanVar()
|
|
self.include_Veng = BooleanVar()
|
|
self.include_Vcut = BooleanVar()
|
|
self.include_Gcde = BooleanVar()
|
|
self.include_Time = BooleanVar()
|
|
|
|
self.advanced = BooleanVar()
|
|
|
|
self.halftone = BooleanVar()
|
|
self.mirror = BooleanVar()
|
|
self.rotate = BooleanVar()
|
|
self.negate = BooleanVar()
|
|
self.inputCSYS = BooleanVar()
|
|
self.HomeUR = BooleanVar()
|
|
self.engraveUP = BooleanVar()
|
|
self.init_home = BooleanVar()
|
|
self.post_home = BooleanVar()
|
|
self.post_beep = BooleanVar()
|
|
self.post_disp = BooleanVar()
|
|
self.post_exec = BooleanVar()
|
|
|
|
self.pre_pr_crc = BooleanVar()
|
|
self.inside_first = BooleanVar()
|
|
self.rotary = BooleanVar()
|
|
self.reduced_mem = BooleanVar()
|
|
self.wait = BooleanVar()
|
|
|
|
|
|
self.ht_size = StringVar()
|
|
self.Reng_feed = StringVar()
|
|
self.Veng_feed = StringVar()
|
|
self.Vcut_feed = StringVar()
|
|
self.fastPlot = BooleanVar()
|
|
self.saveLoadState = BooleanVar()
|
|
|
|
self.Reng_passes = StringVar()
|
|
self.Veng_passes = StringVar()
|
|
self.Vcut_passes = StringVar()
|
|
self.Gcde_passes = StringVar()
|
|
|
|
|
|
self.board_name = StringVar()
|
|
self.units = StringVar()
|
|
self.jog_step = StringVar()
|
|
self.rast_step = StringVar()
|
|
self.funits = StringVar()
|
|
|
|
|
|
self.bezier_M1 = StringVar()
|
|
self.bezier_M2 = StringVar()
|
|
self.bezier_weight = StringVar()
|
|
|
|
## self.unsharp_flag = BooleanVar()
|
|
## self.unsharp_r = StringVar()
|
|
## self.unsharp_p = StringVar()
|
|
## self.unsharp_t = StringVar()
|
|
## self.unsharp_flag.set(False)
|
|
## self.unsharp_r.set("40")
|
|
## self.unsharp_p.set("350")
|
|
## self.unsharp_t.set("3")
|
|
|
|
self.LaserXsize = StringVar()
|
|
self.LaserYsize = StringVar()
|
|
|
|
self.LaserXscale = StringVar()
|
|
self.LaserYscale = StringVar()
|
|
self.LaserRscale = StringVar()
|
|
|
|
self.rapid_feed = StringVar()
|
|
|
|
self.gotoX = StringVar()
|
|
self.gotoY = StringVar()
|
|
|
|
self.lastX = StringVar()
|
|
self.lastY = StringVar()
|
|
|
|
self.n_egv_passes = StringVar()
|
|
|
|
self.inkscape_path = StringVar()
|
|
self.batch_path = StringVar()
|
|
self.ink_timeout = StringVar()
|
|
|
|
self.t_timeout = StringVar()
|
|
self.n_timeouts = StringVar()
|
|
|
|
self.Reng_time = StringVar()
|
|
self.Veng_time = StringVar()
|
|
self.Vcut_time = StringVar()
|
|
self.Gcde_time = StringVar()
|
|
|
|
self.comb_engrave = BooleanVar()
|
|
self.comb_vector = BooleanVar()
|
|
self.zoom2image = BooleanVar()
|
|
|
|
self.trace_w_laser = BooleanVar()
|
|
self.trace_gap = StringVar()
|
|
self.trace_speed = StringVar()
|
|
|
|
###########################################################################
|
|
# INITILIZE VARIABLES #
|
|
# if you want to change a default setting this is the place to do it #
|
|
###########################################################################
|
|
self.include_Reng.set(1)
|
|
self.include_Rpth.set(0)
|
|
self.include_Veng.set(1)
|
|
self.include_Vcut.set(1)
|
|
self.include_Gcde.set(1)
|
|
self.include_Time.set(0)
|
|
self.advanced.set(0)
|
|
|
|
self.halftone.set(1)
|
|
self.mirror.set(0)
|
|
self.rotate.set(0)
|
|
self.negate.set(0)
|
|
self.inputCSYS.set(0)
|
|
self.HomeUR.set(0)
|
|
self.engraveUP.set(0)
|
|
self.init_home.set(1)
|
|
self.post_home.set(0)
|
|
self.post_beep.set(0)
|
|
self.post_disp.set(0)
|
|
self.post_exec.set(0)
|
|
|
|
self.pre_pr_crc.set(1)
|
|
self.inside_first.set(1)
|
|
self.rotary.set(0)
|
|
self.reduced_mem.set(0)
|
|
self.wait.set(1)
|
|
|
|
self.ht_size.set(500)
|
|
|
|
self.Reng_feed.set("100")
|
|
self.Veng_feed.set("20")
|
|
self.Vcut_feed.set("10")
|
|
self.Reng_passes.set("1")
|
|
self.Veng_passes.set("1")
|
|
self.Vcut_passes.set("1")
|
|
self.Gcde_passes.set("1")
|
|
|
|
|
|
self.jog_step.set("1.0")
|
|
self.rast_step.set("0.002")
|
|
|
|
self.bezier_weight.set("3.5")
|
|
self.bezier_M1.set("2.5")
|
|
self.bezier_M2.set("0.50")
|
|
|
|
self.bezier_weight_default = float(self.bezier_weight.get())
|
|
self.bezier_M1_default = float(self.bezier_M1.get())
|
|
self.bezier_M2_default = float(self.bezier_M2.get())
|
|
|
|
|
|
self.board_name.set("LASER-M2") # Options are
|
|
# "LASER-M2",
|
|
# "LASER-M1",
|
|
# "LASER-M",
|
|
# "LASER-B2",
|
|
# "LASER-B1",
|
|
# "LASER-B",
|
|
# "LASER-A"
|
|
|
|
|
|
self.units.set("mm") # Options are "in" and "mm"
|
|
|
|
self.ink_timeout.set("3")
|
|
self.t_timeout.set("200")
|
|
self.n_timeouts.set("30")
|
|
|
|
self.HOME_DIR = os.path.expanduser("~")
|
|
|
|
if not os.path.isdir(self.HOME_DIR):
|
|
self.HOME_DIR = ""
|
|
|
|
self.DESIGN_FILE = (self.HOME_DIR+"/None")
|
|
self.EGV_FILE = None
|
|
|
|
self.aspect_ratio = 0
|
|
self.segID = []
|
|
|
|
self.LaserXsize.set("325")
|
|
self.LaserYsize.set("220")
|
|
|
|
self.LaserXscale.set("1.000")
|
|
self.LaserYscale.set("1.000")
|
|
self.LaserRscale.set("1.000")
|
|
|
|
self.rapid_feed.set("0.0")
|
|
|
|
self.gotoX.set("0.0")
|
|
self.gotoY.set("0.0")
|
|
|
|
self.lastX.set("0.0")
|
|
self.lastY.set("0.0")
|
|
|
|
self.n_egv_passes.set("1")
|
|
|
|
self.comb_engrave.set(0)
|
|
self.comb_vector.set(0)
|
|
self.zoom2image.set(0)
|
|
|
|
|
|
self.trace_w_laser.set(0)
|
|
self.trace_gap.set(0)
|
|
self.trace_speed.set(50)
|
|
|
|
self.laserX = 0.0
|
|
self.laserY = 0.0
|
|
self.PlotScale = 1.0
|
|
self.GUI_Disabled = False
|
|
|
|
# PAN and ZOOM STUFF
|
|
self.panx = 0
|
|
self.panx = 0
|
|
self.lastx = 0
|
|
self.lasty = 0
|
|
self.move_start_x = 0
|
|
self.move_start_y = 0
|
|
|
|
|
|
self.RengData = ECoord()
|
|
self.VengData = ECoord()
|
|
self.VcutData = ECoord()
|
|
self.GcodeData = ECoord()
|
|
self.SCALE = 1
|
|
self.Design_bounds = (0,0,0,0)
|
|
self.UI_image = None
|
|
self.pos_offset=[0.0,0.0]
|
|
self.inkscape_warning = False
|
|
|
|
# Derived variables
|
|
if self.units.get() == 'in':
|
|
self.funits.set('in/min')
|
|
self.units_scale = 1.0
|
|
else:
|
|
self.units.set('mm')
|
|
self.funits.set('mm/s')
|
|
self.units_scale = 25.4
|
|
|
|
self.statusMessage = StringVar()
|
|
self.statusMessage.set("Welcome to K40 Whisperer")
|
|
|
|
|
|
self.Reng_time.set("0")
|
|
self.Veng_time.set("0")
|
|
self.Vcut_time.set("0")
|
|
self.Gcde_time.set("0")
|
|
|
|
self.min_vector_speed = 1.1 #in/min
|
|
self.min_raster_speed = 12 #in/min
|
|
|
|
##########################################################################
|
|
### END INITILIZING VARIABLES ###
|
|
##########################################################################
|
|
|
|
# make a Status Bar
|
|
self.statusbar = Label(self.master, textvariable=self.statusMessage, \
|
|
bd=1, relief=SUNKEN , height=1)
|
|
self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM)
|
|
|
|
|
|
# Canvas
|
|
lbframe = Frame( self.master )
|
|
self.PreviewCanvas_frame = lbframe
|
|
self.PreviewCanvas = Canvas(lbframe, width=self.w-(220+20), height=self.h-200, background="grey75")
|
|
self.PreviewCanvas.pack(side=LEFT, fill=BOTH, expand=1)
|
|
self.PreviewCanvas_frame.place(x=230, y=10)
|
|
|
|
self.PreviewCanvas.tag_bind('LaserTag',"<1>" , self.mousePanStart)
|
|
self.PreviewCanvas.tag_bind('LaserTag',"<B1-Motion>" , self.mousePan)
|
|
self.PreviewCanvas.tag_bind('LaserTag',"<ButtonRelease-1>", self.mousePanStop)
|
|
|
|
self.PreviewCanvas.tag_bind('LaserDot',"<3>" , self.right_mousePanStart)
|
|
self.PreviewCanvas.tag_bind('LaserDot',"<B3-Motion>" , self.right_mousePan)
|
|
self.PreviewCanvas.tag_bind('LaserDot',"<ButtonRelease-3>", self.right_mousePanStop)
|
|
|
|
# Left Column #
|
|
self.separator1 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
self.separator2 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
self.separator3 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
self.separator4 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
|
|
self.Label_Reng_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
|
|
self.Entry_Reng_feed = Entry(self.master,width="15")
|
|
self.Entry_Reng_feed.configure(textvariable=self.Reng_feed,justify='center',fg="black")
|
|
self.Reng_feed.trace_variable("w", self.Entry_Reng_feed_Callback)
|
|
self.NormalColor = self.Entry_Reng_feed.cget('bg')
|
|
|
|
self.Label_Veng_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
|
|
self.Entry_Veng_feed = Entry(self.master,width="15")
|
|
self.Entry_Veng_feed.configure(textvariable=self.Veng_feed,justify='center',fg="blue")
|
|
self.Veng_feed.trace_variable("w", self.Entry_Veng_feed_Callback)
|
|
self.NormalColor = self.Entry_Veng_feed.cget('bg')
|
|
|
|
self.Label_Vcut_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
|
|
self.Entry_Vcut_feed = Entry(self.master,width="15")
|
|
self.Entry_Vcut_feed.configure(textvariable=self.Vcut_feed,justify='center',fg="red")
|
|
self.Vcut_feed.trace_variable("w", self.Entry_Vcut_feed_Callback)
|
|
self.NormalColor = self.Entry_Vcut_feed.cget('bg')
|
|
|
|
# Buttons
|
|
self.Reng_Button = Button(self.master,text="Raster Engrave", command=self.Raster_Eng, bg='#aaaaaa')
|
|
self.Reng_Button_Plus = Button(self.master,text="+", command=self.Raster_Eng_Plus)
|
|
self.Reng_Button_Minus = Button(self.master,text="-", command=self.Raster_Eng_Minus)
|
|
self.Veng_Button = Button(self.master,text="Vector Engrave", command=self.Vector_Eng, bg='#c2c8ff')
|
|
self.Veng_Button_Plus = Button(self.master,text="+", command=self.Vector_Eng_Plus)
|
|
self.Veng_Button_Minus = Button(self.master,text="-", command=self.Vector_Eng_Minus)
|
|
self.Vcut_Button = Button(self.master,text="Vector Cut" , command=self.Vector_Cut, bg='#ffc6c2')
|
|
self.Vcut_Button_Plus = Button(self.master,text="+" , command=self.Vector_Cut_Plus)
|
|
self.Vcut_Button_Minus = Button(self.master,text="-" , command=self.Vector_Cut_Minus)
|
|
self.Grun_Button = Button(self.master,text="Run G-Code" , command=self.Gcode_Cut)
|
|
|
|
self.Reng_Passes_Button_Plus = Button(self.master,text="+", command=self.Reng_Passes_Plus)
|
|
self.Reng_Passes_Button_Minus = Button(self.master,text="-", command=self.Reng_Passes_Minus)
|
|
self.Veng_Passes_Button_Plus = Button(self.master,text="+", command=self.Veng_Passes_Plus)
|
|
self.Veng_Passes_Button_Minus = Button(self.master,text="-", command=self.Veng_Passes_Minus)
|
|
self.Vcut_Passes_Button_Plus = Button(self.master,text="+", command=self.Vcut_Passes_Plus)
|
|
self.Vcut_Passes_Button_Minus = Button(self.master,text="-", command=self.Vcut_Passes_Minus)
|
|
|
|
self.Frame_Button = Button(self.master,text="Frame" , command=self.Move_Frame, bg='#fcba03')
|
|
|
|
self.Reng_Veng_Button = Button(self.master,text="Raster and\nVector Engrave", command=self.Raster_Vector_Eng)
|
|
self.Veng_Vcut_Button = Button(self.master,text="Vector Engrave\nand Cut", command=self.Vector_Eng_Cut)
|
|
self.Reng_Veng_Vcut_Button = Button(self.master,text="Raster Engrave\nVector Engrave\nand\nVector Cut", command=self.Raster_Vector_Cut)
|
|
|
|
self.Label_Position_Control = Label(self.master,text="Position Controls:", anchor=W)
|
|
|
|
self.Initialize_Button = Button(self.master,text="Initialize Laser Cutter", command=self.Initialize_Laser, bg='#ffffff')
|
|
|
|
self.Open_Button = Button(self.master,text="Open\nDesign File", command=self.menu_File_Open_Design, bg='#bede95')
|
|
self.Reload_Button = Button(self.master,text="Reload\nDesign File", command=self.menu_Reload_Design, bg='#dade95')
|
|
|
|
self.Home_Button = Button(self.master,text="Home", command=self.Home, bg='#a895de')
|
|
self.UnLock_Button = Button(self.master,text="Unlock Rail", command=self.Unlock, bg='#de95a7')
|
|
self.Stop_Button = Button(self.master,text="Pause/Stop", command=self.Stop)
|
|
|
|
try:
|
|
self.left_image = PhotoImage(data=K40_Whisperer_Images.left_B64, format='gif')
|
|
self.right_image = PhotoImage(data=K40_Whisperer_Images.right_B64, format='gif')
|
|
self.up_image = PhotoImage(data=K40_Whisperer_Images.up_B64, format='gif')
|
|
self.down_image = PhotoImage(data=K40_Whisperer_Images.down_B64, format='gif')
|
|
|
|
self.fastplot_on_image = PhotoImage(data=K40_Whisperer_Images.fp_on_B64, format='gif')
|
|
self.fastplot_off_image = PhotoImage(data=K40_Whisperer_Images.fp_off_B64, format='gif')
|
|
self.cfg_load_image = PhotoImage(data=K40_Whisperer_Images.cfg_load_B64, format='gif')
|
|
self.cfg_save_image = PhotoImage(data=K40_Whisperer_Images.cfg_save_B64, format='gif')
|
|
self.fs_image = PhotoImage(data=K40_Whisperer_Images.fs_B64, format='gif')
|
|
self.adv_image = PhotoImage(data=K40_Whisperer_Images.adv_B64, format='gif')
|
|
self.xy_image = PhotoImage(data=K40_Whisperer_Images.xy_B64, format='gif')
|
|
self.xyr_image = PhotoImage(data=K40_Whisperer_Images.xyr_B64, format='gif')
|
|
self.check_on_image = PhotoImage(data=K40_Whisperer_Images.check_on_B64, format='gif')
|
|
self.check_off_image = PhotoImage(data=K40_Whisperer_Images.check_off_B64, format='gif')
|
|
|
|
self.Right_Button = Button(self.master,image=self.right_image, command=self.Move_Right, bg='#efffba')
|
|
self.Right_Button_10 = Button(self.master,image=self.right_image, command=self.Move_Right_10, bg='#ffe9ba')
|
|
self.Right_Button_100 = Button(self.master,image=self.right_image, command=self.Move_Right_100, bg='#ffbaba')
|
|
self.Left_Button = Button(self.master,image=self.left_image, command=self.Move_Left, bg='#efffba')
|
|
self.Left_Button_10 = Button(self.master,image=self.left_image, command=self.Move_Left_10, bg='#ffe9ba')
|
|
self.Left_Button_100 = Button(self.master,image=self.left_image, command=self.Move_Left_100, bg='#ffbaba')
|
|
self.Up_Button = Button(self.master,image=self.up_image, command=self.Move_Up, bg='#efffba')
|
|
self.Up_Button_10 = Button(self.master,image=self.up_image, command=self.Move_Up_10, bg='#ffe9ba')
|
|
self.Up_Button_100 = Button(self.master,image=self.up_image, command=self.Move_Up_100, bg='#ffbaba')
|
|
self.Down_Button = Button(self.master,image=self.down_image, command=self.Move_Down, bg='#efffba')
|
|
self.Down_Button_10 = Button(self.master,image=self.down_image, command=self.Move_Down_10, bg='#ffe9ba')
|
|
self.Down_Button_100 = Button(self.master,image=self.down_image, command=self.Move_Down_100, bg='#ffbaba')
|
|
|
|
self.UL_image = PhotoImage(data=K40_Whisperer_Images.UL_B64, format='gif')
|
|
self.UR_image = PhotoImage(data=K40_Whisperer_Images.UR_B64, format='gif')
|
|
self.LR_image = PhotoImage(data=K40_Whisperer_Images.LR_B64, format='gif')
|
|
self.LL_image = PhotoImage(data=K40_Whisperer_Images.LL_B64, format='gif')
|
|
self.CC_image = PhotoImage(data=K40_Whisperer_Images.CC_B64, format='gif')
|
|
|
|
self.UL_Button = Button(self.master,image=self.UL_image, command=self.Move_UL, bg='#bad7ff')
|
|
self.UR_Button = Button(self.master,image=self.UR_image, command=self.Move_UR, bg='#bad7ff')
|
|
self.LR_Button = Button(self.master,image=self.LR_image, command=self.Move_LR, bg='#bad7ff')
|
|
self.LL_Button = Button(self.master,image=self.LL_image, command=self.Move_LL, bg='#bad7ff')
|
|
self.CC_Button = Button(self.master,image=self.CC_image, command=self.Move_CC, bg='#bad7ff')
|
|
|
|
except:
|
|
self.Right_Button = Button(self.master,text=">", command=self.Move_Right)
|
|
self.Right_Button_10 = Button(self.master,text=">>", command=self.Move_Right_10)
|
|
self.Right_Button_100 = Button(self.master,text=">>>", command=self.Move_Right_100)
|
|
self.Left_Button = Button(self.master,text="<", command=self.Move_Left)
|
|
self.Left_Button_10 = Button(self.master,text="<<", command=self.Move_Left_10)
|
|
self.Left_Button_100 = Button(self.master,text="<<<", command=self.Move_Left_100)
|
|
self.Up_Button = Button(self.master,text="^", command=self.Move_Up)
|
|
self.Up_Button_10 = Button(self.master,text="^^", command=self.Move_Up_10)
|
|
self.Up_Button_100 = Button(self.master,text="^^^", command=self.Move_Up_100)
|
|
self.Down_Button = Button(self.master,text="v", command=self.Move_Down)
|
|
self.Down_Button_10 = Button(self.master,text="vv", command=self.Move_Down_10)
|
|
self.Down_Button_100 = Button(self.master,text="vvv", command=self.Move_Down_100)
|
|
|
|
self.UL_Button = Button(self.master,text=" ", command=self.Move_UL)
|
|
self.UR_Button = Button(self.master,text=" ", command=self.Move_UR)
|
|
self.LR_Button = Button(self.master,text=" ", command=self.Move_LR)
|
|
self.LL_Button = Button(self.master,text=" ", command=self.Move_LL)
|
|
self.CC_Button = Button(self.master,text=" ", command=self.Move_CC)
|
|
|
|
self.Label_Step = Label(self.master,text="Jog Step", anchor=CENTER )
|
|
self.Label_Step_u = Label(self.master,textvariable=self.units, anchor=W)
|
|
self.Entry_Step = Entry(self.master,width="15")
|
|
self.Entry_Step.configure(textvariable=self.jog_step, justify='center')
|
|
self.jog_step.trace_variable("w", self.Entry_Step_Callback)
|
|
self.Step_Button_Plus = Button(self.master,text="+", command=self.Step_Plus)
|
|
self.Step_Button_Minus = Button(self.master,text="-", command=self.Step_Minus)
|
|
|
|
# TURBO TOOLBAR BUTTONS
|
|
self.FastPlot_Button = Button(self.master,image=self.fastplot_off_image, command=self.Toggle_FastPlot)
|
|
self.AdvancedShow_Button = Button(self.master,image=self.adv_image,command=self.Toggle_Advanced)
|
|
self.Remember_Button = Button(self.master,image=self.xy_image,command=self.Remember_Position)
|
|
self.Restore_Button = Button(self.master,image=self.xyr_image,command=self.Restore_head_position, state="disabled")
|
|
self.Fullscreen_Button = Button(self.master,image=self.fs_image,command=self.Toggle_Fullscreen)
|
|
|
|
self.fastPlot.trace_variable("w", self.Update_FastPlot)
|
|
|
|
self.SaveLoad_Button = Button(self.master,image=self.cfg_load_image,command=self.SaveLoad_Toggle)
|
|
self.SaveSlot_Button1 = Button(self.master,text="1",command=lambda: self.SaveLoad_Slot("1"))
|
|
self.SaveSlot_Button2 = Button(self.master,text="2",command=lambda: self.SaveLoad_Slot("2"))
|
|
self.SaveSlot_Button3 = Button(self.master,text="3",command=lambda: self.SaveLoad_Slot("3"))
|
|
self.SaveSlot_Button4 = Button(self.master,text="4",command=lambda: self.SaveLoad_Slot("4"))
|
|
self.SaveSlot_Button5 = Button(self.master,text="5",command=lambda: self.SaveLoad_Slot("5"))
|
|
self.SaveSlot_ButtonD = Button(self.master,text="D",command=lambda: self.SaveLoad_Slot("D"))
|
|
|
|
###########################################################################
|
|
self.GoTo_Button = Button(self.master,text="Move To", command=self.GoTo, bg='#87fff5')
|
|
|
|
self.Entry_GoToX = Entry(self.master,width="15",justify='center')
|
|
self.Entry_GoToX.configure(textvariable=self.gotoX)
|
|
self.gotoX.trace_variable("w", self.Entry_GoToX_Callback)
|
|
self.Entry_GoToY = Entry(self.master,width="15",justify='center')
|
|
self.Entry_GoToY.configure(textvariable=self.gotoY)
|
|
self.gotoY.trace_variable("w", self.Entry_GoToY_Callback)
|
|
|
|
self.Label_GoToX = Label(self.master,text="X", anchor=CENTER )
|
|
self.Label_GoToY = Label(self.master,text="Y", anchor=CENTER )
|
|
###########################################################################
|
|
# End Left Column #
|
|
|
|
# Advanced Column #
|
|
self.separator_vert = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
self.Label_Advanced_column = Label(self.master,text="Advanced Settings",anchor=CENTER)
|
|
self.separator_adv = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
|
|
self.Label_Halftone_adv = Label(self.master,text="Halftone (Dither)")
|
|
self.Checkbutton_Halftone_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Halftone_adv.configure(variable=self.halftone)
|
|
self.halftone.trace_variable("w", self.View_Refresh_and_Reset_RasterPath) #self.menu_View_Refresh_Callback
|
|
|
|
self.Label_Negate_adv = Label(self.master,text="Invert Raster Color")
|
|
self.Checkbutton_Negate_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Negate_adv.configure(variable=self.negate)
|
|
self.negate.trace_variable("w", self.View_Refresh_and_Reset_RasterPath)
|
|
|
|
self.separator_adv2 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
|
|
self.Label_Mirror_adv = Label(self.master,text="Mirror Design")
|
|
self.Checkbutton_Mirror_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Mirror_adv.configure(variable=self.mirror)
|
|
self.mirror.trace_variable("w", self.View_Refresh_and_Reset_RasterPath)
|
|
|
|
self.Label_Rotate_adv = Label(self.master,text="Rotate Design")
|
|
self.Checkbutton_Rotate_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Rotate_adv.configure(variable=self.rotate)
|
|
self.rotate.trace_variable("w", self.View_Refresh_and_Reset_RasterPath)
|
|
|
|
self.separator_adv3 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
|
|
self.Label_inputCSYS_adv = Label(self.master,text="Use Input CSYS")
|
|
self.Checkbutton_inputCSYS_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_inputCSYS_adv.configure(variable=self.inputCSYS)
|
|
self.inputCSYS.trace_variable("w", self.menu_View_inputCSYS_Refresh_Callback)
|
|
|
|
self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First")
|
|
self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first)
|
|
self.inside_first.trace_variable("w", self.menu_Inside_First_Callback)
|
|
|
|
self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First")
|
|
self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first)
|
|
|
|
self.Label_Rotary_Enable_adv = Label(self.master,text="Use Rotary Settings")
|
|
self.Checkbutton_Rotary_Enable_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Rotary_Enable_adv.configure(variable=self.rotary)
|
|
self.rotary.trace_variable("w", self.Reset_RasterPath_and_Update_Time)
|
|
|
|
|
|
#####
|
|
self.separator_comb = Frame(self.master, height=2, bd=1, relief=SUNKEN)
|
|
|
|
self.Label_Comb_Engrave_adv = Label(self.master,text="Group Engrave Tasks")
|
|
self.Checkbutton_Comb_Engrave_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Comb_Engrave_adv.configure(variable=self.comb_engrave)
|
|
self.comb_engrave.trace_variable("w", self.menu_View_Refresh_Callback)
|
|
|
|
self.Label_Comb_Vector_adv = Label(self.master,text="Group Vector Tasks")
|
|
self.Checkbutton_Comb_Vector_adv = Checkbutton(self.master,text=" ",image=self.check_off_image,selectimage=self.check_on_image,indicatoron=False,anchor=CENTER)
|
|
self.Checkbutton_Comb_Vector_adv.configure(variable=self.comb_vector)
|
|
self.comb_vector.trace_variable("w", self.menu_View_Refresh_Callback)
|
|
#####
|
|
|
|
self.Label_Reng_passes = Label(self.master,text="Passes")
|
|
self.Entry_Reng_passes = Entry(self.master,width="15")
|
|
self.Entry_Reng_passes.configure(textvariable=self.Reng_passes,justify='center',fg="black")
|
|
self.Reng_passes.trace_variable("w", self.Entry_Reng_passes_Callback)
|
|
self.NormalColor = self.Entry_Reng_passes.cget('bg')
|
|
|
|
self.Label_Veng_passes = Label(self.master,text="Passes")
|
|
self.Entry_Veng_passes = Entry(self.master,width="15")
|
|
self.Entry_Veng_passes.configure(textvariable=self.Veng_passes,justify='center',fg="blue")
|
|
self.Veng_passes.trace_variable("w", self.Entry_Veng_passes_Callback)
|
|
self.NormalColor = self.Entry_Veng_passes.cget('bg')
|
|
|
|
self.Label_Vcut_passes = Label(self.master,text="Passes")
|
|
self.Entry_Vcut_passes = Entry(self.master,width="15")
|
|
self.Entry_Vcut_passes.configure(textvariable=self.Vcut_passes,justify='center',fg="red")
|
|
self.Vcut_passes.trace_variable("w", self.Entry_Vcut_passes_Callback)
|
|
self.NormalColor = self.Entry_Vcut_passes.cget('bg')
|
|
|
|
self.Label_Gcde_passes = Label(self.master,text="G-Code Passes")
|
|
self.Entry_Gcde_passes = Entry(self.master,width="15")
|
|
self.Entry_Gcde_passes.configure(textvariable=self.Gcde_passes,justify='center',fg="black")
|
|
self.Gcde_passes.trace_variable("w", self.Entry_Gcde_passes_Callback)
|
|
self.NormalColor = self.Entry_Gcde_passes.cget('bg')
|
|
|
|
|
|
self.Hide_Adv_Button = Button(self.master,text="Hide Advanced", command=self.Hide_Advanced,bg='#cccccc')
|
|
|
|
# End Right Column #
|
|
self.calc_button = Button(self.master,text="Calculate Raster Time", command=self.menu_Calc_Raster_Time)
|
|
|
|
#GEN Setting Window Entry initializations
|
|
self.Entry_Sspeed = Entry()
|
|
self.Entry_BoxGap = Entry()
|
|
self.Entry_ContAngle = Entry()
|
|
|
|
# Make Menu Bar
|
|
self.menuBar = Menu(self.master, relief = "raised", bd=2)
|
|
|
|
|
|
|
|
|
|
top_File = Menu(self.menuBar, tearoff=0)
|
|
top_File.add("command", label = "Save Settings File", command = self.menu_File_Save)
|
|
top_File.add("command", label = "Read Settings File", command = self.menu_File_Open_Settings_File)
|
|
|
|
top_File.add_separator()
|
|
top_File.add("command", label = "Open Design (SVG/DXF/G-Code)" , command = self.menu_File_Open_Design)
|
|
top_File.add("command", label = "Reload Design" , command = self.menu_Reload_Design)
|
|
|
|
top_File.add_separator()
|
|
top_File.add("command", label = "Send EGV File to Laser" , command = self.menu_File_Open_EGV)
|
|
|
|
SaveEGVmenu = Menu(self.master, relief = "raised", bd=2, tearoff=0)
|
|
top_File.add_cascade(label="Save EGV File", menu=SaveEGVmenu)
|
|
SaveEGVmenu.add("command", label = "Raster Engrave" , command = self.menu_File_Raster_Engrave)
|
|
SaveEGVmenu.add("command", label = "Vector Engrave" , command = self.menu_File_Vector_Engrave)
|
|
SaveEGVmenu.add("command", label = "Vector Cut" , command = self.menu_File_Vector_Cut)
|
|
SaveEGVmenu.add("command", label = "G-Code Operations" , command = self.menu_File_G_Code)
|
|
SaveEGVmenu.add_separator()
|
|
SaveEGVmenu.add("command", label = "Raster and Vector Engrave" , command = self.menu_File_Raster_Vector_Engrave)
|
|
SaveEGVmenu.add("command", label = "Vector Engrave and Cut" , command = self.menu_File_Vector_Engrave_Cut)
|
|
SaveEGVmenu.add("command", label = "Raster, Vector Engrave and Vector Cut" , command = self.menu_File_Raster_Vector_Cut)
|
|
|
|
|
|
top_File.add_separator()
|
|
top_File.add("command", label = "Exit" , command = self.menu_File_Quit)
|
|
|
|
self.menuBar.add("cascade", label="File", menu=top_File)
|
|
|
|
#top_Edit = Menu(self.menuBar, tearoff=0)
|
|
#self.menuBar.add("cascade", label="Edit", menu=top_Edit)
|
|
|
|
top_View = Menu(self.menuBar, tearoff=0)
|
|
top_View.add("command", label = "Refresh <F5>", command = self.menu_View_Refresh)
|
|
top_View.add_separator()
|
|
top_View.add_checkbutton(label = "Show Raster Image" , variable=self.include_Reng ,command= self.menu_View_Refresh)
|
|
if DEBUG:
|
|
top_View.add_checkbutton(label = "Show Raster Paths" ,variable=self.include_Rpth ,command= self.menu_View_Refresh)
|
|
|
|
top_View.add_checkbutton(label = "Show Vector Engrave", variable=self.include_Veng ,command= self.menu_View_Refresh)
|
|
top_View.add_checkbutton(label = "Show Vector Cut" , variable=self.include_Vcut ,command= self.menu_View_Refresh)
|
|
top_View.add_checkbutton(label = "Show G-Code Paths" , variable=self.include_Gcde ,command= self.menu_View_Refresh)
|
|
top_View.add_separator()
|
|
top_View.add_checkbutton(label = "Show Time Estimates", variable=self.include_Time ,command= self.menu_View_Refresh)
|
|
top_View.add_checkbutton(label = "Zoom to Design Size", variable=self.zoom2image ,command= self.menu_View_Refresh)
|
|
|
|
#top_View.add_separator()
|
|
#top_View.add("command", label = "computeAccurateReng",command= self.computeAccurateReng)
|
|
#top_View.add("command", label = "computeAccurateVeng",command= self.computeAccurateVeng)
|
|
#top_View.add("command", label = "computeAccurateVcut",command= self.computeAccurateVcut)
|
|
|
|
self.menuBar.add("cascade", label="View", menu=top_View)
|
|
|
|
top_Tools = Menu(self.menuBar, tearoff=0)
|
|
self.menuBar.add("cascade", label="Tools", menu=top_Tools)
|
|
USBmenu = Menu(self.master, relief = "raised", bd=2, tearoff=0)
|
|
|
|
top_Tools.add("command", label = "Calculate Raster Time", command = self.menu_Calc_Raster_Time)
|
|
top_Tools.add("command", label = "Trace Design Boundary <Ctrl-t>", command = self.TRACE_Settings_Window)
|
|
top_Tools.add_separator()
|
|
top_Tools.add("command", label = "Initialize Laser <Ctrl-i>", command = self.Initialize_Laser)
|
|
top_Tools.add("command", label = "Unfreeze Laser <Ctrl-f>" , command = self.Unfreeze_Laser)
|
|
top_Tools.add_cascade(label="USB", menu=USBmenu)
|
|
USBmenu.add("command", label = "Reset USB", command = self.Reset)
|
|
USBmenu.add("command", label = "Release USB", command = self.Release_USB)
|
|
|
|
|
|
|
|
#top_USB = Menu(self.menuBar, tearoff=0)
|
|
#top_USB.add("command", label = "Reset USB", command = self.Reset)
|
|
#top_USB.add("command", label = "Release USB", command = self.Release_USB)
|
|
#top_USB.add("command", label = "Initialize Laser", command = self.Initialize_Laser)
|
|
#self.menuBar.add("cascade", label="USB", menu=top_USB)
|
|
|
|
|
|
top_Settings = Menu(self.menuBar, tearoff=0)
|
|
top_Settings.add("command", label = "General Settings <F2>", command = self.GEN_Settings_Window)
|
|
top_Settings.add("command", label = "Raster Settings <F3>", command = self.RASTER_Settings_Window)
|
|
top_Settings.add("command", label = "Rotary Settings <F4>", command = self.ROTARY_Settings_Window)
|
|
top_Settings.add_separator()
|
|
top_Settings.add_checkbutton(label = "Advanced Settings <F6>", variable=self.advanced ,command= self.menu_View_Refresh)
|
|
|
|
self.menuBar.add("cascade", label="Settings", menu=top_Settings)
|
|
|
|
top_Help = Menu(self.menuBar, tearoff=0)
|
|
top_Help.add("command", label = "About (e-mail)", command = self.menu_Help_About)
|
|
top_Help.add("command", label = "K40 Whisperer Web Page", command = self.menu_Help_Web)
|
|
top_Help.add("command", label = "TURBO fork GitHub page", command = self.menu_Help_GitHub)
|
|
top_Help.add("command", label = "Manual (Web Page)", command = self.menu_Help_Manual)
|
|
self.menuBar.add("cascade", label="Help", menu=top_Help)
|
|
|
|
self.master.config(menu=self.menuBar)
|
|
|
|
##########################################################################
|
|
# Config File and command line options #
|
|
##########################################################################
|
|
config_file = "k40_whisperer.txt"
|
|
home_config1 = self.HOME_DIR + "/" + config_file
|
|
if ( os.path.isfile(config_file) ):
|
|
self.Open_Settings_File(config_file)
|
|
elif ( os.path.isfile(home_config1) ):
|
|
self.Open_Settings_File(home_config1)
|
|
|
|
|
|
# opts, args = None, None
|
|
# try:
|
|
# opts, args = getopt.getopt(sys.argv[1:], "ho:",["help", "other_option"])
|
|
# except:
|
|
# debug_message('Unable interpret command line options')
|
|
# sys.exit()
|
|
# for option, value in opts:
|
|
## if option in ('-h','--help'):
|
|
## fmessage(' ')
|
|
## fmessage('Usage: python .py [-g file]')
|
|
## fmessage('-o : unknown other option (also --other_option)')
|
|
## fmessage('-h : print this help (also --help)\n')
|
|
## sys.exit()
|
|
# if option in ('-m','--micro'):
|
|
# self.micro = True
|
|
|
|
##########################################################################
|
|
|
|
################################################################################
|
|
def entry_set(self, val2, calc_flag=0, new=0):
|
|
if calc_flag == 0 and new==0:
|
|
try:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
val2.configure( bg = 'yellow' )
|
|
self.statusMessage.set(" Recalculation required.")
|
|
except:
|
|
pass
|
|
elif calc_flag == 3:
|
|
try:
|
|
val2.configure( bg = 'red' )
|
|
self.statusbar.configure( bg = 'red' )
|
|
self.statusMessage.set(" Value should be a number. ")
|
|
except:
|
|
pass
|
|
elif calc_flag == 2:
|
|
try:
|
|
self.statusbar.configure( bg = 'red' )
|
|
val2.configure( bg = 'red' )
|
|
except:
|
|
pass
|
|
elif (calc_flag == 0 or calc_flag == 1) and new==1 :
|
|
try:
|
|
self.statusbar.configure( bg = 'white' )
|
|
self.statusMessage.set(" ")
|
|
val2.configure( bg = 'white' )
|
|
except:
|
|
pass
|
|
elif (calc_flag == 1) and new==0 :
|
|
try:
|
|
self.statusbar.configure( bg = 'white' )
|
|
self.statusMessage.set(" ")
|
|
val2.configure( bg = 'white' )
|
|
except:
|
|
pass
|
|
|
|
elif (calc_flag == 0 or calc_flag == 1) and new==2:
|
|
return 0
|
|
return 1
|
|
|
|
################################################################################
|
|
def Write_Config_File(self, event):
|
|
|
|
config_data = self.WriteConfig()
|
|
config_file = "k40_whisperer.txt"
|
|
configname_full = self.HOME_DIR + "/" + config_file
|
|
|
|
current_name = event.widget.winfo_parent()
|
|
win_id = event.widget.nametowidget(current_name)
|
|
|
|
if ( os.path.isfile(configname_full) ):
|
|
try:
|
|
win_id.withdraw()
|
|
except:
|
|
pass
|
|
|
|
if not message_ask_ok_cancel("Replace", "Replace Exiting Configuration File?\n"+configname_full):
|
|
try:
|
|
win_id.deiconify()
|
|
except:
|
|
pass
|
|
return
|
|
try:
|
|
fout = open(configname_full,'w')
|
|
except:
|
|
self.statusMessage.set("Unable to open file for writing: %s" %(configname_full))
|
|
self.statusbar.configure( bg = 'red' )
|
|
return
|
|
for line in config_data:
|
|
try:
|
|
fout.write(line+'\n')
|
|
except:
|
|
fout.write('(skipping line)\n')
|
|
fout.close
|
|
self.statusMessage.set("Configuration File Saved: %s" %(configname_full))
|
|
self.statusbar.configure( bg = 'white' )
|
|
try:
|
|
win_id.deiconify()
|
|
except:
|
|
pass
|
|
|
|
def Read_Config_File_Ex(self, config_file):
|
|
home_config1 = self.HOME_DIR + "/" + config_file
|
|
if ( os.path.isfile(home_config1) ):
|
|
self.Open_Settings_File(home_config1)
|
|
self.statusMessage.set("Configuration File Loaded: %s" %(config_file))
|
|
else:
|
|
self.statusMessage.set("Configuration File Not Found: %s" %(config_file))
|
|
#self.menu_View_Refresh()
|
|
|
|
def Write_Config_File_Ex(self, config_file):
|
|
config_data = self.WriteConfig()
|
|
configname_full = self.HOME_DIR + "/" + config_file
|
|
|
|
try:
|
|
fout = open(configname_full,'w')
|
|
except:
|
|
self.statusMessage.set("Unable to open file for writing: %s" %(configname_full))
|
|
self.statusbar.configure( bg = 'red' )
|
|
return
|
|
for line in config_data:
|
|
try:
|
|
fout.write(line+'\n')
|
|
except:
|
|
fout.write('(skipping line)\n')
|
|
fout.close
|
|
self.statusMessage.set("Configuration File Saved: %s" %(configname_full))
|
|
self.statusbar.configure( bg = 'white' )
|
|
|
|
################################################################################
|
|
def WriteConfig(self):
|
|
global Zero
|
|
header = []
|
|
header.append('( K40 Whisperer Settings: '+version+' )')
|
|
header.append('( by Scorch - 2019 )')
|
|
header.append("(=========================================================)")
|
|
# BOOL
|
|
header.append('(k40_whisperer_set include_Reng %s )' %( int(self.include_Reng.get()) ))
|
|
header.append('(k40_whisperer_set include_Veng %s )' %( int(self.include_Veng.get()) ))
|
|
header.append('(k40_whisperer_set include_Vcut %s )' %( int(self.include_Vcut.get()) ))
|
|
header.append('(k40_whisperer_set include_Gcde %s )' %( int(self.include_Gcde.get()) ))
|
|
header.append('(k40_whisperer_set include_Time %s )' %( int(self.include_Time.get()) ))
|
|
|
|
header.append('(k40_whisperer_set halftone %s )' %( int(self.halftone.get()) ))
|
|
header.append('(k40_whisperer_set HomeUR %s )' %( int(self.HomeUR.get()) ))
|
|
header.append('(k40_whisperer_set inputCSYS %s )' %( int(self.inputCSYS.get()) ))
|
|
header.append('(k40_whisperer_set advanced %s )' %( int(self.advanced.get()) ))
|
|
header.append('(k40_whisperer_set mirror %s )' %( int(self.mirror.get()) ))
|
|
header.append('(k40_whisperer_set rotate %s )' %( int(self.rotate.get()) ))
|
|
header.append('(k40_whisperer_set negate %s )' %( int(self.negate.get()) ))
|
|
|
|
header.append('(k40_whisperer_set engraveUP %s )' %( int(self.engraveUP.get()) ))
|
|
header.append('(k40_whisperer_set init_home %s )' %( int(self.init_home.get()) ))
|
|
header.append('(k40_whisperer_set post_home %s )' %( int(self.post_home.get()) ))
|
|
header.append('(k40_whisperer_set post_beep %s )' %( int(self.post_beep.get()) ))
|
|
header.append('(k40_whisperer_set post_disp %s )' %( int(self.post_disp.get()) ))
|
|
header.append('(k40_whisperer_set post_exec %s )' %( int(self.post_exec.get()) ))
|
|
|
|
header.append('(k40_whisperer_set pre_pr_crc %s )' %( int(self.pre_pr_crc.get()) ))
|
|
header.append('(k40_whisperer_set inside_first %s )' %( int(self.inside_first.get()) ))
|
|
|
|
header.append('(k40_whisperer_set comb_engrave %s )' %( int(self.comb_engrave.get()) ))
|
|
header.append('(k40_whisperer_set comb_vector %s )' %( int(self.comb_vector.get()) ))
|
|
header.append('(k40_whisperer_set zoom2image %s )' %( int(self.zoom2image.get()) ))
|
|
header.append('(k40_whisperer_set rotary %s )' %( int(self.rotary.get()) ))
|
|
header.append('(k40_whisperer_set reduced_mem %s )' %( int(self.reduced_mem.get()) ))
|
|
header.append('(k40_whisperer_set wait %s )' %( int(self.wait.get()) ))
|
|
|
|
header.append('(k40_whisperer_set trace_w_laser %s )' %( int(self.trace_w_laser.get()) ))
|
|
|
|
# STRING.get()
|
|
header.append('(k40_whisperer_set board_name %s )' %( self.board_name.get() ))
|
|
header.append('(k40_whisperer_set units %s )' %( self.units.get() ))
|
|
header.append('(k40_whisperer_set Reng_feed %s )' %( self.Reng_feed.get() ))
|
|
header.append('(k40_whisperer_set Veng_feed %s )' %( self.Veng_feed.get() ))
|
|
header.append('(k40_whisperer_set Vcut_feed %s )' %( self.Vcut_feed.get() ))
|
|
header.append('(k40_whisperer_set jog_step %s )' %( self.jog_step.get() ))
|
|
|
|
header.append('(k40_whisperer_set Reng_passes %s )' %( self.Reng_passes.get() ))
|
|
header.append('(k40_whisperer_set Veng_passes %s )' %( self.Veng_passes.get() ))
|
|
header.append('(k40_whisperer_set Vcut_passes %s )' %( self.Vcut_passes.get() ))
|
|
header.append('(k40_whisperer_set Gcde_passes %s )' %( self.Gcde_passes.get() ))
|
|
|
|
header.append('(k40_whisperer_set rast_step %s )' %( self.rast_step.get() ))
|
|
header.append('(k40_whisperer_set ht_size %s )' %( self.ht_size.get() ))
|
|
|
|
header.append('(k40_whisperer_set LaserXsize %s )' %( self.LaserXsize.get() ))
|
|
header.append('(k40_whisperer_set LaserYsize %s )' %( self.LaserYsize.get() ))
|
|
header.append('(k40_whisperer_set LaserXscale %s )' %( self.LaserXscale.get() ))
|
|
header.append('(k40_whisperer_set LaserYscale %s )' %( self.LaserYscale.get() ))
|
|
header.append('(k40_whisperer_set LaserRscale %s )' %( self.LaserRscale.get() ))
|
|
header.append('(k40_whisperer_set rapid_feed %s )' %( self.rapid_feed.get() ))
|
|
|
|
header.append('(k40_whisperer_set gotoX %s )' %( self.gotoX.get() ))
|
|
header.append('(k40_whisperer_set gotoY %s )' %( self.gotoY.get() ))
|
|
|
|
header.append('(k40_whisperer_set bezier_M1 %s )' %( self.bezier_M1.get() ))
|
|
header.append('(k40_whisperer_set bezier_M2 %s )' %( self.bezier_M2.get() ))
|
|
header.append('(k40_whisperer_set bezier_weight %s )' %( self.bezier_weight.get() ))
|
|
|
|
header.append('(k40_whisperer_set trace_gap %s )' %( self.trace_gap.get() ))
|
|
header.append('(k40_whisperer_set trace_speed %s )' %( self.trace_speed.get() ))
|
|
|
|
## header.append('(k40_whisperer_set unsharp_flag %s )' %( int(self.unsharp_flag.get()) ))
|
|
## header.append('(k40_whisperer_set unsharp_r %s )' %( self.unsharp_r.get() ))
|
|
## header.append('(k40_whisperer_set unsharp_p %s )' %( self.unsharp_p.get() ))
|
|
## header.append('(k40_whisperer_set unsharp_t %s )' %( self.unsharp_t.get() ))
|
|
|
|
header.append('(k40_whisperer_set t_timeout %s )' %( self.t_timeout.get() ))
|
|
header.append('(k40_whisperer_set n_timeouts %s )' %( self.n_timeouts.get() ))
|
|
|
|
header.append('(k40_whisperer_set ink_timeout %s )' %( self.ink_timeout.get() ))
|
|
|
|
|
|
header.append('(k40_whisperer_set designfile \042%s\042 )' %( self.DESIGN_FILE ))
|
|
header.append('(k40_whisperer_set inkscape_path \042%s\042 )' %( self.inkscape_path.get() ))
|
|
header.append('(k40_whisperer_set batch_path \042%s\042 )' %( self.batch_path.get() ))
|
|
|
|
header.append('(k40_whisperer_set fast_plot %s )' %( int(self.fastPlot.get()) ))
|
|
|
|
self.jog_step
|
|
header.append("(=========================================================)")
|
|
|
|
return header
|
|
######################################################
|
|
|
|
def Quit_Click(self, event):
|
|
self.statusMessage.set("Exiting!")
|
|
self.Release_USB
|
|
root.destroy()
|
|
|
|
def mousePanStart(self,event):
|
|
self.panx = event.x
|
|
self.pany = event.y
|
|
self.move_start_x = event.x
|
|
self.move_start_y = event.y
|
|
|
|
def mousePan(self,event):
|
|
all = self.PreviewCanvas.find_all()
|
|
dx = event.x-self.panx
|
|
dy = event.y-self.pany
|
|
|
|
self.PreviewCanvas.move('LaserTag', dx, dy)
|
|
self.lastx = self.lastx + dx
|
|
self.lasty = self.lasty + dy
|
|
self.panx = event.x
|
|
self.pany = event.y
|
|
|
|
def mousePanStop(self,event):
|
|
Xold = round(self.laserX,3)
|
|
Yold = round(self.laserY,3)
|
|
|
|
can_dx = event.x-self.move_start_x
|
|
can_dy = -(event.y-self.move_start_y)
|
|
|
|
dx = can_dx*self.PlotScale
|
|
dy = can_dy*self.PlotScale
|
|
if self.HomeUR.get():
|
|
dx = -dx
|
|
self.laserX,self.laserY = self.XY_in_bounds(dx,dy)
|
|
DXmils = round((self.laserX - Xold)*1000.0,0)
|
|
DYmils = round((self.laserY - Yold)*1000.0,0)
|
|
|
|
if self.Send_Rapid_Move(DXmils,DYmils):
|
|
self.menu_View_Refresh()
|
|
|
|
def right_mousePanStart(self,event):
|
|
self.s_panx = event.x
|
|
self.s_pany = event.y
|
|
self.s_move_start_x = event.x
|
|
self.s_move_start_y = event.y
|
|
|
|
def right_mousePan(self,event):
|
|
all = self.PreviewCanvas.find_all()
|
|
dx = event.x-self.s_panx
|
|
dy = event.y-self.s_pany
|
|
|
|
self.PreviewCanvas.move('LaserDot', dx, dy)
|
|
self.s_lastx = self.lastx + dx
|
|
self.s_lasty = self.lasty + dy
|
|
self.s_panx = event.x
|
|
self.s_pany = event.y
|
|
|
|
def right_mousePanStop(self,event):
|
|
Xold = round(self.laserX,3)
|
|
Yold = round(self.laserY,3)
|
|
can_dx = event.x-self.s_move_start_x
|
|
can_dy = -(event.y-self.s_move_start_y)
|
|
|
|
dx = can_dx*self.PlotScale
|
|
dy = can_dy*self.PlotScale
|
|
|
|
DX = round(dx*1000)
|
|
DY = round(dy*1000)
|
|
self.Move_Arbitrary(DX,DY)
|
|
self.menu_View_Refresh()
|
|
|
|
def LASER_Size(self):
|
|
MINX = 0.0
|
|
MAXY = 0.0
|
|
if self.units.get()=="in":
|
|
MAXX = float(self.LaserXsize.get())
|
|
MINY = -float(self.LaserYsize.get())
|
|
else:
|
|
MAXX = float(self.LaserXsize.get())/25.4
|
|
MINY = -float(self.LaserYsize.get())/25.4
|
|
|
|
return (MAXX-MINX,MAXY-MINY)
|
|
|
|
|
|
def XY_in_bounds(self,dx_inches,dy_inches, no_size=False):
|
|
MINX = 0.0
|
|
MAXY = 0.0
|
|
if self.units.get()=="in":
|
|
MAXX = float(self.LaserXsize.get())
|
|
MINY = -float(self.LaserYsize.get())
|
|
else:
|
|
MAXX = float(self.LaserXsize.get())/25.4
|
|
MINY = -float(self.LaserYsize.get())/25.4
|
|
|
|
if (self.inputCSYS.get() and self.RengData.image == None) or no_size:
|
|
xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
|
|
else:
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
|
|
X = self.laserX + dx_inches
|
|
Y = self.laserY + dy_inches
|
|
################
|
|
dx=xmax-xmin
|
|
dy=ymax-ymin
|
|
if X < MINX:
|
|
X = MINX
|
|
if X+dx > MAXX:
|
|
X = MAXX-dx
|
|
|
|
if Y-dy < MINY:
|
|
Y = MINY+dy
|
|
if Y > MAXY:
|
|
Y = MAXY
|
|
################
|
|
if not no_size:
|
|
XOFF = self.pos_offset[0]/1000.0
|
|
YOFF = self.pos_offset[1]/1000.0
|
|
if X+XOFF < MINX:
|
|
X= X +(MINX-(X+XOFF))
|
|
if X+XOFF > MAXX:
|
|
X= X -((X+XOFF)-MAXX)
|
|
if Y+YOFF < MINY:
|
|
Y= Y + (MINY-(Y+YOFF))
|
|
if Y+YOFF > MAXY:
|
|
Y= Y -((Y+YOFF)-MAXY)
|
|
################
|
|
X = round(X,3)
|
|
Y = round(Y,3)
|
|
return X,Y
|
|
|
|
## def computeAccurateVeng(self):
|
|
## self.update_gui("Optimize vector engrave.")
|
|
## self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords),data_sorted=True)
|
|
## self.refreshTime()
|
|
##
|
|
## def computeAccurateVcut(self):
|
|
## self.update_gui("Optimize vector cut.")
|
|
## self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True)
|
|
## self.refreshTime()
|
|
##
|
|
## def computeAccurateReng(self):
|
|
## self.update_gui("Calculating Raster engrave.")
|
|
## if self.RengData.image != None:
|
|
## if self.RengData.ecoords == []:
|
|
## self.make_raster_coords()
|
|
## self.RengData.sorted = True
|
|
## self.refreshTime()
|
|
|
|
|
|
def format_time(self,time_in_seconds):
|
|
# format the duration from seconds to something human readable
|
|
if time_in_seconds !=None and time_in_seconds >=0 :
|
|
s = round(time_in_seconds)
|
|
m,s=divmod(s,60)
|
|
h,m=divmod(m,60)
|
|
res = ""
|
|
if h > 0:
|
|
res = "%dh " %(h)
|
|
if m > 0:
|
|
res += "%dm " %(m)
|
|
if h == 0:
|
|
res += "%ds " %(s)
|
|
#L=len(res)
|
|
#for i in range(L,8):
|
|
# res = res+" "
|
|
return res
|
|
else :
|
|
return "?"
|
|
|
|
def refreshTime(self):
|
|
if not self.include_Time.get():
|
|
return
|
|
if self.units.get() == 'in':
|
|
factor = 60.0
|
|
else :
|
|
factor = 25.4
|
|
|
|
Raster_eng_feed = float(self.Reng_feed.get()) / factor
|
|
Vector_eng_feed = float(self.Veng_feed.get()) / factor
|
|
Vector_cut_feed = float(self.Vcut_feed.get()) / factor
|
|
|
|
Raster_eng_passes = float(self.Reng_passes.get())
|
|
Vector_eng_passes = float(self.Veng_passes.get())
|
|
Vector_cut_passes = float(self.Vcut_passes.get())
|
|
Gcode_passes = float(self.Gcde_passes.get())
|
|
|
|
rapid_feed = 100.0 / 25.4 # 100 mm/s move feed to be confirmed
|
|
|
|
if self.RengData.rpaths:
|
|
Reng_time=0
|
|
else:
|
|
Reng_time = None
|
|
Veng_time = 0
|
|
Vcut_time = 0
|
|
|
|
if self.RengData.len!=None:
|
|
# these equations are a terrible hack based on measured raster engraving times
|
|
# to be fixed someday
|
|
if Raster_eng_feed*60.0 <= 300:
|
|
accel_time=8.3264*(Raster_eng_feed*60.0)**(-0.7451)
|
|
else:
|
|
accel_time=2.5913*(Raster_eng_feed*60.0)**(-0.4795)
|
|
|
|
t_accel = self.RengData.n_scanlines * accel_time
|
|
Reng_time = ( (self.RengData.len)/Raster_eng_feed ) * Raster_eng_passes + t_accel
|
|
if self.VengData.len!=None:
|
|
Veng_time = (self.VengData.len / Vector_eng_feed + self.VengData.move / rapid_feed) * Vector_eng_passes
|
|
if self.VcutData.len!=None:
|
|
Vcut_time = (self.VcutData.len / Vector_cut_feed + self.VcutData.move / rapid_feed) * Vector_cut_passes
|
|
|
|
Gcode_time = self.GcodeData.gcode_time * Gcode_passes
|
|
|
|
self.Reng_time.set("Raster Engrave: %s" %(self.format_time(Reng_time)))
|
|
self.Veng_time.set("Vector Engrave: %s" %(self.format_time(Veng_time)))
|
|
self.Vcut_time.set(" Vector Cut: %s" %(self.format_time(Vcut_time)))
|
|
self.Gcde_time.set(" Gcode: %s" %(self.format_time(Gcode_time)))
|
|
|
|
##########################################
|
|
cszw = int(self.PreviewCanvas.cget("width"))
|
|
cszh = int(self.PreviewCanvas.cget("height"))
|
|
HUD_vspace = 15
|
|
HUD_X = cszw-5
|
|
HUD_Y = cszh-5
|
|
|
|
w = int(self.master.winfo_width())
|
|
h = int(self.master.winfo_height())
|
|
HUD_X2 = w-20
|
|
HUD_Y2 = h-75
|
|
|
|
self.PreviewCanvas.delete("HUD")
|
|
self.calc_button.place_forget()
|
|
|
|
if self.GcodeData.ecoords == []:
|
|
self.PreviewCanvas.create_text(HUD_X, HUD_Y , fill = "red" ,text =self.Vcut_time.get(), anchor="se",tags="HUD")
|
|
self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace , fill = "blue" ,text =self.Veng_time.get(), anchor="se",tags="HUD")
|
|
|
|
if (Reng_time==None):
|
|
#try:
|
|
# self.calc_button.place_forget()
|
|
#except:
|
|
# pass
|
|
#self.calc_button = Button(self.master,text="Calculate Raster Time", command=self.menu_Calc_Raster_Time)
|
|
self.calc_button.place(x=HUD_X2, y=HUD_Y2, width=120+20, height=17, anchor="se")
|
|
else:
|
|
self.calc_button.place_forget()
|
|
self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace*2, fill = "black",
|
|
text =self.Reng_time.get(), anchor="se",tags="HUD")
|
|
else:
|
|
self.PreviewCanvas.create_text(HUD_X, HUD_Y, fill = "black",text =self.Gcde_time.get(), anchor="se",tags="HUD")
|
|
##########################################
|
|
|
|
|
|
def Settings_ReLoad_Click(self, event):
|
|
win_id=self.grab_current()
|
|
|
|
def Close_Current_Window_Click(self,event=None):
|
|
current_name = event.widget.winfo_parent()
|
|
win_id = event.widget.nametowidget(current_name)
|
|
win_id.destroy()
|
|
|
|
# Left Column #
|
|
#############################
|
|
def Entry_Reng_feed_Check(self):
|
|
try:
|
|
value = float(self.Reng_feed.get())
|
|
vfactor=(25.4/60.0)/self.feed_factor()
|
|
low_limit = self.min_raster_speed*vfactor
|
|
if value < low_limit:
|
|
self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Reng_feed_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Reng_feed, self.Entry_Reng_feed_Check(), new=1)
|
|
#############################
|
|
def Entry_Veng_feed_Check(self):
|
|
try:
|
|
value = float(self.Veng_feed.get())
|
|
vfactor=(25.4/60.0)/self.feed_factor()
|
|
low_limit = self.min_vector_speed*vfactor
|
|
if value < low_limit:
|
|
self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Veng_feed_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Veng_feed, self.Entry_Veng_feed_Check(), new=1)
|
|
#############################
|
|
def Entry_Vcut_feed_Check(self):
|
|
try:
|
|
value = float(self.Vcut_feed.get())
|
|
vfactor=(25.4/60.0)/self.feed_factor()
|
|
low_limit = self.min_vector_speed*vfactor
|
|
if value < low_limit:
|
|
self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Vcut_feed_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Vcut_feed, self.Entry_Vcut_feed_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Step_Check(self):
|
|
try:
|
|
value = float(self.jog_step.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" Step should be greater than 0.0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Step_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Step, self.Entry_Step_Check(), new=1)
|
|
|
|
def Step_Plus(self,dummy=None):
|
|
self.jog_step.set(float(self.jog_step.get()) + 1)
|
|
|
|
def Step_Minus(self,dummy=None):
|
|
self.jog_step.set(float(self.jog_step.get()) - 1)
|
|
|
|
#############################
|
|
def Entry_GoToX_Check(self):
|
|
try:
|
|
value = float(self.gotoX.get())
|
|
if (value < 0.0) and (not self.HomeUR.get()):
|
|
self.statusMessage.set(" Value should be greater than 0.0 ")
|
|
return 2 # Value is invalid number
|
|
elif (value > 0.0) and self.HomeUR.get():
|
|
self.statusMessage.set(" Value should be less than 0.0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_GoToX_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_GoToX, self.Entry_GoToX_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_GoToY_Check(self):
|
|
try:
|
|
value = float(self.gotoY.get())
|
|
if value > 0.0:
|
|
self.statusMessage.set(" Value should be less than 0.0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_GoToY_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_GoToY, self.Entry_GoToY_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Rstep_Check(self):
|
|
try:
|
|
value = self.get_raster_step_1000in()
|
|
if value <= 0 or value > 63:
|
|
self.statusMessage.set(" Step should be between 0.001 and 0.063 in")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Rstep_Callback(self, varName, index, mode):
|
|
self.RengData.reset_path()
|
|
self.refreshTime()
|
|
self.entry_set(self.Entry_Rstep, self.Entry_Rstep_Check(), new=1)
|
|
|
|
## #############################
|
|
## def Entry_Unsharp_Radius_Check(self):
|
|
## try:
|
|
## value = float(self.unsharp_r.get())
|
|
## if value <= 0:
|
|
## self.statusMessage.set(" Radius should be greater than zero.")
|
|
## return 2 # Value is invalid number
|
|
## except:
|
|
## return 3 # Value not a number
|
|
## self.menu_View_Refresh_Callback()
|
|
## return 0 # Value is a valid number
|
|
## def Entry_Unsharp_Radius_Callback(self, varName, index, mode):
|
|
## self.entry_set(self.Entry_Unsharp_Radius, self.Entry_Unsharp_Radius_Check(), new=1)
|
|
##
|
|
##
|
|
## #############################
|
|
## def Entry_Unsharp_Percent_Check(self):
|
|
## try:
|
|
## value = float(self.unsharp_p.get())
|
|
## if value <= 0:
|
|
## self.statusMessage.set(" Percent should be greater than zero.")
|
|
## return 2 # Value is invalid number
|
|
## except:
|
|
## return 3 # Value not a number
|
|
## self.menu_View_Refresh_Callback()
|
|
## return 0 # Value is a valid number
|
|
## def Entry_Unsharp_Percent_Callback(self, varName, index, mode):
|
|
## self.entry_set(self.Entry_Unsharp_Percent, self.Entry_Unsharp_Percent_Check(), new=1)
|
|
##
|
|
## #############################
|
|
## def Entry_Unsharp_Threshold_Check(self):
|
|
## try:
|
|
## value = float(self.unsharp_t.get())
|
|
## if value < 0:
|
|
## self.statusMessage.set(" Threshold should be greater than or equal to zero.")
|
|
## return 2 # Value is invalid number
|
|
## except:
|
|
## return 3 # Value not a number
|
|
## self.menu_View_Refresh_Callback()
|
|
## return 0 # Value is a valid number
|
|
## def Entry_Unsharp_Threshold_Callback(self, varName, index, mode):
|
|
## self.entry_set(self.Entry_Unsharp_Threshold, self.Entry_Unsharp_Threshold_Check(), new=1)
|
|
|
|
#############################
|
|
# End Left Column #
|
|
#############################
|
|
def bezier_weight_Callback(self, varName=None, index=None, mode=None):
|
|
self.Reset_RasterPath_and_Update_Time()
|
|
self.bezier_plot()
|
|
|
|
def bezier_M1_Callback(self, varName=None, index=None, mode=None):
|
|
self.Reset_RasterPath_and_Update_Time()
|
|
self.bezier_plot()
|
|
|
|
def bezier_M2_Callback(self, varName=None, index=None, mode=None):
|
|
self.Reset_RasterPath_and_Update_Time()
|
|
self.bezier_plot()
|
|
|
|
def bezier_plot(self):
|
|
self.BezierCanvas.delete('bez')
|
|
|
|
#self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="black", capstyle="round", width = 2, tags='bez')
|
|
M1 = float(self.bezier_M1.get())
|
|
M2 = float(self.bezier_M2.get())
|
|
w = float(self.bezier_weight.get())
|
|
num = 10
|
|
x,y = self.generate_bezier(M1,M2,w,n=num)
|
|
for i in range(0,num):
|
|
self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="black", \
|
|
capstyle="round", width = 2, tags='bez')
|
|
self.BezierCanvas.create_text(128, 0, text="Output Level vs. Input Level",anchor="n", tags='bez')
|
|
|
|
|
|
#############################
|
|
def Entry_Ink_Timeout_Check(self):
|
|
try:
|
|
value = float(self.ink_timeout.get())
|
|
if value < 0.0:
|
|
self.statusMessage.set(" Timeout should be 0 or greater")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Ink_Timeout_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Ink_Timeout,self.Entry_Ink_Timeout_Check(), new=1)
|
|
|
|
|
|
#############################
|
|
def Entry_Timeout_Check(self):
|
|
try:
|
|
value = float(self.t_timeout.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" Timeout should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Timeout_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_N_Timeouts_Check(self):
|
|
try:
|
|
value = float(self.n_timeouts.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" N_Timeouts should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_N_Timeouts_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_N_EGV_Passes_Check(self):
|
|
try:
|
|
value = int(self.n_egv_passes.get())
|
|
if value < 1:
|
|
self.statusMessage.set(" EGV passes should be 1 or higher")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_N_EGV_Passes_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_N_EGV_Passes,self.Entry_N_EGV_Passes_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Laser_Area_Width_Check(self):
|
|
try:
|
|
value = float(self.LaserXsize.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" Width should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Laser_Area_Width_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Laser_Area_Height_Check(self):
|
|
try:
|
|
value = float(self.LaserYsize.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" Height should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Laser_Area_Height_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(), new=1)
|
|
|
|
|
|
#############################
|
|
def Entry_Laser_X_Scale_Check(self):
|
|
try:
|
|
value = float(self.LaserXscale.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" X scale factor should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.Reset_RasterPath_and_Update_Time()
|
|
return 0 # Value is a valid number
|
|
def Entry_Laser_X_Scale_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(), new=1)
|
|
#############################
|
|
def Entry_Laser_Y_Scale_Check(self):
|
|
try:
|
|
value = float(self.LaserYscale.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" Y scale factor should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.Reset_RasterPath_and_Update_Time()
|
|
return 0 # Value is a valid number
|
|
def Entry_Laser_Y_Scale_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Laser_R_Scale_Check(self):
|
|
try:
|
|
value = float(self.LaserRscale.get())
|
|
if value <= 0.0:
|
|
self.statusMessage.set(" Rotary scale factor should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.Reset_RasterPath_and_Update_Time()
|
|
return 0 # Value is a valid number
|
|
def Entry_Laser_R_Scale_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Laser_R_Scale,self.Entry_Laser_R_Scale_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Laser_Rapid_Feed_Check(self):
|
|
try:
|
|
value = float(self.rapid_feed.get())
|
|
vfactor=(25.4/60.0)/self.feed_factor()
|
|
low_limit = 1.0*vfactor
|
|
if value !=0 and value < low_limit:
|
|
self.statusMessage.set(" Rapid feed should be greater than or equal to %f (or 0 for default speed) " %(low_limit))
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Laser_Rapid_Feed_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Laser_Rapid_Feed,self.Entry_Laser_Rapid_Feed_Check(), new=1)
|
|
|
|
# Advanced Column #
|
|
#############################
|
|
def Entry_Reng_passes_Check(self):
|
|
try:
|
|
value = int(self.Reng_passes.get())
|
|
if value < 1:
|
|
self.statusMessage.set(" Number of passes should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Reng_passes_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Reng_passes, self.Entry_Reng_passes_Check(), new=1)
|
|
#############################
|
|
def Entry_Veng_passes_Check(self):
|
|
try:
|
|
value = int(self.Veng_passes.get())
|
|
if value < 1:
|
|
self.statusMessage.set(" Number of passes should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Veng_passes_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Veng_passes, self.Entry_Veng_passes_Check(), new=1)
|
|
#############################
|
|
def Entry_Vcut_passes_Check(self):
|
|
try:
|
|
value = int(self.Vcut_passes.get())
|
|
if value < 1:
|
|
self.statusMessage.set(" Number of passes should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Vcut_passes_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Vcut_passes, self.Entry_Vcut_passes_Check(), new=1)
|
|
|
|
#############################
|
|
def Entry_Gcde_passes_Check(self):
|
|
try:
|
|
value = int(self.Gcde_passes.get())
|
|
if value < 1:
|
|
self.statusMessage.set(" Number of passes should be greater than 0 ")
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Gcde_passes_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Gcde_passes, self.Entry_Gcde_passes_Check(), new=1)
|
|
|
|
#############################
|
|
|
|
def Entry_Trace_Gap_Check(self):
|
|
try:
|
|
value = float(self.trace_gap.get())
|
|
except:
|
|
return 3 # Value not a number
|
|
self.menu_View_Refresh()
|
|
return 0 # Value is a valid number
|
|
def Entry_Trace_Gap_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Trace_Gap, self.Entry_Trace_Gap_Check(), new=1)
|
|
|
|
#############################
|
|
|
|
def Entry_Trace_Speed_Check(self):
|
|
try:
|
|
value = float(self.trace_speed.get())
|
|
vfactor=(25.4/60.0)/self.feed_factor()
|
|
low_limit = self.min_vector_speed*vfactor
|
|
if value < low_limit:
|
|
self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
self.refreshTime()
|
|
return 0 # Value is a valid number
|
|
def Entry_Trace_Speed_Callback(self, varName, index, mode):
|
|
self.entry_set(self.Entry_Trace_Speed, self.Entry_Trace_Speed_Check(), new=1)
|
|
|
|
#############################
|
|
def Inkscape_Path_Click(self, event):
|
|
self.Inkscape_Path_Message()
|
|
win_id=self.grab_current()
|
|
newfontdir = askopenfilename(filetypes=[("Executable Files",("inkscape.exe","*inkscape*")),\
|
|
("All Files","*")],\
|
|
initialdir=self.inkscape_path.get())
|
|
if newfontdir != "" and newfontdir != ():
|
|
if type(newfontdir) is not str:
|
|
newfontdir = newfontdir.encode("utf-8")
|
|
self.inkscape_path.set(newfontdir)
|
|
|
|
try:
|
|
win_id.withdraw()
|
|
win_id.deiconify()
|
|
except:
|
|
pass
|
|
|
|
def Inkscape_Path_Message(self, event=None):
|
|
if self.inkscape_warning == False:
|
|
self.inkscape_warning = True
|
|
msg1 = "Beware:"
|
|
msg2 = "Most people should leave the 'Inkscape Executable' entry field blank. "
|
|
msg3 = "K40 Whisperer will find Inkscape in one of the the standard locations after you install Inkscape."
|
|
message_box(msg1, msg2+msg3)
|
|
|
|
|
|
def Entry_units_var_Callback(self):
|
|
if (self.units.get() == 'in') and (self.funits.get()=='mm/s'):
|
|
self.funits.set('in/min')
|
|
self.Scale_Linear_Inputs('in')
|
|
elif (self.units.get() == 'mm') and (self.funits.get()=='in/min'):
|
|
self.funits.set('mm/s')
|
|
self.Scale_Linear_Inputs('mm')
|
|
|
|
def Scale_Linear_Inputs(self, new_units=None):
|
|
if new_units=='in':
|
|
self.units_scale = 1.0
|
|
factor = 1/25.4
|
|
vfactor = 60.0/25.4
|
|
elif new_units=='mm':
|
|
factor = 25.4
|
|
vfactor = 25.4/60.0
|
|
self.units_scale = 25.4
|
|
else:
|
|
return
|
|
self.LaserXsize.set ( self.Scale_Text_Value('%.2f',self.LaserXsize.get() ,factor ) )
|
|
self.LaserYsize.set ( self.Scale_Text_Value('%.2f',self.LaserYsize.get() ,factor ) )
|
|
self.jog_step.set ( self.Scale_Text_Value('%.3f',self.jog_step.get() ,factor ) )
|
|
self.gotoX.set ( self.Scale_Text_Value('%.3f',self.gotoX.get() ,factor ) )
|
|
self.gotoY.set ( self.Scale_Text_Value('%.3f',self.gotoY.get() ,factor ) )
|
|
self.Reng_feed.set ( self.Scale_Text_Value('%.1f',self.Reng_feed.get() ,vfactor) )
|
|
self.Veng_feed.set ( self.Scale_Text_Value('%.1f',self.Veng_feed.get() ,vfactor) )
|
|
self.Vcut_feed.set ( self.Scale_Text_Value('%.1f',self.Vcut_feed.get() ,vfactor) )
|
|
self.trace_speed.set( self.Scale_Text_Value('%.1f',self.trace_speed.get() ,vfactor) )
|
|
self.rapid_feed.set ( self.Scale_Text_Value('%.1f',self.rapid_feed.get() ,vfactor) )
|
|
|
|
def Scale_Text_Value(self,format_txt,Text_Value,factor):
|
|
try:
|
|
return format_txt %(float(Text_Value)*factor )
|
|
except:
|
|
return ''
|
|
|
|
def menu_File_Open_Settings_File(self,event=None):
|
|
init_dir = os.path.dirname(self.DESIGN_FILE)
|
|
if ( not os.path.isdir(init_dir) ):
|
|
init_dir = self.HOME_DIR
|
|
fileselect = askopenfilename(filetypes=[("Settings Files","*.txt"),\
|
|
("All Files","*")],\
|
|
initialdir=init_dir)
|
|
if fileselect != '' and fileselect != ():
|
|
self.Open_Settings_File(fileselect)
|
|
|
|
def Reduced_Memory_Callback(self, varName, index, mode):
|
|
if self.RengData.image != None:
|
|
self.menu_Reload_Design()
|
|
#print("Reload_Design")
|
|
|
|
def menu_Reload_Design(self,event=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
file_full = self.DESIGN_FILE
|
|
file_name = os.path.basename(file_full)
|
|
if ( os.path.isfile(file_full) ):
|
|
filename = file_full
|
|
elif ( os.path.isfile( file_name ) ):
|
|
filename = file_name
|
|
elif ( os.path.isfile( self.HOME_DIR+"/"+file_name ) ):
|
|
filename = self.HOME_DIR+"/"+file_name
|
|
else:
|
|
self.statusMessage.set("file not found: %s" %(os.path.basename(file_full)) )
|
|
self.statusbar.configure( bg = 'red' )
|
|
return
|
|
|
|
Name, fileExtension = os.path.splitext(filename)
|
|
TYPE=fileExtension.upper()
|
|
if TYPE=='.DXF':
|
|
self.Open_DXF(filename)
|
|
elif TYPE=='.SVG':
|
|
self.Open_SVG(filename)
|
|
elif TYPE=='.EGV':
|
|
self.EGV_Send_Window(filename)
|
|
else:
|
|
self.Open_G_Code(filename)
|
|
self.menu_View_Refresh()
|
|
|
|
|
|
|
|
def menu_File_Open_Design(self,event=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
init_dir = os.path.dirname(self.DESIGN_FILE)
|
|
if ( not os.path.isdir(init_dir) ):
|
|
init_dir = self.HOME_DIR
|
|
|
|
design_types = ("Design Files", ("*.svg","*.dxf"))
|
|
gcode_types = ("G-Code Files", ("*.ngc","*.gcode","*.g","*.tap"))
|
|
|
|
Name, fileExtension = os.path.splitext(self.DESIGN_FILE)
|
|
TYPE=fileExtension.upper()
|
|
if TYPE != '.DXF' and TYPE!='.SVG' and TYPE!='.EGV' and TYPE!='':
|
|
default_types = gcode_types
|
|
else:
|
|
default_types = design_types
|
|
|
|
fileselect = askopenfilename(filetypes=[default_types,
|
|
("G-Code Files ", ("*.ngc","*.gcode","*.g","*.tap")),\
|
|
("DXF Files ","*.dxf"),\
|
|
("SVG Files ","*.svg"),\
|
|
("All Files ","*"),\
|
|
("Design Files ", ("*.svg","*.dxf"))],\
|
|
initialdir=init_dir)
|
|
|
|
if fileselect == () or (not os.path.isfile(fileselect)):
|
|
return
|
|
|
|
Name, fileExtension = os.path.splitext(fileselect)
|
|
self.update_gui("Opening '%s'" % fileselect )
|
|
TYPE=fileExtension.upper()
|
|
if TYPE=='.DXF':
|
|
self.Open_DXF(fileselect)
|
|
elif TYPE=='.SVG':
|
|
self.Open_SVG(fileselect)
|
|
else:
|
|
self.Open_G_Code(fileselect)
|
|
|
|
|
|
self.DESIGN_FILE = fileselect
|
|
self.menu_View_Refresh()
|
|
|
|
def menu_File_Raster_Engrave(self):
|
|
self.menu_File_save_EGV(operation_type="Raster_Eng")
|
|
|
|
def menu_File_Vector_Engrave(self):
|
|
self.menu_File_save_EGV(operation_type="Vector_Eng")
|
|
|
|
def menu_File_Vector_Cut(self):
|
|
self.menu_File_save_EGV(operation_type="Vector_Cut")
|
|
|
|
def menu_File_G_Code(self):
|
|
self.menu_File_save_EGV(operation_type="Gcode_Cut")
|
|
|
|
def menu_File_Raster_Vector_Engrave(self):
|
|
self.menu_File_save_EGV(operation_type="Raster_Eng-Vector_Eng")
|
|
|
|
def menu_File_Vector_Engrave_Cut(self):
|
|
self.menu_File_save_EGV(operation_type="Vector_Eng-Vector_Cut")
|
|
|
|
def menu_File_Raster_Vector_Cut(self):
|
|
self.menu_File_save_EGV(operation_type="Raster_Eng-Vector_Eng-Vector_Cut")
|
|
|
|
def menu_File_save_EGV(self,operation_type=None,default_name="out.EGV"):
|
|
self.stop[0]=False
|
|
if DEBUG:
|
|
start=time()
|
|
fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
|
|
init_file=os.path.basename(fileName)
|
|
default_name = init_file+"_"+operation_type
|
|
|
|
if self.EGV_FILE != None:
|
|
init_dir = os.path.dirname(self.EGV_FILE)
|
|
else:
|
|
init_dir = os.path.dirname(self.DESIGN_FILE)
|
|
|
|
if ( not os.path.isdir(init_dir) ):
|
|
init_dir = self.HOME_DIR
|
|
|
|
fileName, fileExtension = os.path.splitext(default_name)
|
|
init_file=os.path.basename(fileName)
|
|
|
|
filename = asksaveasfilename(defaultextension='.EGV', \
|
|
filetypes=[("EGV File","*.EGV")],\
|
|
initialdir=init_dir,\
|
|
initialfile= init_file )
|
|
|
|
if filename != '' and filename != ():
|
|
|
|
if operation_type.find("Raster_Eng") > -1:
|
|
self.make_raster_coords()
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No raster data to engrave")
|
|
|
|
self.send_data(operation_type=operation_type, output_filename=filename)
|
|
self.EGV_FILE = filename
|
|
if DEBUG:
|
|
print("time = %d seconds" %(int(time()-start)))
|
|
self.stop[0]=True
|
|
|
|
|
|
|
|
def menu_File_Open_EGV(self):
|
|
init_dir = os.path.dirname(self.DESIGN_FILE)
|
|
if ( not os.path.isdir(init_dir) ):
|
|
init_dir = self.HOME_DIR
|
|
fileselect = askopenfilename(filetypes=[("Engraver Files", ("*.egv","*.EGV")),\
|
|
("All Files","*")],\
|
|
initialdir=init_dir)
|
|
if fileselect != '' and fileselect != ():
|
|
self.resetPath()
|
|
self.DESIGN_FILE = fileselect
|
|
self.EGV_Send_Window(fileselect)
|
|
|
|
def Open_EGV(self,filemname,n_passes=1):
|
|
self.stop[0]=False
|
|
EGV_data=[]
|
|
value1 = ""
|
|
value2 = ""
|
|
value3 = ""
|
|
value4 = ""
|
|
data=""
|
|
#value1 and value2 are the absolute y and x starting positions
|
|
#value3 and value4 are the absolute y and x end positions
|
|
with open(filemname) as f:
|
|
while True:
|
|
## Skip header
|
|
c = f.read(1)
|
|
while c!="%" and c:
|
|
c = f.read(1)
|
|
## Read 1st Value
|
|
c = f.read(1)
|
|
while c!="%" and c:
|
|
value1 = value1 + c
|
|
c = f.read(1)
|
|
y_start_mils = int(value1)
|
|
## Read 2nd Value
|
|
c = f.read(1)
|
|
while c!="%" and c:
|
|
value2 = value2 + c
|
|
c = f.read(1)
|
|
x_start_mils = int(value2)
|
|
## Read 3rd Value
|
|
c = f.read(1)
|
|
while c!="%" and c:
|
|
value3 = value3 + c
|
|
c = f.read(1)
|
|
y_end_mils = int(value3)
|
|
## Read 4th Value
|
|
c = f.read(1)
|
|
while c!="%" and c:
|
|
value4 = value4 + c
|
|
c = f.read(1)
|
|
x_end_mils = int(value4)
|
|
break
|
|
|
|
## Read Data
|
|
while True:
|
|
c = f.read(1)
|
|
if not c:
|
|
break
|
|
if c=='\n' or c==' ' or c=='\r':
|
|
pass
|
|
else:
|
|
data=data+"%c" %c
|
|
EGV_data.append(ord(c))
|
|
|
|
if ( (x_end_mils != 0) or (y_end_mils != 0) ):
|
|
n_passes=1
|
|
else:
|
|
x_start_mils = 0
|
|
y_start_mils = 0
|
|
|
|
try:
|
|
self.send_egv_data(EGV_data,n_passes)
|
|
except MemoryError as e:
|
|
msg1 = "Memory Error:"
|
|
msg2 = "Memory Error: Out of Memory."
|
|
self.statusMessage.set(msg2)
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
|
|
except Exception as e:
|
|
msg1 = "Sending Data Stopped: "
|
|
msg2 = "%s" %(e)
|
|
if msg2 == "":
|
|
formatted_lines = traceback.format_exc().splitlines()
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
|
|
#rapid move back to starting position
|
|
dxmils = -(x_end_mils - x_start_mils)
|
|
dymils = y_end_mils - y_start_mils
|
|
self.Send_Rapid_Move(dxmils,dxmils)
|
|
self.stop[0]=True
|
|
|
|
def Open_SVG(self,filemname):
|
|
self.resetPath()
|
|
self.SVG_FILE = filemname
|
|
if self.reduced_mem.get():
|
|
self.input_dpi = 500.0
|
|
else:
|
|
self.input_dpi = 1000.0
|
|
svg_reader = SVG_READER()
|
|
svg_reader.image_dpi = self.input_dpi
|
|
svg_reader.set_inkscape_path(self.inkscape_path.get())
|
|
svg_reader.timout = int(float( self.ink_timeout.get())*60.0)
|
|
dialog_pxpi = None
|
|
dialog_viewbox = None
|
|
try:
|
|
try:
|
|
try:
|
|
svg_reader.parse_svg(self.SVG_FILE)
|
|
svg_reader.make_paths()
|
|
except SVG_PXPI_EXCEPTION as e:
|
|
pxpi_dialog = pxpiDialog(root,
|
|
self.units.get(),
|
|
svg_reader.SVG_Size,
|
|
svg_reader.SVG_ViewBox,
|
|
svg_reader.SVG_inkscape_version)
|
|
|
|
svg_reader = SVG_READER()
|
|
svg_reader.image_dpi = self.input_dpi
|
|
svg_reader.set_inkscape_path(self.inkscape_path.get())
|
|
svg_reader.timout = int(float( self.ink_timeout.get())*60.0)
|
|
if pxpi_dialog.result == None:
|
|
return
|
|
|
|
dialog_pxpi,dialog_viewbox = pxpi_dialog.result
|
|
svg_reader.parse_svg(self.SVG_FILE)
|
|
svg_reader.set_size(dialog_pxpi,dialog_viewbox)
|
|
svg_reader.make_paths()
|
|
|
|
except SVG_TEXT_EXCEPTION as e:
|
|
svg_reader = SVG_READER()
|
|
svg_reader.image_dpi = self.input_dpi
|
|
svg_reader.set_inkscape_path(self.inkscape_path.get())
|
|
svg_reader.timout = int(float( self.ink_timeout.get())*60.0)
|
|
self.statusMessage.set("Converting TEXT to PATHS.")
|
|
self.master.update()
|
|
svg_reader.parse_svg(self.SVG_FILE)
|
|
if dialog_pxpi != None and dialog_viewbox != None:
|
|
svg_reader.set_size(dialog_pxpi,dialog_viewbox)
|
|
svg_reader.make_paths(txt2paths=True)
|
|
|
|
except Exception as e:
|
|
msg1 = "SVG Error: "
|
|
msg2 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
return
|
|
except:
|
|
self.statusMessage.set("Unable To open SVG File: %s" %(filemname))
|
|
debug_message(traceback.format_exc())
|
|
return
|
|
xmax = svg_reader.Xsize/25.4
|
|
ymax = svg_reader.Ysize/25.4
|
|
xmin = 0
|
|
ymin = 0
|
|
|
|
self.Design_bounds = (xmin,xmax,ymin,ymax)
|
|
|
|
##########################
|
|
### Create ECOORDS ###
|
|
##########################
|
|
self.VcutData.make_ecoords(svg_reader.cut_lines,scale=1/25.4)
|
|
self.VengData.make_ecoords(svg_reader.eng_lines,scale=1/25.4)
|
|
|
|
##########################
|
|
### Load Image ###
|
|
##########################
|
|
self.RengData.set_image(svg_reader.raster_PIL)
|
|
|
|
if (self.RengData.image != None):
|
|
self.wim, self.him = self.RengData.image.size
|
|
self.aspect_ratio = float(self.wim-1) / float(self.him-1)
|
|
#self.make_raster_coords()
|
|
self.refreshTime()
|
|
margin=0.0625 # A bit of margin to prevent the warningwindow for designs that are close to being within the bounds
|
|
if self.Design_bounds[0] > self.VengData.bounds[0]+margin or\
|
|
self.Design_bounds[0] > self.VcutData.bounds[0]+margin or\
|
|
self.Design_bounds[1] < self.VengData.bounds[1]-margin or\
|
|
self.Design_bounds[1] < self.VcutData.bounds[1]-margin or\
|
|
self.Design_bounds[2] > self.VengData.bounds[2]+margin or\
|
|
self.Design_bounds[2] > self.VcutData.bounds[2]+margin or\
|
|
self.Design_bounds[3] < self.VengData.bounds[3]-margin or\
|
|
self.Design_bounds[3] < self.VcutData.bounds[3]-margin:
|
|
line1 = "Warning:\n"
|
|
line2 = "There is vector cut or vector engrave data located outside of the SVG page bounds.\n\n"
|
|
line3 = "K40 Whisperer will attempt to use all of the vector data. "
|
|
line4 = "Please verify that the vector data is not outside of your lasers working area before engraving."
|
|
message_box("Warning", line1+line2+line3+line4)
|
|
|
|
|
|
#####################################################################
|
|
def make_raster_coords(self):
|
|
if self.RengData.rpaths:
|
|
return
|
|
try:
|
|
hcoords=[]
|
|
if (self.RengData.image != None and self.RengData.ecoords==[]):
|
|
ecoords=[]
|
|
cutoff=128
|
|
image_temp = self.RengData.image.convert("L")
|
|
## if self.unsharp_flag.get():
|
|
## from PIL import ImageFilter
|
|
## #image_temp = image_temp.filter(UnsharpMask(radius=self.unsharp_r, percent=self.unsharp_p, threshold=self.unsharp_t))
|
|
## filter = ImageFilter.UnsharpMask()
|
|
## filter.radius = float(self.unsharp_r.get()) # radius 3-5 pixels
|
|
## filter.percent = int(float(self.unsharp_p.get())) # precent 500%
|
|
## filter.threshold = int(float(self.unsharp_t.get())) # Threshold 0
|
|
## image_temp = image_temp.filter(filter)
|
|
|
|
if self.negate.get():
|
|
image_temp = ImageOps.invert(image_temp)
|
|
|
|
if self.mirror.get():
|
|
image_temp = ImageOps.mirror(image_temp)
|
|
|
|
if self.rotate.get():
|
|
#image_temp = image_temp.rotate(90,expand=True)
|
|
image_temp = self.rotate_raster(image_temp)
|
|
|
|
Xscale = float(self.LaserXscale.get())
|
|
Yscale = float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
|
|
if Xscale != 1.0 or Yscale != 1.0:
|
|
wim,him = image_temp.size
|
|
nw = int(wim*Xscale)
|
|
nh = int(him*Yscale)
|
|
image_temp = image_temp.resize((nw,nh))
|
|
|
|
|
|
if self.halftone.get():
|
|
ht_size_mils = round( self.input_dpi / float(self.ht_size.get()) ,1)
|
|
npixels = int( round(ht_size_mils,1) )
|
|
if npixels == 0:
|
|
return
|
|
wim,him = image_temp.size
|
|
# Convert to Halftoning and save
|
|
nw=int(wim / npixels)
|
|
nh=int(him / npixels)
|
|
image_temp = image_temp.resize((nw,nh))
|
|
|
|
image_temp = self.convert_halftoning(image_temp)
|
|
image_temp = image_temp.resize((wim,him))
|
|
else:
|
|
image_temp = image_temp.point(lambda x: 0 if x<128 else 255, '1')
|
|
|
|
if DEBUG:
|
|
image_name = os.path.expanduser("~")+"/IMAGE.png"
|
|
image_temp.save(image_name,"PNG")
|
|
|
|
Reng_np = image_temp.load()
|
|
wim,him = image_temp.size
|
|
del image_temp
|
|
#######################################
|
|
x=0
|
|
y=0
|
|
loop=1
|
|
LENGTH=0
|
|
n_scanlines = 0
|
|
|
|
my_hull = hull2D()
|
|
bignumber = 9999999;
|
|
Raster_step = int(self.get_raster_step_1000in())
|
|
timestamp=0
|
|
im_height_mils = int(him/self.input_dpi*1000.0)
|
|
for i_step in range(0,im_height_mils,Raster_step):
|
|
i=floor(i_step*self.input_dpi/1000.0)
|
|
#print(i_step,i)
|
|
stamp=int(3*time()) #update every 1/3 of a second
|
|
if (stamp != timestamp):
|
|
timestamp=stamp #interlock
|
|
self.statusMessage.set("Creating Scan Lines: %.1f %%" %( (100.0*i)/him ) )
|
|
self.master.update()
|
|
if self.stop[0]==True:
|
|
raise Exception("Action stopped by User.")
|
|
line = []
|
|
cnt=1
|
|
LEFT = bignumber;
|
|
RIGHT =-bignumber;
|
|
for j in range(1,wim):
|
|
if (Reng_np[j,i] == Reng_np[j-1,i]):
|
|
cnt = cnt+1
|
|
else:
|
|
if Reng_np[j-1,i]:
|
|
laser = "U"
|
|
else:
|
|
laser = "D"
|
|
LEFT = min(j-cnt,LEFT)
|
|
RIGHT = max(j,RIGHT)
|
|
|
|
line.append((cnt,laser))
|
|
cnt=1
|
|
if Reng_np[j-1,i] > cutoff:
|
|
laser = "U"
|
|
else:
|
|
laser = "D"
|
|
LEFT = min(j-cnt,LEFT)
|
|
RIGHT = max(j,RIGHT)
|
|
|
|
line.append((cnt,laser))
|
|
if LEFT != bignumber and RIGHT != -bignumber:
|
|
LENGTH = LENGTH + (RIGHT - LEFT)/self.input_dpi
|
|
n_scanlines = n_scanlines + 1
|
|
|
|
y=(im_height_mils-i_step)/1000.0
|
|
x=0
|
|
if LEFT != bignumber:
|
|
hcoords.append([LEFT/self.input_dpi,y])
|
|
if RIGHT != -bignumber:
|
|
hcoords.append([RIGHT/self.input_dpi,y])
|
|
if hcoords!=[]:
|
|
hcoords = my_hull.convexHullecoords(hcoords)
|
|
|
|
rng = list(range(0,len(line),1))
|
|
|
|
for i in rng:
|
|
seg = line[i]
|
|
delta = seg[0]/self.input_dpi
|
|
if seg[1]=="D":
|
|
loop=loop+1
|
|
ecoords.append([x ,y,loop])
|
|
ecoords.append([x+delta,y,loop])
|
|
x = x + delta
|
|
self.RengData.set_ecoords(ecoords,data_sorted=True)
|
|
self.RengData.len=LENGTH
|
|
self.RengData.n_scanlines = n_scanlines
|
|
#Set Flag indicating raster paths have been calculated
|
|
self.RengData.rpaths = True
|
|
self.RengData.hull_coords = hcoords
|
|
|
|
except MemoryError as e:
|
|
msg1 = "Memory Error:"
|
|
msg2 = "Memory Error: Out of Memory."
|
|
self.statusMessage.set(msg2)
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
|
|
except Exception as e:
|
|
msg1 = "Making Raster Coords Stopped: "
|
|
msg2 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
#######################################################################
|
|
|
|
|
|
def rotate_raster(self,image_in):
|
|
wim,him = image_in.size
|
|
im_rotated = Image.new("L", (him, wim), "white")
|
|
|
|
image_in_np = image_in.load()
|
|
im_rotated_np = im_rotated.load()
|
|
|
|
for i in range(1,him):
|
|
for j in range(1,wim):
|
|
im_rotated_np[i,wim-j] = image_in_np[j,i]
|
|
return im_rotated
|
|
|
|
def get_raster_step_1000in(self):
|
|
val_in = float(self.rast_step.get())
|
|
value = int(round(val_in*1000.0,1))
|
|
return value
|
|
|
|
|
|
def generate_bezier(self,M1,M2,w,n=100):
|
|
if (M1==M2):
|
|
x1=0
|
|
y1=0
|
|
else:
|
|
x1 = 255*(1-M2)/(M1-M2)
|
|
y1 = M1*x1
|
|
x=[]
|
|
y=[]
|
|
# Calculate Bezier Curve
|
|
for step in range(0,n+1):
|
|
t = float(step)/float(n)
|
|
Ct = 1 / ( pow(1-t,2)+2*(1-t)*t*w+pow(t,2) )
|
|
x.append( Ct*( 2*(1-t)*t*w*x1+pow(t,2)*255) )
|
|
y.append( Ct*( 2*(1-t)*t*w*y1+pow(t,2)*255) )
|
|
return x,y
|
|
|
|
'''This Example opens an Image and transform the image into halftone. -Isai B. Cicourel'''
|
|
# Create a Half-tone version of the image
|
|
def convert_halftoning(self,image):
|
|
image = image.convert('L')
|
|
x_lim, y_lim = image.size
|
|
pixel = image.load()
|
|
|
|
M1 = float(self.bezier_M1.get())
|
|
M2 = float(self.bezier_M2.get())
|
|
w = float(self.bezier_weight.get())
|
|
|
|
if w > 0:
|
|
x,y = self.generate_bezier(M1,M2,w)
|
|
|
|
interp = interpolate(x, y) # Set up interpolate class
|
|
val_map=[]
|
|
# Map Bezier Curve to values between 0 and 255
|
|
for val in range(0,256):
|
|
val_out = int(round(interp[val])) # Get the interpolated value at each value
|
|
val_map.append(val_out)
|
|
# Adjust image
|
|
timestamp=0
|
|
for y in range(1, y_lim):
|
|
stamp=int(3*time()) #update every 1/3 of a second
|
|
if (stamp != timestamp):
|
|
timestamp=stamp #interlock
|
|
self.statusMessage.set("Adjusting Image Darkness: %.1f %%" %( (100.0*y)/y_lim ) )
|
|
self.master.update()
|
|
for x in range(1, x_lim):
|
|
pixel[x, y] = val_map[ pixel[x, y] ]
|
|
|
|
self.statusMessage.set("Creating Halftone Image." )
|
|
self.master.update()
|
|
image = image.convert('1')
|
|
return image
|
|
|
|
#######################################################################
|
|
|
|
def gcode_error_message(self,message):
|
|
error_report = Toplevel(width=525,height=60)
|
|
error_report.title("G-Code Reading Errors/Warnings")
|
|
error_report.iconname("G-Code Errors")
|
|
error_report.grab_set()
|
|
return_value = StringVar()
|
|
return_value.set("none")
|
|
|
|
|
|
def Close_Click(event):
|
|
return_value.set("close")
|
|
error_report.destroy()
|
|
|
|
#Text Box
|
|
Error_Frame = Frame(error_report)
|
|
scrollbar = Scrollbar(Error_Frame, orient=VERTICAL)
|
|
Error_Text = Text(Error_Frame, width="80", height="20",yscrollcommand=scrollbar.set,bg='white')
|
|
for line in message:
|
|
Error_Text.insert(END,line+"\n")
|
|
scrollbar.config(command=Error_Text.yview)
|
|
scrollbar.pack(side=RIGHT,fill=Y)
|
|
#End Text Box
|
|
|
|
Button_Frame = Frame(error_report)
|
|
close_button = Button(Button_Frame,text=" Close ")
|
|
close_button.bind("<ButtonRelease-1>", Close_Click)
|
|
close_button.pack(side=RIGHT,fill=X)
|
|
|
|
Error_Text.pack(side=LEFT,fill=BOTH,expand=1)
|
|
Button_Frame.pack(side=BOTTOM)
|
|
Error_Frame.pack(side=LEFT,fill=BOTH,expand=1)
|
|
|
|
root.wait_window(error_report)
|
|
return return_value.get()
|
|
|
|
def Open_G_Code(self,filename):
|
|
self.resetPath()
|
|
|
|
g_rip = G_Code_Rip()
|
|
try:
|
|
MSG = g_rip.Read_G_Code(filename, XYarc2line = True, arc_angle=2, units="in", Accuracy="")
|
|
Error_Text = ""
|
|
if MSG!=[]:
|
|
self.gcode_error_message(MSG)
|
|
|
|
#except StandardError as e:
|
|
except Exception as e:
|
|
msg1 = "G-Code Load Failed: "
|
|
msg2 = "Filename: %s" %(filename)
|
|
msg3 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg3).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, "%s\n%s" %(msg2,msg3))
|
|
debug_message(traceback.format_exc())
|
|
|
|
|
|
ecoords= g_rip.generate_laser_paths(g_rip.g_code_data)
|
|
self.GcodeData.set_ecoords(ecoords,data_sorted=True)
|
|
self.Design_bounds = self.GcodeData.bounds
|
|
|
|
|
|
def Open_DXF(self,filemname):
|
|
self.resetPath()
|
|
|
|
self.DXF_FILE = filemname
|
|
dxf_import=DXF_CLASS()
|
|
tolerance = .0005
|
|
try:
|
|
fd = open(self.DXF_FILE)
|
|
dxf_import.GET_DXF_DATA(fd,lin_tol = tolerance,get_units=True,units=None)
|
|
fd.seek(0)
|
|
|
|
dxf_units = dxf_import.units
|
|
if dxf_units=="Unitless":
|
|
d = UnitsDialog(root)
|
|
dxf_units = d.result
|
|
if dxf_units=="Inches":
|
|
dxf_scale = 1.0
|
|
elif dxf_units=="Feet":
|
|
dxf_scale = 12.0
|
|
elif dxf_units=="Miles":
|
|
dxf_scale = 5280.0*12.0
|
|
elif dxf_units=="Millimeters":
|
|
dxf_scale = 1.0/25.4
|
|
elif dxf_units=="Centimeters":
|
|
dxf_scale = 1.0/2.54
|
|
elif dxf_units=="Meters":
|
|
dxf_scale = 1.0/254.0
|
|
elif dxf_units=="Kilometers":
|
|
dxf_scale = 1.0/254000.0
|
|
elif dxf_units=="Microinches":
|
|
dxf_scale = 1.0/1000000.0
|
|
elif dxf_units=="Mils":
|
|
dxf_scale = 1.0/1000.0
|
|
else:
|
|
return
|
|
|
|
lin_tol = tolerance / dxf_scale
|
|
dxf_import.GET_DXF_DATA(fd,lin_tol=lin_tol,get_units=False,units=None)
|
|
fd.close()
|
|
#except StandardError as e:
|
|
except Exception as e:
|
|
msg1 = "DXF Load Failed:"
|
|
msg2 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
except:
|
|
fmessage("Unable To open Drawing Exchange File (DXF) file.")
|
|
debug_message(traceback.format_exc())
|
|
return
|
|
|
|
new_origin=False
|
|
dxf_engrave_coords = dxf_import.DXF_COORDS_GET_TYPE(engrave=True, new_origin=False)
|
|
dxf_cut_coords = dxf_import.DXF_COORDS_GET_TYPE(engrave=False,new_origin=False)
|
|
## if DEBUG:
|
|
## dxf_code = dxf_import.WriteDXF(close_loops=False)
|
|
## fout = open('Z:\\out.dxf','w')
|
|
## for line in dxf_code:
|
|
## fout.write(line+'\n')
|
|
## fout.close
|
|
|
|
if dxf_import.dxf_messages != "":
|
|
msg_split=dxf_import.dxf_messages.split("\n")
|
|
msg_split.sort()
|
|
msg_split.append("")
|
|
mcnt=1
|
|
msg_out = ""
|
|
for i in range(1,len(msg_split)):
|
|
if msg_split[i-1]==msg_split[i]:
|
|
mcnt=mcnt+1
|
|
else:
|
|
if msg_split[i-1]!="":
|
|
msg_line = "%s (%d places)\n" %(msg_split[i-1],mcnt)
|
|
msg_out = msg_out + msg_line
|
|
mcnt=1
|
|
message_box("DXF Import:",msg_out)
|
|
|
|
##########################
|
|
### Create ECOORDS ###
|
|
##########################
|
|
self.VcutData.make_ecoords(dxf_cut_coords ,scale=dxf_scale)
|
|
self.VengData.make_ecoords(dxf_engrave_coords,scale=dxf_scale)
|
|
|
|
xmin = min(self.VcutData.bounds[0],self.VengData.bounds[0])
|
|
xmax = max(self.VcutData.bounds[1],self.VengData.bounds[1])
|
|
ymin = min(self.VcutData.bounds[2],self.VengData.bounds[2])
|
|
ymax = max(self.VcutData.bounds[3],self.VengData.bounds[3])
|
|
self.Design_bounds = (xmin,xmax,ymin,ymax)
|
|
|
|
|
|
def Open_Settings_File(self,filename):
|
|
try:
|
|
fin = open(filename,'r')
|
|
except:
|
|
fmessage("Unable to open file: %s" %(filename))
|
|
return
|
|
|
|
text_codes=[]
|
|
ident = "k40_whisperer_set"
|
|
for line in fin:
|
|
try:
|
|
if ident in line:
|
|
# BOOL
|
|
if "include_Reng" in line:
|
|
self.include_Reng.set(line[line.find("include_Reng"):].split()[1])
|
|
elif "include_Veng" in line:
|
|
self.include_Veng.set(line[line.find("include_Veng"):].split()[1])
|
|
elif "include_Vcut" in line:
|
|
self.include_Vcut.set(line[line.find("include_Vcut"):].split()[1])
|
|
elif "include_Gcde" in line:
|
|
self.include_Gcde.set(line[line.find("include_Gcde"):].split()[1])
|
|
elif "include_Time" in line:
|
|
self.include_Time.set(line[line.find("include_Time"):].split()[1])
|
|
elif "halftone" in line:
|
|
self.halftone.set(line[line.find("halftone"):].split()[1])
|
|
elif "negate" in line:
|
|
self.negate.set(line[line.find("negate"):].split()[1])
|
|
elif "HomeUR" in line:
|
|
self.HomeUR.set(line[line.find("HomeUR"):].split()[1])
|
|
elif "inputCSYS" in line:
|
|
self.inputCSYS.set(line[line.find("inputCSYS"):].split()[1])
|
|
elif "advanced" in line:
|
|
self.advanced.set(line[line.find("advanced"):].split()[1])
|
|
elif "mirror" in line:
|
|
self.mirror.set(line[line.find("mirror"):].split()[1])
|
|
elif "rotate" in line:
|
|
self.rotate.set(line[line.find("rotate"):].split()[1])
|
|
elif "engraveUP" in line:
|
|
self.engraveUP.set(line[line.find("engraveUP"):].split()[1])
|
|
elif "init_home" in line:
|
|
self.init_home.set(line[line.find("init_home"):].split()[1])
|
|
elif "post_home" in line:
|
|
self.post_home.set(line[line.find("post_home"):].split()[1])
|
|
elif "post_beep" in line:
|
|
self.post_beep.set(line[line.find("post_beep"):].split()[1])
|
|
elif "post_disp" in line:
|
|
self.post_disp.set(line[line.find("post_disp"):].split()[1])
|
|
elif "post_exec" in line:
|
|
self.post_exec.set(line[line.find("post_exec"):].split()[1])
|
|
|
|
elif "pre_pr_crc" in line:
|
|
self.pre_pr_crc.set(line[line.find("pre_pr_crc"):].split()[1])
|
|
elif "inside_first" in line:
|
|
self.inside_first.set(line[line.find("inside_first"):].split()[1])
|
|
elif "comb_engrave" in line:
|
|
self.comb_engrave.set(line[line.find("comb_engrave"):].split()[1])
|
|
elif "comb_vector" in line:
|
|
self.comb_vector.set(line[line.find("comb_vector"):].split()[1])
|
|
elif "zoom2image" in line:
|
|
self.zoom2image.set(line[line.find("zoom2image"):].split()[1])
|
|
|
|
elif "rotary" in line:
|
|
self.rotary.set(line[line.find("rotary"):].split()[1])
|
|
elif "reduced_mem" in line:
|
|
self.reduced_mem.set(line[line.find("reduced_mem"):].split()[1])
|
|
elif "wait" in line:
|
|
self.wait.set(line[line.find("wait"):].split()[1])
|
|
|
|
elif "trace_w_laser" in line:
|
|
self.trace_w_laser.set(line[line.find("trace_w_laser"):].split()[1])
|
|
|
|
# STRING.set()
|
|
elif "board_name" in line:
|
|
self.board_name.set(line[line.find("board_name"):].split()[1])
|
|
elif "units" in line:
|
|
self.units.set(line[line.find("units"):].split()[1])
|
|
elif "Reng_feed" in line:
|
|
self.Reng_feed .set(line[line.find("Reng_feed"):].split()[1])
|
|
elif "Veng_feed" in line:
|
|
self.Veng_feed .set(line[line.find("Veng_feed"):].split()[1])
|
|
elif "Vcut_feed" in line:
|
|
self.Vcut_feed.set(line[line.find("Vcut_feed"):].split()[1])
|
|
elif "jog_step" in line:
|
|
self.jog_step.set(line[line.find("jog_step"):].split()[1])
|
|
|
|
elif "Reng_passes" in line:
|
|
self.Reng_passes.set(line[line.find("Reng_passes"):].split()[1])
|
|
elif "Veng_passes" in line:
|
|
self.Veng_passes.set(line[line.find("Veng_passes"):].split()[1])
|
|
elif "Vcut_passes" in line:
|
|
self.Vcut_passes.set(line[line.find("Vcut_passes"):].split()[1])
|
|
elif "Gcde_passes" in line:
|
|
self.Gcde_passes.set(line[line.find("Gcde_passes"):].split()[1])
|
|
|
|
elif "rast_step" in line:
|
|
self.rast_step.set(line[line.find("rast_step"):].split()[1])
|
|
elif "ht_size" in line:
|
|
self.ht_size.set(line[line.find("ht_size"):].split()[1])
|
|
|
|
elif "LaserXsize" in line:
|
|
self.LaserXsize.set(line[line.find("LaserXsize"):].split()[1])
|
|
elif "LaserYsize" in line:
|
|
self.LaserYsize.set(line[line.find("LaserYsize"):].split()[1])
|
|
|
|
elif "LaserXscale" in line:
|
|
self.LaserXscale.set(line[line.find("LaserXscale"):].split()[1])
|
|
elif "LaserYscale" in line:
|
|
self.LaserYscale.set(line[line.find("LaserYscale"):].split()[1])
|
|
elif "LaserRscale" in line:
|
|
self.LaserRscale.set(line[line.find("LaserRscale"):].split()[1])
|
|
|
|
elif "rapid_feed" in line:
|
|
self.rapid_feed.set(line[line.find("rapid_feed"):].split()[1])
|
|
|
|
elif "gotoX" in line:
|
|
self.gotoX.set(line[line.find("gotoX"):].split()[1])
|
|
elif "gotoY" in line:
|
|
self.gotoY.set(line[line.find("gotoY"):].split()[1])
|
|
|
|
elif "bezier_M1" in line:
|
|
self.bezier_M1.set(line[line.find("bezier_M1"):].split()[1])
|
|
elif "bezier_M2" in line:
|
|
self.bezier_M2.set(line[line.find("bezier_M2"):].split()[1])
|
|
elif "bezier_weight" in line:
|
|
self.bezier_weight.set(line[line.find("bezier_weight"):].split()[1])
|
|
elif "trace_gap" in line:
|
|
self.trace_gap.set(line[line.find("trace_gap"):].split()[1])
|
|
elif "trace_speed" in line:
|
|
self.trace_speed.set(line[line.find("trace_speed"):].split()[1])
|
|
|
|
## elif "unsharp_flag" in line:
|
|
## self.unsharp_flag.set(line[line.find("unsharp_flag"):].split()[1])
|
|
## elif "unsharp_r" in line:
|
|
## self.unsharp_r.set(line[line.find("unsharp_r"):].split()[1])
|
|
## elif "unsharp_p" in line:
|
|
## self.unsharp_p.set(line[line.find("unsharp_p"):].split()[1])
|
|
## elif "unsharp_t" in line:
|
|
## self.unsharp_t.set(line[line.find("unsharp_t"):].split()[1])
|
|
|
|
elif "t_timeout" in line:
|
|
self.t_timeout.set(line[line.find("t_timeout"):].split()[1])
|
|
elif "n_timeouts" in line:
|
|
self.n_timeouts.set(line[line.find("n_timeouts"):].split()[1])
|
|
|
|
elif "ink_timeout" in line:
|
|
self.ink_timeout.set(line[line.find("ink_timeout"):].split()[1])
|
|
|
|
elif "designfile" in line:
|
|
self.DESIGN_FILE=(line[line.find("designfile"):].split("\042")[1])
|
|
elif "inkscape_path" in line:
|
|
self.inkscape_path.set(line[line.find("inkscape_path"):].split("\042")[1])
|
|
elif "batch_path" in line:
|
|
self.batch_path.set(line[line.find("batch_path"):].split("\042")[1])
|
|
elif "fast_plot" in line:
|
|
self.fastPlot.set(line[line.find("fast_plot"):].split()[1])
|
|
|
|
except:
|
|
#Ignoring exeptions during reading data from line
|
|
pass
|
|
|
|
fin.close()
|
|
|
|
fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
|
|
init_file=os.path.basename(fileName)
|
|
|
|
if init_file != "None":
|
|
if ( os.path.isfile(self.DESIGN_FILE) ):
|
|
pass
|
|
else:
|
|
self.statusMessage.set("Image file not found: %s " %(self.DESIGN_FILE))
|
|
|
|
if self.units.get() == 'in':
|
|
self.funits.set('in/min')
|
|
self.units_scale = 1.0
|
|
else:
|
|
self.units.set('mm')
|
|
self.funits.set('mm/s')
|
|
self.units_scale = 25.4
|
|
|
|
temp_name, fileExtension = os.path.splitext(filename)
|
|
file_base=os.path.basename(temp_name)
|
|
|
|
if self.initComplete == 1:
|
|
self.menu_Mode_Change()
|
|
self.DESIGN_FILE = filename
|
|
|
|
##########################################################################
|
|
##########################################################################
|
|
def menu_File_Save(self):
|
|
settings_data = self.WriteConfig()
|
|
init_dir = os.path.dirname(self.DESIGN_FILE)
|
|
if ( not os.path.isdir(init_dir) ):
|
|
init_dir = self.HOME_DIR
|
|
|
|
fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
|
|
init_file=os.path.basename(fileName)
|
|
|
|
filename = asksaveasfilename(defaultextension='.txt', \
|
|
filetypes=[("Text File","*.txt")],\
|
|
initialdir=init_dir,\
|
|
initialfile= init_file )
|
|
|
|
if filename != '' and filename != ():
|
|
try:
|
|
fout = open(filename,'w')
|
|
except:
|
|
self.statusMessage.set("Unable to open file for writing: %s" %(filename))
|
|
self.statusbar.configure( bg = 'red' )
|
|
return
|
|
|
|
for line in settings_data:
|
|
try:
|
|
fout.write(line+'\n')
|
|
except:
|
|
fout.write('(skipping line)\n')
|
|
debug_message(traceback.format_exc())
|
|
fout.close
|
|
self.statusMessage.set("File Saved: %s" %(filename))
|
|
self.statusbar.configure( bg = 'white' )
|
|
|
|
def Get_Design_Bounds(self):
|
|
if self.rotate.get():
|
|
ymin = self.Design_bounds[0]
|
|
ymax = self.Design_bounds[1]
|
|
xmin = -self.Design_bounds[3]
|
|
xmax = -self.Design_bounds[2]
|
|
else:
|
|
xmin,xmax,ymin,ymax = self.Design_bounds
|
|
return (xmin,xmax,ymin,ymax)
|
|
|
|
def Move_UL(self,dummy=None):
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
if self.HomeUR.get():
|
|
Xnew = self.laserX + (xmax-xmin)
|
|
DX = round((xmax-xmin)*1000.0)
|
|
else:
|
|
Xnew = self.laserX
|
|
DX = 0
|
|
|
|
(Xsize,Ysize)=self.LASER_Size()
|
|
if Xnew <= Xsize+.001:
|
|
self.move_head_window_temporary([DX,0.0])
|
|
else:
|
|
pass
|
|
|
|
def Move_UR(self,dummy=None):
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
if self.HomeUR.get():
|
|
Xnew = self.laserX
|
|
DX = 0
|
|
else:
|
|
Xnew = self.laserX + (xmax-xmin)
|
|
DX = round((xmax-xmin)*1000.0)
|
|
|
|
(Xsize,Ysize)=self.LASER_Size()
|
|
if Xnew <= Xsize+.001:
|
|
self.move_head_window_temporary([DX,0.0])
|
|
else:
|
|
pass
|
|
|
|
def Move_LR(self,dummy=None):
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
if self.HomeUR.get():
|
|
Xnew = self.laserX
|
|
DX = 0
|
|
else:
|
|
Xnew = self.laserX + (xmax-xmin)
|
|
DX = round((xmax-xmin)*1000.0)
|
|
|
|
Ynew = self.laserY - (ymax-ymin)
|
|
(Xsize,Ysize)=self.LASER_Size()
|
|
if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
|
|
DY = round((ymax-ymin)*1000.0)
|
|
self.move_head_window_temporary([DX,-DY])
|
|
else:
|
|
pass
|
|
|
|
def Move_LL(self,dummy=None):
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
if self.HomeUR.get():
|
|
Xnew = self.laserX + (xmax-xmin)
|
|
DX = round((xmax-xmin)*1000.0)
|
|
else:
|
|
Xnew = self.laserX
|
|
DX = 0
|
|
|
|
Ynew = self.laserY - (ymax-ymin)
|
|
(Xsize,Ysize)=self.LASER_Size()
|
|
if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
|
|
DY = round((ymax-ymin)*1000.0)
|
|
self.move_head_window_temporary([DX,-DY])
|
|
else:
|
|
pass
|
|
|
|
def Move_Frame(self,dummy=None):
|
|
self.Move_UL()
|
|
self.Move_UR()
|
|
self.Move_LR()
|
|
self.Move_LL()
|
|
self.Move_UL()
|
|
|
|
def Move_CC(self,dummy=None):
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
if self.HomeUR.get():
|
|
Xnew = self.laserX + (xmax-xmin)/2.0
|
|
DX = round((xmax-xmin)/2.0*1000.0)
|
|
else:
|
|
Xnew = self.laserX + (xmax-xmin)/2.0
|
|
DX = round((xmax-xmin)/2.0*1000.0)
|
|
|
|
|
|
Ynew = self.laserY - (ymax-ymin)/2.0
|
|
(Xsize,Ysize)=self.LASER_Size()
|
|
if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
|
|
DY = round((ymax-ymin)/2.0*1000.0)
|
|
self.move_head_window_temporary([DX,-DY])
|
|
else:
|
|
pass
|
|
|
|
def Move_Arbitrary(self,MoveX,MoveY,dummy=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
if self.HomeUR.get():
|
|
DX = -MoveX
|
|
else:
|
|
DX = MoveX
|
|
DY = MoveY
|
|
NewXpos = self.pos_offset[0]+DX
|
|
NewYpos = self.pos_offset[1]+DY
|
|
self.move_head_window_temporary([NewXpos,NewYpos])
|
|
|
|
def Move_Arb_Step(self,dx,dy):
|
|
if self.GUI_Disabled:
|
|
return
|
|
if self.units.get()=="in":
|
|
dx_inches = round(dx*1000)
|
|
dy_inches = round(dy*1000)
|
|
else:
|
|
dx_inches = round(dx/25.4*1000)
|
|
dy_inches = round(dy/25.4*1000)
|
|
self.Move_Arbitrary( dx_inches,dy_inches )
|
|
|
|
def Move_Arb_Right(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Move_Arb_Step( JOG_STEP,0 )
|
|
|
|
def Move_Arb_Left(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Move_Arb_Step( -JOG_STEP,0 )
|
|
|
|
def Move_Arb_Up(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Move_Arb_Step( 0,JOG_STEP )
|
|
|
|
def Move_Arb_Down(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Move_Arb_Step( 0,-JOG_STEP )
|
|
|
|
####################################################
|
|
|
|
def Move_Right(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Rapid_Move( JOG_STEP,0 )
|
|
|
|
def Move_Right_10(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 10.0
|
|
self.Rapid_Move( JOG_STEP,0 )
|
|
|
|
def Move_Right_100(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 20.0
|
|
self.Rapid_Move( JOG_STEP,0 )
|
|
|
|
def Move_Left(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Rapid_Move( -JOG_STEP,0 )
|
|
|
|
def Move_Left_10(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 10.0
|
|
self.Rapid_Move( -JOG_STEP,0 )
|
|
|
|
def Move_Left_100(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 20.0
|
|
self.Rapid_Move( -JOG_STEP,0 )
|
|
|
|
def Move_Up(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Rapid_Move( 0,JOG_STEP )
|
|
|
|
def Move_Up_10(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 10.0
|
|
self.Rapid_Move( 0,JOG_STEP )
|
|
|
|
def Move_Up_100(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 20.0
|
|
self.Rapid_Move( 0,JOG_STEP )
|
|
|
|
def Move_Down(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() )
|
|
self.Rapid_Move( 0,-JOG_STEP )
|
|
|
|
def Move_Down_10(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 10.0
|
|
self.Rapid_Move( 0,-JOG_STEP )
|
|
|
|
def Move_Down_100(self,dummy=None):
|
|
JOG_STEP = float( self.jog_step.get() ) * 20.0
|
|
self.Rapid_Move( 0,-JOG_STEP )
|
|
|
|
def Rapid_Move(self,dx,dy):
|
|
if self.GUI_Disabled:
|
|
return
|
|
if self.units.get()=="in":
|
|
dx_inches = round(dx,3)
|
|
dy_inches = round(dy,3)
|
|
else:
|
|
dx_inches = round(dx/25.4,3)
|
|
dy_inches = round(dy/25.4,3)
|
|
|
|
if (self.HomeUR.get()):
|
|
dx_inches = -dx_inches
|
|
|
|
Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches)
|
|
dxmils = (Xnew - self.laserX)*1000.0
|
|
dymils = (Ynew - self.laserY)*1000.0
|
|
|
|
if self.k40 == None:
|
|
self.laserX = Xnew
|
|
self.laserY = Ynew
|
|
self.menu_View_Refresh()
|
|
elif self.Send_Rapid_Move(dxmils,dymils):
|
|
self.laserX = Xnew
|
|
self.laserY = Ynew
|
|
self.menu_View_Refresh()
|
|
|
|
|
|
def Send_Rapid_Move(self,dxmils,dymils):
|
|
try:
|
|
if self.k40 != None:
|
|
Xscale = float(self.LaserXscale.get())
|
|
Yscale = float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
|
|
if Xscale != 1.0 or Yscale != 1.0:
|
|
dxmils = int(round(dxmils *Xscale))
|
|
dymils = int(round(dymils *Yscale))
|
|
self.k40.n_timeouts = 10
|
|
|
|
if self.rotary.get() and float(self.rapid_feed.get()):
|
|
self.slow_jog(int(dxmils),int(dymils))
|
|
else:
|
|
self.k40.rapid_move(int(dxmils),int(dymils))
|
|
|
|
|
|
return True
|
|
else:
|
|
return True
|
|
#except StandardError as e:
|
|
except Exception as e:
|
|
msg1 = "Rapid Move Failed: "
|
|
msg2 = "%s" %(e)
|
|
if msg2 == "":
|
|
formatted_lines = traceback.format_exc().splitlines()
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
debug_message(traceback.format_exc())
|
|
return False
|
|
|
|
|
|
def slow_jog(self,dxmils,dymils):
|
|
if int(dxmils)==0 and int(dymils)==0:
|
|
return
|
|
self.stop[0]=False
|
|
Rapid_data=[]
|
|
Rapid_inst = egv(target=lambda s:Rapid_data.append(s))
|
|
Rapid_feed = float(self.rapid_feed.get())*self.feed_factor()
|
|
Rapid_inst.make_egv_rapid(dxmils,dymils,Feed=Rapid_feed,board_name=self.board_name.get())
|
|
self.send_egv_data(Rapid_data, 1, None)
|
|
self.stop[0]=True
|
|
|
|
def update_gui(self, message=None, bgcolor='white'):
|
|
if message!=None:
|
|
self.statusMessage.set(message)
|
|
self.statusbar.configure( bg = bgcolor )
|
|
self.master.update()
|
|
return True
|
|
|
|
def set_gui(self,new_state="normal"):
|
|
if new_state=="normal":
|
|
self.GUI_Disabled=False
|
|
else:
|
|
self.GUI_Disabled=True
|
|
|
|
try:
|
|
self.menuBar.entryconfigure("File" , state=new_state)
|
|
self.menuBar.entryconfigure("View" , state=new_state)
|
|
self.menuBar.entryconfigure("Tools" , state=new_state)
|
|
self.menuBar.entryconfigure("Settings", state=new_state)
|
|
self.menuBar.entryconfigure("Help" , state=new_state)
|
|
self.PreviewCanvas.configure(state=new_state)
|
|
|
|
for w in self.master.winfo_children():
|
|
try:
|
|
w.configure(state=new_state)
|
|
except:
|
|
pass
|
|
self.Stop_Button.configure(state="normal")
|
|
self.Fullscreen_Button.configure(state="normal")
|
|
self.statusbar.configure(state="normal")
|
|
self.master.update()
|
|
except:
|
|
if DEBUG:
|
|
debug_message(traceback.format_exc())
|
|
|
|
def Vector_Cut(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Vector Cut: Processing Vector Data.")
|
|
if self.VcutData.ecoords!=[]:
|
|
self.send_data("Vector_Cut", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No vector data to cut")
|
|
self.Finish_Job()
|
|
|
|
def Vector_Cut_Plus(self, dummy=None):
|
|
self.Vcut_feed.set(float(self.Vcut_feed.get()) + 1)
|
|
|
|
def Vector_Cut_Minus(self, dummy=None):
|
|
self.Vcut_feed.set(float(self.Vcut_feed.get()) - 1)
|
|
|
|
def Reng_Passes_Plus(self, dummy=None):
|
|
self.Reng_passes.set(int(self.Reng_passes.get()) + 1)
|
|
|
|
def Reng_Passes_Minus(self, dummy=None):
|
|
self.Reng_passes.set(int(self.Reng_passes.get()) - 1)
|
|
|
|
def Veng_Passes_Plus(self, dummy=None):
|
|
self.Veng_passes.set(int(self.Veng_passes.get()) + 1)
|
|
|
|
def Veng_Passes_Minus(self, dummy=None):
|
|
self.Veng_passes.set(int(self.Veng_passes.get()) - 1)
|
|
|
|
def Vcut_Passes_Plus(self, dummy=None):
|
|
self.Vcut_passes.set(int(self.Vcut_passes.get()) + 1)
|
|
|
|
def Vcut_Passes_Minus(self, dummy=None):
|
|
self.Vcut_passes.set(int(self.Vcut_passes.get()) - 1)
|
|
|
|
|
|
def Vector_Eng(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Vector Engrave: Processing Vector Data.")
|
|
if self.VengData.ecoords!=[]:
|
|
self.send_data("Vector_Eng", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No vector data to engrave")
|
|
self.Finish_Job()
|
|
|
|
def Vector_Eng_Plus(self, dummy=None):
|
|
self.Veng_feed.set(float(self.Veng_feed.get()) + 1)
|
|
|
|
def Vector_Eng_Minus(self, dummy=None):
|
|
self.Veng_feed.set(float(self.Veng_feed.get()) - 1)
|
|
|
|
def Trace_Eng(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Boundary Trace: Processing Data.")
|
|
self.trace_coords = self.make_trace_path()
|
|
|
|
if self.trace_coords!=[]:
|
|
self.send_data("Trace_Eng", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No trace data to follow")
|
|
self.Finish_Job()
|
|
|
|
def Raster_Eng(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Raster Engraving: Processing Image Data.")
|
|
try:
|
|
self.make_raster_coords()
|
|
if self.RengData.ecoords!=[]:
|
|
self.send_data("Raster_Eng", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No raster data to engrave")
|
|
|
|
except MemoryError as e:
|
|
msg1 = "Memory Error:"
|
|
msg2 = "Memory Error: Out of Memory."
|
|
self.statusMessage.set(msg2)
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
|
|
except Exception as e:
|
|
msg1 = "Making Raster Data Stopped: "
|
|
msg2 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
self.Finish_Job()
|
|
|
|
def Raster_Eng_Plus(self, dummy=None):
|
|
self.Reng_feed.set(float(self.Reng_feed.get()) + 10)
|
|
|
|
def Raster_Eng_Minus(self, dummy=None):
|
|
self.Reng_feed.set(float(self.Reng_feed.get()) - 10)
|
|
|
|
def Raster_Vector_Eng(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Raster Engraving: Processing Image and Vector Data.")
|
|
try:
|
|
self.make_raster_coords()
|
|
if self.RengData.ecoords!=[] or self.VengData.ecoords!=[]:
|
|
self.send_data("Raster_Eng+Vector_Eng", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No data to engrave")
|
|
except Exception as e:
|
|
msg1 = "Preparing Data Stopped: "
|
|
msg2 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
self.Finish_Job()
|
|
|
|
def Vector_Eng_Cut(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Vector Cut: Processing Vector Data.")
|
|
if self.VcutData.ecoords!=[] or self.VengData.ecoords!=[]:
|
|
self.send_data("Vector_Eng+Vector_Cut", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No vector data.")
|
|
self.Finish_Job()
|
|
|
|
def Raster_Vector_Cut(self, output_filename=None):
|
|
self.Prepare_for_laser_run("Raster Engraving: Processing Image and Vector Data.")
|
|
try:
|
|
self.make_raster_coords()
|
|
if self.RengData.ecoords!=[] or self.VengData.ecoords!=[] or self.VcutData.ecoords!=[]:
|
|
self.send_data("Raster_Eng+Vector_Eng+Vector_Cut", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No data to engrave/cut")
|
|
except Exception as e:
|
|
msg1 = "Preparing Data Stopped: "
|
|
msg2 = "%s" %(e)
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
self.Finish_Job()
|
|
|
|
def Gcode_Cut(self, output_filename=None):
|
|
self.Prepare_for_laser_run("G Code Cutting.")
|
|
if self.GcodeData.ecoords!=[]:
|
|
self.send_data("Gcode_Cut", output_filename)
|
|
else:
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
self.statusMessage.set("No g-code data to cut")
|
|
self.Finish_Job()
|
|
|
|
def Remember_head_position(self):
|
|
self.Restore_Button.configure(state="normal")
|
|
if self.units.get()=="in":
|
|
self.lastX.set(self.laserX + self.pos_offset[0]/1000.0)
|
|
self.lastY.set(self.laserY + self.pos_offset[1]/1000.0)
|
|
else:
|
|
self.lastX.set((self.laserX + self.pos_offset[0]/1000.0)*self.units_scale)
|
|
self.lastY.set((self.laserY + self.pos_offset[1]/1000.0)*self.units_scale)
|
|
|
|
def Restore_head_position(self):
|
|
xpos = float(self.lastX.get())
|
|
ypos = float(self.lastY.get())
|
|
if self.k40 != None:
|
|
self.k40.home_position()
|
|
self.laserX = 0.0
|
|
self.laserY = 0.0
|
|
self.Rapid_Move(xpos,ypos)
|
|
self.menu_View_Refresh()
|
|
|
|
def Prepare_for_laser_run(self,msg):
|
|
self.stop[0]=False
|
|
self.move_head_window_temporary([0,0])
|
|
self.Remember_head_position()
|
|
self.set_gui("disabled")
|
|
self.statusbar.configure( bg = 'green' )
|
|
self.statusMessage.set(msg)
|
|
self.master.update()
|
|
|
|
def Finish_Job(self, event=None):
|
|
self.set_gui("normal")
|
|
self.stop[0]=True
|
|
if self.post_home.get():
|
|
self.Unlock()
|
|
|
|
if self.post_beep.get():
|
|
self.master.bell()
|
|
|
|
stderr = ''
|
|
stdout = ''
|
|
if self.post_exec.get():
|
|
cmd = [self.batch_path.get()]
|
|
from subprocess import Popen, PIPE
|
|
startupinfo=None
|
|
proc = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE, startupinfo=startupinfo)
|
|
stdout,stderr = proc.communicate()
|
|
|
|
if self.post_disp.get() or stderr != '':
|
|
msg1 = ''
|
|
minutes = floor(self.run_time / 60)
|
|
seconds = self.run_time - minutes*60
|
|
msg2 = "Job Ended.\nRun Time = %02d:%02d" %(minutes,seconds)
|
|
if stdout != '':
|
|
msg2=msg2+'\n\nBatch File Output:\n'+stdout
|
|
if stderr != '':
|
|
msg2=msg2+'\n\nBatch File Errors:\n'+stderr
|
|
self.run_time = 0
|
|
message_box(msg1, msg2)
|
|
|
|
|
|
def make_trace_path(self):
|
|
my_hull = hull2D()
|
|
if self.inputCSYS.get() and self.RengData.image == None:
|
|
xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
|
|
else:
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
|
|
startx = xmin
|
|
starty = ymax
|
|
|
|
#######################################
|
|
Vcut_coords = self.VcutData.ecoords
|
|
Veng_coords = self.VengData.ecoords
|
|
Gcode_coords= self.GcodeData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords)
|
|
Veng_coords = self.mirror_rotate_vector_coords(Veng_coords)
|
|
Gcode_coords= self.mirror_rotate_vector_coords(Gcode_coords)
|
|
|
|
#######################################
|
|
if self.RengData.ecoords==[]:
|
|
if self.stop[0] == True:
|
|
self.stop[0]=False
|
|
self.make_raster_coords()
|
|
self.stop[0]=True
|
|
else:
|
|
self.make_raster_coords()
|
|
|
|
RengHullCoords = []
|
|
Xscale = 1/float(self.LaserXscale.get())
|
|
Yscale = 1/float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = 1/float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
|
|
for point in self.RengData.hull_coords:
|
|
RengHullCoords.append([point[0]*Xscale+xmin, point[1]*Yscale, point[2]])
|
|
|
|
all_coords = []
|
|
all_coords.extend(Vcut_coords)
|
|
all_coords.extend(Veng_coords)
|
|
all_coords.extend(Gcode_coords)
|
|
all_coords.extend(RengHullCoords)
|
|
|
|
trace_coords=[]
|
|
if all_coords != []:
|
|
trace_coords = my_hull.convexHullecoords(all_coords)
|
|
gap = float(self.trace_gap.get())/self.units_scale
|
|
trace_coords = self.offset_eccords(trace_coords,gap)
|
|
|
|
trace_coords,startx,starty = self.scale_vector_coords(trace_coords,startx,starty)
|
|
return trace_coords
|
|
|
|
|
|
################################################################################
|
|
def Sort_Paths(self,ecoords,i_loop=2):
|
|
##########################
|
|
### find loop ends ###
|
|
##########################
|
|
Lbeg=[]
|
|
Lend=[]
|
|
if len(ecoords)>0:
|
|
Lbeg.append(0)
|
|
loop_old=ecoords[0][i_loop]
|
|
for i in range(1,len(ecoords)):
|
|
loop = ecoords[i][i_loop]
|
|
if loop != loop_old:
|
|
Lbeg.append(i)
|
|
Lend.append(i-1)
|
|
loop_old=loop
|
|
Lend.append(i)
|
|
|
|
#######################################################
|
|
# Find new order based on distance to next beg or end #
|
|
#######################################################
|
|
order_out = []
|
|
use_beg=0
|
|
if len(ecoords)>0:
|
|
order_out.append([Lbeg[0],Lend[0]])
|
|
inext = 0
|
|
total=len(Lbeg)
|
|
for i in range(total-1):
|
|
if use_beg==1:
|
|
ii=Lbeg.pop(inext)
|
|
Lend.pop(inext)
|
|
else:
|
|
ii=Lend.pop(inext)
|
|
Lbeg.pop(inext)
|
|
|
|
Xcur = ecoords[ii][0]
|
|
Ycur = ecoords[ii][1]
|
|
|
|
dx = Xcur - ecoords[ Lbeg[0] ][0]
|
|
dy = Ycur - ecoords[ Lbeg[0] ][1]
|
|
min_dist = dx*dx + dy*dy
|
|
|
|
dxe = Xcur - ecoords[ Lend[0] ][0]
|
|
dye = Ycur - ecoords[ Lend[0] ][1]
|
|
min_diste = dxe*dxe + dye*dye
|
|
|
|
inext=0
|
|
inexte=0
|
|
for j in range(1,len(Lbeg)):
|
|
dx = Xcur - ecoords[ Lbeg[j] ][0]
|
|
dy = Ycur - ecoords[ Lbeg[j] ][1]
|
|
dist = dx*dx + dy*dy
|
|
if dist < min_dist:
|
|
min_dist=dist
|
|
inext=j
|
|
###
|
|
dxe = Xcur - ecoords[ Lend[j] ][0]
|
|
dye = Ycur - ecoords[ Lend[j] ][1]
|
|
diste = dxe*dxe + dye*dye
|
|
if diste < min_diste:
|
|
min_diste=diste
|
|
inexte=j
|
|
###
|
|
if min_diste < min_dist:
|
|
inext=inexte
|
|
order_out.append([Lend[inexte],Lbeg[inexte]])
|
|
use_beg=1
|
|
else:
|
|
order_out.append([Lbeg[inext],Lend[inext]])
|
|
use_beg=0
|
|
###########################################################
|
|
return order_out
|
|
|
|
#####################################################
|
|
# determine if a point is inside a given polygon or not
|
|
# Polygon is a list of (x,y) pairs.
|
|
# http://www.ariel.com.au/a/python-point-int-poly.html
|
|
#####################################################
|
|
def point_inside_polygon(self,x,y,poly):
|
|
n = len(poly)
|
|
inside = -1
|
|
p1x = poly[0][0]
|
|
p1y = poly[0][1]
|
|
for i in range(n+1):
|
|
p2x = poly[i%n][0]
|
|
p2y = poly[i%n][1]
|
|
if y > min(p1y,p2y):
|
|
if y <= max(p1y,p2y):
|
|
if x <= max(p1x,p2x):
|
|
if p1y != p2y:
|
|
xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
|
|
if p1x == p2x or x <= xinters:
|
|
inside = inside * -1
|
|
p1x,p1y = p2x,p2y
|
|
|
|
return inside
|
|
|
|
def optimize_paths(self,ecoords,inside_check=True):
|
|
order_out = self.Sort_Paths(ecoords)
|
|
lastx=-999
|
|
lasty=-999
|
|
Acc=0.004
|
|
cuts=[]
|
|
|
|
for line in order_out:
|
|
temp=line
|
|
if temp[0] > temp[1]:
|
|
step = -1
|
|
else:
|
|
step = 1
|
|
|
|
loop_old = -1
|
|
|
|
for i in range(temp[0],temp[1]+step,step):
|
|
x1 = ecoords[i][0]
|
|
y1 = ecoords[i][1]
|
|
loop = ecoords[i][2]
|
|
# check and see if we need to move to a new discontinuous start point
|
|
if (loop != loop_old):
|
|
dx = x1-lastx
|
|
dy = y1-lasty
|
|
dist = sqrt(dx*dx + dy*dy)
|
|
if dist > Acc:
|
|
cuts.append([[x1,y1]])
|
|
else:
|
|
cuts[-1].append([x1,y1])
|
|
else:
|
|
cuts[-1].append([x1,y1])
|
|
lastx = x1
|
|
lasty = y1
|
|
loop_old = loop
|
|
|
|
if inside_check:
|
|
#####################################################
|
|
# For each loop determine if other loops are inside #
|
|
#####################################################
|
|
Nloops=len(cuts)
|
|
self.LoopTree=[]
|
|
for iloop in range(Nloops):
|
|
self.LoopTree.append([])
|
|
## CUR_PCT=float(iloop)/Nloops*100.0
|
|
## if (not self.batch.get()):
|
|
## self.statusMessage.set('Determining Which Side of Loop to Cut: %d of %d' %(iloop+1,Nloops))
|
|
## self.master.update()
|
|
ipoly = cuts[iloop]
|
|
## Check points in other loops (could just check one) ##
|
|
if ipoly != []:
|
|
for jloop in range(Nloops):
|
|
if jloop != iloop:
|
|
inside = 0
|
|
inside = inside + self.point_inside_polygon(cuts[jloop][0][0],cuts[jloop][0][1],ipoly)
|
|
if inside > 0:
|
|
self.LoopTree[iloop].append(jloop)
|
|
#####################################################
|
|
for i in range(Nloops):
|
|
lns=[]
|
|
lns.append(i)
|
|
self.remove_self_references(lns,self.LoopTree[i])
|
|
|
|
self.order=[]
|
|
self.loops = list(range(Nloops))
|
|
for i in range(Nloops):
|
|
if self.LoopTree[i]!=[]:
|
|
self.addlist(self.LoopTree[i])
|
|
self.LoopTree[i]=[]
|
|
if self.loops[i]!=[]:
|
|
self.order.append(self.loops[i])
|
|
self.loops[i]=[]
|
|
#END inside_check
|
|
ecoords_out = []
|
|
for i in self.order:
|
|
line = cuts[i]
|
|
for coord in line:
|
|
ecoords_out.append([coord[0],coord[1],i])
|
|
#END inside_check
|
|
else:
|
|
ecoords_out = []
|
|
for i in range(len(cuts)):
|
|
line = cuts[i]
|
|
for coord in line:
|
|
ecoords_out.append([coord[0],coord[1],i])
|
|
|
|
return ecoords_out
|
|
|
|
def remove_self_references(self,loop_numbers,loops):
|
|
for i in range(0,len(loops)):
|
|
for j in range(0,len(loop_numbers)):
|
|
if loops[i]==loop_numbers[j]:
|
|
loops.pop(i)
|
|
return
|
|
if self.LoopTree[loops[i]]!=[]:
|
|
loop_numbers.append(loops[i])
|
|
self.remove_self_references(loop_numbers,self.LoopTree[loops[i]])
|
|
|
|
def addlist(self,list):
|
|
for i in list:
|
|
try: #this try/except is a bad hack fix to a recursion error. It should be fixed properly later.
|
|
if self.LoopTree[i]!=[]:
|
|
self.addlist(self.LoopTree[i]) #too many recursions here causes cmp error
|
|
self.LoopTree[i]=[]
|
|
except:
|
|
pass
|
|
if self.loops[i]!=[]:
|
|
self.order.append(self.loops[i])
|
|
self.loops[i]=[]
|
|
|
|
|
|
def mirror_rotate_vector_coords(self,coords):
|
|
xmin = self.Design_bounds[0]
|
|
xmax = self.Design_bounds[1]
|
|
coords_rotate_mirror=[]
|
|
|
|
for i in range(len(coords)):
|
|
coords_rotate_mirror.append(coords[i][:])
|
|
if self.mirror.get():
|
|
if self.inputCSYS.get() and self.RengData.image == None:
|
|
coords_rotate_mirror[i][0]=-coords_rotate_mirror[i][0]
|
|
else:
|
|
coords_rotate_mirror[i][0]=xmin+xmax-coords_rotate_mirror[i][0]
|
|
|
|
|
|
if self.rotate.get():
|
|
x = coords_rotate_mirror[i][0]
|
|
y = coords_rotate_mirror[i][1]
|
|
coords_rotate_mirror[i][0] = -y
|
|
coords_rotate_mirror[i][1] = x
|
|
|
|
return coords_rotate_mirror
|
|
|
|
def scale_vector_coords(self,coords,startx,starty):
|
|
|
|
Xscale = float(self.LaserXscale.get())
|
|
Yscale = float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
|
|
coords_scale=[]
|
|
if Xscale != 1.0 or Yscale != 1.0:
|
|
for i in range(len(coords)):
|
|
coords_scale.append(coords[i][:])
|
|
x = coords_scale[i][0]
|
|
y = coords_scale[i][1]
|
|
coords_scale[i][0] = x*Xscale
|
|
coords_scale[i][1] = y*Yscale
|
|
scaled_startx = startx*Xscale
|
|
scaled_starty = starty*Yscale
|
|
else:
|
|
coords_scale = coords
|
|
scaled_startx = startx
|
|
scaled_starty = starty
|
|
|
|
return coords_scale,scaled_startx,scaled_starty
|
|
|
|
|
|
def feed_factor(self):
|
|
if self.units.get()=='in':
|
|
feed_factor = 25.4/60.0
|
|
else:
|
|
feed_factor = 1.0
|
|
return feed_factor
|
|
|
|
def send_data(self,operation_type=None, output_filename=None):
|
|
num_passes=0
|
|
if self.k40 == None and output_filename == None:
|
|
self.statusMessage.set("Laser Cutter is not Initialized...")
|
|
self.statusbar.configure( bg = 'red' )
|
|
return
|
|
try:
|
|
feed_factor=self.feed_factor()
|
|
|
|
if self.inputCSYS.get() and self.RengData.image == None:
|
|
xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
|
|
else:
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
|
|
startx = xmin
|
|
starty = ymax
|
|
|
|
if self.HomeUR.get():
|
|
Xscale = float(self.LaserXscale.get())
|
|
FlipXoffset = Xscale*abs(xmax-xmin)
|
|
if self.rotate.get():
|
|
startx = -xmin
|
|
else:
|
|
FlipXoffset = 0
|
|
|
|
if self.rotary.get():
|
|
Rapid_Feed = float(self.rapid_feed.get())*feed_factor
|
|
else:
|
|
Rapid_Feed = 0.0
|
|
|
|
Raster_Eng_data=[]
|
|
Vector_Eng_data=[]
|
|
Trace_Eng_data=[]
|
|
Vector_Cut_data=[]
|
|
G_code_Cut_data=[]
|
|
|
|
if (operation_type.find("Vector_Cut") > -1) and (self.VcutData.ecoords!=[]):
|
|
Feed_Rate = float(self.Vcut_feed.get())*feed_factor
|
|
self.statusMessage.set("Vector Cut: Determining Cut Order....")
|
|
self.master.update()
|
|
if not self.VcutData.sorted and self.inside_first.get():
|
|
self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True)
|
|
|
|
|
|
## DEBUG_PLOT=False
|
|
## test_ecoords=self.VcutData.ecoords
|
|
## if DEBUG_PLOT:
|
|
## import matplotlib.pyplot as plt
|
|
## plt.ion()
|
|
## plt.clf()
|
|
## X=[]
|
|
## Y=[]
|
|
## LOOP_OLD = test_ecoords[0][2]
|
|
## for i in range(len(test_ecoords)):
|
|
## LOOP = test_ecoords[i][2]
|
|
## if LOOP != LOOP_OLD:
|
|
## plt.plot(X,Y)
|
|
## plt.pause(.5)
|
|
## X=[]
|
|
## Y=[]
|
|
## LOOP_OLD=LOOP
|
|
## X.append(test_ecoords[i][0])
|
|
## Y.append(test_ecoords[i][1])
|
|
## plt.plot(X,Y)
|
|
|
|
|
|
self.statusMessage.set("Generating EGV data...")
|
|
self.master.update()
|
|
|
|
Vcut_coords = self.VcutData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords)
|
|
|
|
Vcut_coords,startx,starty = self.scale_vector_coords(Vcut_coords,startx,starty)
|
|
Vector_Cut_egv_inst = egv(target=lambda s:Vector_Cut_data.append(s))
|
|
Vector_Cut_egv_inst.make_egv_data(
|
|
Vcut_coords, \
|
|
startX=startx, \
|
|
startY=starty, \
|
|
Feed = Feed_Rate, \
|
|
board_name=self.board_name.get(), \
|
|
Raster_step = 0, \
|
|
update_gui=self.update_gui, \
|
|
stop_calc=self.stop, \
|
|
FlipXoffset=FlipXoffset, \
|
|
Rapid_Feed_Rate = Rapid_Feed, \
|
|
use_laser=True
|
|
)
|
|
|
|
if (operation_type.find("Vector_Eng") > -1) and (self.VengData.ecoords!=[]):
|
|
Feed_Rate = float(self.Veng_feed.get())*feed_factor
|
|
self.statusMessage.set("Vector Engrave: Determining Cut Order....")
|
|
self.master.update()
|
|
if not self.VengData.sorted and self.inside_first.get():
|
|
self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords,inside_check=False),data_sorted=True)
|
|
self.statusMessage.set("Generating EGV data...")
|
|
self.master.update()
|
|
|
|
Veng_coords = self.VengData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
Veng_coords = self.mirror_rotate_vector_coords(Veng_coords)
|
|
|
|
Veng_coords,startx,starty = self.scale_vector_coords(Veng_coords,startx,starty)
|
|
Vector_Eng_egv_inst = egv(target=lambda s:Vector_Eng_data.append(s))
|
|
Vector_Eng_egv_inst.make_egv_data(
|
|
Veng_coords, \
|
|
startX=startx, \
|
|
startY=starty, \
|
|
Feed = Feed_Rate, \
|
|
board_name=self.board_name.get(), \
|
|
Raster_step = 0, \
|
|
update_gui=self.update_gui, \
|
|
stop_calc=self.stop, \
|
|
FlipXoffset=FlipXoffset, \
|
|
Rapid_Feed_Rate = Rapid_Feed, \
|
|
use_laser=True
|
|
)
|
|
|
|
|
|
if (operation_type.find("Trace_Eng") > -1) and (self.trace_coords!=[]):
|
|
Feed_Rate = float(self.trace_speed.get())*feed_factor
|
|
laser_on = self.trace_w_laser.get()
|
|
self.statusMessage.set("Generating EGV data...")
|
|
self.master.update()
|
|
Trace_Eng_egv_inst = egv(target=lambda s:Trace_Eng_data.append(s))
|
|
Trace_Eng_egv_inst.make_egv_data(
|
|
self.trace_coords, \
|
|
startX=startx, \
|
|
startY=starty, \
|
|
Feed = Feed_Rate, \
|
|
board_name=self.board_name.get(), \
|
|
Raster_step = 0, \
|
|
update_gui=self.update_gui, \
|
|
stop_calc=self.stop, \
|
|
FlipXoffset=FlipXoffset, \
|
|
Rapid_Feed_Rate = Rapid_Feed, \
|
|
use_laser=laser_on
|
|
)
|
|
|
|
|
|
if (operation_type.find("Raster_Eng") > -1) and (self.RengData.ecoords!=[]):
|
|
Feed_Rate = float(self.Reng_feed.get())*feed_factor
|
|
Raster_step = self.get_raster_step_1000in()
|
|
if not self.engraveUP.get():
|
|
Raster_step = -Raster_step
|
|
|
|
raster_startx = 0
|
|
|
|
Yscale = float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
raster_starty = Yscale*starty
|
|
|
|
self.statusMessage.set("Generating EGV data...")
|
|
self.master.update()
|
|
Raster_Eng_egv_inst = egv(target=lambda s:Raster_Eng_data.append(s))
|
|
Raster_Eng_egv_inst.make_egv_data(
|
|
self.RengData.ecoords, \
|
|
startX=raster_startx, \
|
|
startY=raster_starty, \
|
|
Feed = Feed_Rate, \
|
|
board_name=self.board_name.get(), \
|
|
Raster_step = Raster_step, \
|
|
update_gui=self.update_gui, \
|
|
stop_calc=self.stop, \
|
|
FlipXoffset=FlipXoffset, \
|
|
Rapid_Feed_Rate = Rapid_Feed, \
|
|
use_laser=True
|
|
)
|
|
#print(len(Raster_Eng_data))
|
|
Raster_Eng_data=Raster_Eng_egv_inst.strip_redundant_codes(Raster_Eng_data)
|
|
#print(len(Raster_Eng_data))
|
|
|
|
if (operation_type.find("Gcode_Cut") > -1) and (self.GcodeData.ecoords!=[]):
|
|
self.statusMessage.set("Generating EGV data...")
|
|
self.master.update()
|
|
Gcode_coords = self.GcodeData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
Gcode_coords = self.mirror_rotate_vector_coords(Gcode_coords)
|
|
|
|
Gcode_coords,startx,starty = self.scale_vector_coords(Gcode_coords,startx,starty)
|
|
G_code_Cut_egv_inst = egv(target=lambda s:G_code_Cut_data.append(s))
|
|
G_code_Cut_egv_inst.make_egv_data(
|
|
Gcode_coords, \
|
|
startX=startx, \
|
|
startY=starty, \
|
|
Feed = None, \
|
|
board_name=self.board_name.get(), \
|
|
Raster_step = 0, \
|
|
update_gui=self.update_gui, \
|
|
stop_calc=self.stop, \
|
|
FlipXoffset=FlipXoffset, \
|
|
Rapid_Feed_Rate = Rapid_Feed, \
|
|
use_laser=True
|
|
)
|
|
|
|
### Join Resulting Data together ###
|
|
data=[]
|
|
data.append(ord("I"))
|
|
if Trace_Eng_data!=[]:
|
|
trace_passes=1
|
|
for k in range(trace_passes):
|
|
if len(data)> 4:
|
|
data[-4]=ord("@")
|
|
data.extend(Trace_Eng_data)
|
|
if Raster_Eng_data!=[]:
|
|
num_passes = int(float(self.Reng_passes.get()))
|
|
for k in range(num_passes):
|
|
if len(data)> 4:
|
|
data[-4]=ord("@")
|
|
data.extend(Raster_Eng_data)
|
|
if Vector_Eng_data!=[]:
|
|
num_passes = int(float(self.Veng_passes.get()))
|
|
for k in range(num_passes):
|
|
if len(data)> 4:
|
|
data[-4]=ord("@")
|
|
data.extend(Vector_Eng_data)
|
|
if Vector_Cut_data!=[]:
|
|
num_passes = int(float(self.Vcut_passes.get()))
|
|
for k in range(num_passes):
|
|
if len(data)> 4:
|
|
data[-4]=ord("@")
|
|
data.extend(Vector_Cut_data)
|
|
if G_code_Cut_data!=[]:
|
|
num_passes = int(float(self.Gcde_passes.get()))
|
|
for k in range(num_passes):
|
|
if len(data)> 4:
|
|
data[-4]=ord("@")
|
|
data.extend(G_code_Cut_data)
|
|
if len(data)< 4:
|
|
raise Exception("No laser data was generated.")
|
|
|
|
self.master.update()
|
|
if output_filename != None:
|
|
self.write_egv_to_file(data,output_filename)
|
|
else:
|
|
self.send_egv_data(data, 1, output_filename)
|
|
self.menu_View_Refresh()
|
|
|
|
except MemoryError as e:
|
|
msg1 = "Memory Error:"
|
|
msg2 = "Memory Error: Out of Memory."
|
|
self.statusMessage.set(msg2)
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
|
|
except Exception as e:
|
|
msg1 = "Sending Data Stopped: "
|
|
msg2 = "%s" %(e)
|
|
if msg2 == "":
|
|
formatted_lines = traceback.format_exc().splitlines()
|
|
self.statusMessage.set((msg1+msg2).split("\n")[0] )
|
|
self.statusbar.configure( bg = 'red' )
|
|
message_box(msg1, msg2)
|
|
debug_message(traceback.format_exc())
|
|
|
|
def send_egv_data(self,data,num_passes=1,output_filename=None):
|
|
pre_process_CRC = self.pre_pr_crc.get()
|
|
if self.k40 != None:
|
|
self.k40.timeout = int(float( self.t_timeout.get() ))
|
|
self.k40.n_timeouts = int(float( self.n_timeouts.get() ))
|
|
time_start = time()
|
|
self.k40.send_data(data,self.update_gui,self.stop,num_passes,pre_process_CRC, wait_for_laser=self.wait.get())
|
|
self.run_time = time()-time_start
|
|
if DEBUG:
|
|
print(("Elapsed Time: %.6f" %(time()-time_start)))
|
|
|
|
else:
|
|
self.statusMessage.set("Laser is not initialized.")
|
|
self.statusbar.configure( bg = 'yellow' )
|
|
return
|
|
self.menu_View_Refresh()
|
|
|
|
##########################################################################
|
|
##########################################################################
|
|
def write_egv_to_file(self,data,fname):
|
|
if len(data) == 0:
|
|
raise Exception("No data available to write to file.")
|
|
try:
|
|
fout = open(fname,'w')
|
|
except:
|
|
raise Exception("Unable to open file ( %s ) for writing." %(fname))
|
|
fout.write("Document type : LHYMICRO-GL file\n")
|
|
fout.write("Creator-Software: K40 Whisperer\n")
|
|
|
|
fout.write("\n")
|
|
fout.write("%0%0%0%0%")
|
|
for char_val in data:
|
|
char = chr(char_val)
|
|
fout.write("%s" %(char))
|
|
|
|
#fout.write("\n")
|
|
fout.close
|
|
self.menu_View_Refresh()
|
|
self.statusMessage.set("Data saved to: %s" %(fname))
|
|
|
|
def Home(self, event=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
if self.k40 != None:
|
|
self.k40.home_position()
|
|
self.laserX = 0.0
|
|
self.laserY = 0.0
|
|
self.pos_offset = [0.0,0.0]
|
|
self.menu_View_Refresh()
|
|
|
|
def GoTo(self):
|
|
xpos = float(self.gotoX.get())
|
|
ypos = float(self.gotoY.get())
|
|
if self.k40 != None:
|
|
self.k40.home_position()
|
|
self.laserX = 0.0
|
|
self.laserY = 0.0
|
|
self.Rapid_Move(xpos,ypos)
|
|
self.menu_View_Refresh()
|
|
|
|
def Reset(self):
|
|
if self.k40 != None:
|
|
try:
|
|
self.k40.reset_usb()
|
|
self.statusMessage.set("USB Reset Succeeded")
|
|
except:
|
|
debug_message(traceback.format_exc())
|
|
pass
|
|
|
|
def Stop(self,event=None):
|
|
if self.stop[0]==True:
|
|
return
|
|
line1 = "Sending data to the laser from K40 Whisperer is currently Paused."
|
|
line2 = "Press \"OK\" to abort any jobs currently running."
|
|
line3 = "Press \"Cancel\" to resume."
|
|
if self.k40 != None:
|
|
try:
|
|
self.k40.pause_un_pause()
|
|
except:
|
|
if message_ask_ok_cancel("Stop Laser Job.", "\n%s\n%s" %(line2,line3)):
|
|
self.stop[0]=True
|
|
|
|
if message_ask_ok_cancel("Stop Laser Job.", "%s\n\n%s\n%s" %(line1,line2,line3)):
|
|
self.stop[0]=True
|
|
else:
|
|
if self.k40 != None:
|
|
self.k40.pause_un_pause()
|
|
|
|
def Hide_Advanced(self,event=None):
|
|
self.advanced.set(0)
|
|
self.menu_View_Refresh()
|
|
|
|
def Show_Advanced(self,event=None):
|
|
self.advanced.set(1)
|
|
self.menu_View_Refresh()
|
|
|
|
def Toggle_Advanced(self,event=None):
|
|
if (self.advanced.get() == 0):
|
|
self.advanced.set(1)
|
|
else:
|
|
self.advanced.set(0)
|
|
self.menu_View_Refresh()
|
|
|
|
def Toggle_FastPlot(self,event=None):
|
|
if (self.fastPlot.get()):
|
|
self.fastPlot.set(False)
|
|
self.FastPlot_Button['image']=self.fastplot_off_image
|
|
#self.FastPlot_Button['text'] = "SP"
|
|
else:
|
|
self.fastPlot.set(True)
|
|
self.FastPlot_Button['image']=self.fastplot_on_image
|
|
#self.FastPlot_Button['text'] = "FP"
|
|
self.Plot_Data()
|
|
|
|
def Update_FastPlot(self,varName,index,mode):
|
|
if (self.fastPlot.get()):
|
|
self.FastPlot_Button['image']=self.fastplot_on_image
|
|
else:
|
|
self.FastPlot_Button['image']=self.fastplot_off_image
|
|
|
|
def Remember_Position(self,event=None):
|
|
if self.units.get()=="in":
|
|
self.gotoX.set(self.laserX + self.pos_offset[0]/1000.0)
|
|
self.gotoY.set(self.laserY + self.pos_offset[1]/1000.0)
|
|
else:
|
|
self.gotoX.set((self.laserX + self.pos_offset[0]/1000.0)*self.units_scale)
|
|
self.gotoY.set((self.laserY + self.pos_offset[1]/1000.0)*self.units_scale)
|
|
|
|
def SaveLoad_Toggle(self,event=None):
|
|
if self.saveLoadState.get():
|
|
self.saveLoadState.set(False)
|
|
self.SaveLoad_Button['image'] = self.cfg_load_image
|
|
else:
|
|
self.saveLoadState.set(True)
|
|
self.SaveLoad_Button['image'] = self.cfg_save_image
|
|
|
|
def SaveLoad_Slot(self,btn=None):
|
|
if (btn != 'D'):
|
|
btn = '_' + btn
|
|
else:
|
|
btn = ''
|
|
|
|
if (self.saveLoadState.get()):
|
|
self.Write_Config_File_Ex("k40_whisperer%s.txt" %(btn))
|
|
else:
|
|
self.Read_Config_File_Ex("k40_whisperer%s.txt" %(btn))
|
|
|
|
def Release_USB(self):
|
|
if self.k40 != None:
|
|
try:
|
|
self.k40.release_usb()
|
|
self.statusMessage.set("USB Release Succeeded")
|
|
except:
|
|
debug_message(traceback.format_exc())
|
|
pass
|
|
self.k40=None
|
|
|
|
def Initialize_Laser(self,event=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.stop[0]=True
|
|
self.Release_USB()
|
|
self.k40=None
|
|
self.move_head_window_temporary([0.0,0.0])
|
|
self.k40=K40_CLASS()
|
|
try:
|
|
self.k40.initialize_device()
|
|
self.k40.say_hello()
|
|
if self.init_home.get():
|
|
self.Home()
|
|
else:
|
|
self.Unlock()
|
|
|
|
except Exception as e:
|
|
error_text = "%s" %(e)
|
|
if "BACKEND" in error_text.upper():
|
|
error_text = error_text + " (libUSB driver not installed)"
|
|
self.statusMessage.set("USB Error: %s" %(error_text))
|
|
self.statusbar.configure( bg = 'red' )
|
|
self.k40=None
|
|
debug_message(traceback.format_exc())
|
|
|
|
except:
|
|
self.statusMessage.set("Unknown USB Error")
|
|
self.statusbar.configure( bg = 'red' )
|
|
self.k40=None
|
|
debug_message(traceback.format_exc())
|
|
|
|
def Unfreeze_Laser(self,event=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
if self.k40 != None:
|
|
try:
|
|
self.k40.unfreeze()
|
|
self.statusMessage.set("Unfreeze Complete")
|
|
self.statusbar.configure( bg = 'white' )
|
|
except:
|
|
pass
|
|
|
|
def Unlock(self,event=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
if self.k40 != None:
|
|
try:
|
|
self.k40.unlock_rail()
|
|
self.statusMessage.set("Rail Unlock Succeeded")
|
|
self.statusbar.configure( bg = 'white' )
|
|
except:
|
|
self.statusMessage.set("Rail Unlock Failed.")
|
|
self.statusbar.configure( bg = 'red' )
|
|
debug_message(traceback.format_exc())
|
|
pass
|
|
|
|
##########################################################################
|
|
##########################################################################
|
|
|
|
def menu_File_Quit(self):
|
|
if message_ask_ok_cancel("Exit", "Exiting...."):
|
|
self.Quit_Click(None)
|
|
|
|
def Reset_RasterPath_and_Update_Time(self, varName=0, index=0, mode=0):
|
|
self.RengData.reset_path()
|
|
self.refreshTime()
|
|
|
|
def View_Refresh_and_Reset_RasterPath(self, varName=0, index=0, mode=0):
|
|
self.RengData.reset_path()
|
|
self.SCALE = 0
|
|
self.menu_View_Refresh()
|
|
|
|
def menu_View_inputCSYS_Refresh_Callback(self, varName, index, mode):
|
|
self.move_head_window_temporary([0.0,0.0])
|
|
self.SCALE = 0
|
|
self.menu_View_Refresh()
|
|
|
|
def menu_View_Refresh_Callback(self, varName=0, index=0, mode=0):
|
|
self.SCALE = 0
|
|
self.menu_View_Refresh()
|
|
|
|
if DEBUG:
|
|
curframe = inspect.currentframe()
|
|
calframe = inspect.getouterframes(curframe, 2)
|
|
print('menu_View_Refresh_Callback called by: %s' %(calframe[1][3]))
|
|
|
|
def menu_View_Refresh(self):
|
|
if DEBUG:
|
|
curframe = inspect.currentframe()
|
|
calframe = inspect.getouterframes(curframe, 2)
|
|
print('menu_View_Refresh called by: %s' %(calframe[1][3]))
|
|
|
|
try:
|
|
app.master.title(title_text+" "+ self.DESIGN_FILE)
|
|
except:
|
|
pass
|
|
dummy_event = Event()
|
|
dummy_event.widget=self.master
|
|
self.Master_Configure(dummy_event,1)
|
|
self.Plot_Data()
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
W = xmax-xmin
|
|
H = ymax-ymin
|
|
|
|
if self.units.get()=="in":
|
|
X_display = self.laserX + self.pos_offset[0]/1000.0
|
|
Y_display = self.laserY + self.pos_offset[1]/1000.0
|
|
W_display = W
|
|
H_display = H
|
|
U_display = self.units.get()
|
|
else:
|
|
X_display = (self.laserX + self.pos_offset[0]/1000.0)*self.units_scale
|
|
Y_display = (self.laserY + self.pos_offset[1]/1000.0)*self.units_scale
|
|
W_display = W*self.units_scale
|
|
H_display = H*self.units_scale
|
|
U_display = self.units.get()
|
|
if self.HomeUR.get():
|
|
X_display = -X_display
|
|
|
|
self.statusMessage.set(" Current Position: X=%.3f Y=%.3f ( W X H )=( %.3f%s X %.3f%s ) "
|
|
%(X_display,
|
|
Y_display,
|
|
W_display,
|
|
U_display,
|
|
H_display,
|
|
U_display))
|
|
|
|
self.statusbar.configure( bg = 'white' )
|
|
|
|
def menu_Inside_First_Callback(self, varName, index, mode):
|
|
if self.GcodeData.ecoords != []:
|
|
if self.VcutData.sorted == True:
|
|
self.menu_Reload_Design()
|
|
elif self.VengData.sorted == True:
|
|
self.menu_Reload_Design()
|
|
|
|
def menu_Mode_Change(self):
|
|
dummy_event = Event()
|
|
dummy_event.widget=self.master
|
|
self.Master_Configure(dummy_event,1)
|
|
|
|
def menu_Calc_Raster_Time(self,event=None):
|
|
self.set_gui("disabled")
|
|
self.stop[0]=False
|
|
self.make_raster_coords()
|
|
self.stop[0]=True
|
|
self.refreshTime()
|
|
self.set_gui("normal")
|
|
self.menu_View_Refresh()
|
|
|
|
|
|
def menu_Help_About(self):
|
|
application="K40 Whisperer"
|
|
about = "%s Version %s\n\n" %(application,version)
|
|
about = about + "By Scorch.\n"
|
|
about = about + "\163\143\157\162\143\150\100\163\143\157\162"
|
|
about = about + "\143\150\167\157\162\153\163\056\143\157\155\n"
|
|
about = about + "https://www.scorchworks.com/\n\n"
|
|
about = about + "TURBO fork by AfBu.\n"
|
|
about = about + "https://github.com/AfBu/k40whisperer_turbo\n\n"
|
|
try:
|
|
python_version = "%d.%d.%d" %(sys.version_info.major,sys.version_info.minor,sys.version_info.micro)
|
|
except:
|
|
python_version = ""
|
|
about = about + "Python "+python_version+" (%d bit)" %(struct.calcsize("P") * 8)
|
|
message_box("About %s" %(application),about)
|
|
|
|
def menu_Help_GitHub(self):
|
|
webbrowser.open_new(r"https://github.com/AfBu/k40whisperer_turbo")
|
|
|
|
def menu_Help_Web(self):
|
|
webbrowser.open_new(r"https://www.scorchworks.com/K40whisperer/k40whisperer.html")
|
|
|
|
def menu_Help_Manual(self):
|
|
webbrowser.open_new(r"https://www.scorchworks.com/K40whisperer/k40w_manual.html")
|
|
|
|
def KEY_F1(self, event):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.menu_Help_About()
|
|
|
|
def KEY_F2(self, event):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.GEN_Settings_Window()
|
|
|
|
def KEY_F3(self, event):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.RASTER_Settings_Window()
|
|
|
|
def KEY_F4(self, event):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.ROTARY_Settings_Window()
|
|
self.menu_View_Refresh()
|
|
|
|
def KEY_F5(self, event):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.menu_View_Refresh()
|
|
|
|
def KEY_F6(self, event):
|
|
if self.GUI_Disabled:
|
|
return
|
|
self.advanced.set(not self.advanced.get())
|
|
self.menu_View_Refresh()
|
|
|
|
def bindConfigure(self, event):
|
|
if not self.initComplete:
|
|
self.initComplete = 1
|
|
self.menu_Mode_Change()
|
|
|
|
def Master_Configure(self, event, update=0):
|
|
if event.widget != self.master:
|
|
return
|
|
x = int(self.master.winfo_x())
|
|
y = int(self.master.winfo_y())
|
|
w = int(self.master.winfo_width())
|
|
h = int(self.master.winfo_height())
|
|
if (self.x, self.y) == (-1,-1):
|
|
self.x, self.y = x,y
|
|
if abs(self.w-w)>10 or abs(self.h-h)>10 or update==1:
|
|
###################################################
|
|
# Form changed Size (resized) adjust as required #
|
|
###################################################
|
|
self.w=w
|
|
self.h=h
|
|
|
|
# TURBO Toolbar
|
|
typos = 10
|
|
self.FastPlot_Button.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos + 45
|
|
self.Fullscreen_Button.place(x=w-50, y=typos, width=40, height=40)
|
|
typos = typos + 45
|
|
self.AdvancedShow_Button.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos + 45
|
|
self.Remember_Button.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos + 45
|
|
self.Restore_Button.place(x=w - 50, y=typos, width=40, height=40)
|
|
|
|
typos = h - 70
|
|
self.SaveSlot_Button5.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos - 45
|
|
self.SaveSlot_Button4.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos - 45
|
|
self.SaveSlot_Button3.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos - 45
|
|
self.SaveSlot_Button2.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos - 45
|
|
self.SaveSlot_Button1.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos - 45
|
|
self.SaveSlot_ButtonD.place(x=w - 50, y=typos, width=40, height=40)
|
|
typos = typos - 45
|
|
self.SaveLoad_Button.place(x=w - 50, y=typos, width=40, height=40)
|
|
|
|
if True:
|
|
# Left Column #
|
|
w_label=120
|
|
w_entry=48
|
|
w_units=52
|
|
|
|
x_label_L=10
|
|
x_entry_L=x_label_L+w_label+20-5
|
|
x_units_L=x_entry_L+w_entry+2
|
|
|
|
Yloc=10
|
|
self.Initialize_Button.place (x=0, y=Yloc, width=280, height=40)
|
|
Yloc=Yloc+50
|
|
|
|
self.Open_Button.place (x=0, y=Yloc, width=140, height=50)
|
|
self.Reload_Button.place(x=140, y=Yloc, width=140, height=50)
|
|
Yloc=Yloc+10
|
|
|
|
if h>=660:
|
|
Yloc=Yloc+50
|
|
#self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40+30, height=2)
|
|
self.separator1.place_forget()
|
|
#Yloc=Yloc+6
|
|
#self.Label_Position_Control.place(x=x_label_L, y=Yloc, width=w_label*2, height=21)
|
|
self.Label_Position_Control.place_forget()
|
|
|
|
Yloc=Yloc
|
|
self.Home_Button.place (x=0, y=Yloc, width=140, height=40)
|
|
self.UnLock_Button.place(x=140, y=Yloc, width=140, height=40)
|
|
|
|
Yloc=Yloc+50
|
|
self.Label_Step.place(x=10, y=Yloc, width=80, height=40)
|
|
#self.Label_Step_u.place(x=x_units_L, y=Yloc, width=w_units, height=21)
|
|
self.Label_Step_u.place_forget()
|
|
|
|
self.Entry_Step.place(x=140, y=Yloc, width=100, height=40)
|
|
self.Step_Button_Minus.place(x=100, y=Yloc, width=40, height=40)
|
|
self.Step_Button_Plus.place(x=240, y=Yloc, width=40, height=40)
|
|
|
|
###########################################################################
|
|
Yloc=Yloc+50
|
|
bsz=40
|
|
xoffst=67
|
|
|
|
self.Up_Button_100.place (x=xoffst+12+bsz - bsz * 2 , y=Yloc, width=bsz * 5, height=bsz)
|
|
self.UL_Button.place (x=xoffst+12-bsz*2 , y=Yloc, width=bsz, height=bsz)
|
|
self.UR_Button.place (x=xoffst+12+bsz*4, y=Yloc, width=bsz, height=bsz)
|
|
|
|
Yloc=Yloc+bsz
|
|
|
|
self.Up_Button_10.place (x=xoffst+12+bsz - bsz , y=Yloc, width=bsz * 3, height=bsz)
|
|
|
|
Yloc=Yloc+bsz
|
|
|
|
self.Up_Button.place (x=xoffst+12+bsz , y=Yloc, width=bsz, height=bsz)
|
|
|
|
Yloc=Yloc+bsz
|
|
|
|
self.Left_Button.place (x=xoffst+12 ,y=Yloc, width=bsz, height=bsz)
|
|
self.Left_Button_10.place (x=xoffst+12-bsz ,y=Yloc-bsz, width=bsz, height=bsz*3)
|
|
self.Left_Button_100.place (x=xoffst+12-bsz*2 ,y=Yloc-bsz*2, width=bsz, height=bsz*5)
|
|
|
|
self.CC_Button.place (x=xoffst+12+bsz ,y=Yloc, width=bsz, height=bsz)
|
|
|
|
self.Right_Button.place (x=xoffst+12+bsz*2,y=Yloc, width=bsz, height=bsz)
|
|
self.Right_Button_10.place (x=xoffst+12+bsz*3,y=Yloc-bsz, width=bsz, height=bsz*3)
|
|
self.Right_Button_100.place (x=xoffst+12+bsz*4,y=Yloc-bsz*2, width=bsz, height=bsz*5)
|
|
|
|
Yloc=Yloc+bsz
|
|
|
|
self.Down_Button.place (x=xoffst+12+bsz , y=Yloc, width=bsz, height=bsz)
|
|
|
|
Yloc=Yloc+bsz
|
|
|
|
self.Down_Button_10.place (x=xoffst+12+bsz - bsz , y=Yloc, width=bsz * 3, height=bsz)
|
|
|
|
Yloc=Yloc+bsz
|
|
|
|
self.Down_Button_100.place (x=xoffst+12+bsz - bsz * 2 , y=Yloc, width=bsz * 5, height=bsz)
|
|
self.LL_Button.place (x=xoffst+12-bsz*2 , y=Yloc, width=bsz, height=bsz)
|
|
self.LR_Button.place (x=xoffst+12+bsz*4, y=Yloc, width=bsz, height=bsz)
|
|
|
|
Yloc=Yloc+bsz
|
|
###########################################################################
|
|
Yloc=Yloc+5
|
|
self.Frame_Button.place(x=0, y=Yloc, width=280, height=40)
|
|
|
|
Yloc=Yloc+35
|
|
###########################################################################
|
|
#self.Label_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
|
|
#self.Label_GoToY.place(x=x_units_L+25, y=Yloc, width=w_entry, height=23)
|
|
self.Label_GoToX.place_forget()
|
|
self.Label_GoToY.place_forget()
|
|
Yloc=Yloc+10
|
|
self.GoTo_Button.place (x=0, y=Yloc, width=120, height=40)
|
|
self.Entry_GoToX.place(x=x_entry_L-10, y=Yloc, width=w_entry+20, height=40)
|
|
self.Entry_GoToY.place(x=x_units_L+15, y=Yloc, width=w_entry+20, height=40)
|
|
###########################################################################
|
|
else:
|
|
###########################################################################
|
|
self.separator1.place_forget()
|
|
self.Label_Position_Control.place_forget()
|
|
##
|
|
Yloc=Yloc+50
|
|
self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40+30, height=2)
|
|
#self.separator1.place_forget()
|
|
Yloc=Yloc+6
|
|
self.Home_Button.place (x=12, y=Yloc, width=130, height=23)
|
|
self.UnLock_Button.place(x=12+130, y=Yloc, width=130, height=23)
|
|
##
|
|
self.Label_Step.place_forget()
|
|
self.Label_Step_u.place_forget()
|
|
self.Entry_Step.place_forget()
|
|
self.UL_Button.place_forget()
|
|
self.Up_Button.place_forget()
|
|
self.Up_Button_10.place_forget()
|
|
self.Up_Button_100.place_forget()
|
|
self.UR_Button.place_forget()
|
|
self.Left_Button.place_forget()
|
|
self.Left_Button_10.place_forget()
|
|
self.Left_Button_100.place_forget()
|
|
self.CC_Button.place_forget()
|
|
self.Right_Button.place_forget()
|
|
self.Right_Button_10.place_forget()
|
|
self.Right_Button_100.place_forget()
|
|
self.LL_Button.place_forget()
|
|
self.Down_Button.place_forget()
|
|
self.Down_Button_10.place_forget()
|
|
self.Down_Button_100.place_forget()
|
|
self.LR_Button.place_forget()
|
|
self.Label_GoToX.place_forget()
|
|
self.Label_GoToY.place_forget()
|
|
self.GoTo_Button.place_forget()
|
|
self.Frame_Button.place_forget()
|
|
self.Entry_GoToX.place_forget()
|
|
self.Entry_GoToY.place_forget()
|
|
###########################################################################
|
|
|
|
#From Bottom up
|
|
BUinit = self.h-70
|
|
Yloc = BUinit
|
|
self.Stop_Button.place (x=0, y=Yloc, width=280, height=40)
|
|
|
|
self.Stop_Button.configure(bg='light coral')
|
|
Yloc=Yloc-10+10
|
|
|
|
wadv = 220 #200
|
|
wadv_use = wadv-20
|
|
Xvert_sep = 280
|
|
Xadvanced = Xvert_sep+10
|
|
w_label_adv= wadv-60 # 110 w_entry
|
|
|
|
if self.GcodeData.ecoords == []:
|
|
self.Grun_Button.place_forget()
|
|
self.Reng_Veng_Vcut_Button.place_forget()
|
|
self.Reng_Veng_Button.place_forget()
|
|
self.Veng_Vcut_Button.place_forget()
|
|
|
|
Yloc=Yloc-40
|
|
self.Vcut_Button.place (x=0, y=Yloc, width=140, height=40)
|
|
self.Vcut_Button_Plus.place (x=240, y=Yloc, width=40, height=40)
|
|
self.Vcut_Button_Minus.place (x=140, y=Yloc, width=40, height=40)
|
|
self.Entry_Vcut_feed.place (x=180, y=Yloc, width=60, height=40)
|
|
#self.Label_Vcut_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
|
|
self.Label_Vcut_feed_u.place_forget()
|
|
Y_Vcut=Yloc
|
|
|
|
Yloc=Yloc-40
|
|
self.Veng_Button.place (x=0, y=Yloc, width=140, height=40)
|
|
self.Veng_Button_Plus.place (x=240, y=Yloc, width=40, height=40)
|
|
self.Veng_Button_Minus.place (x=140, y=Yloc, width=40, height=40)
|
|
self.Entry_Veng_feed.place( x=180, y=Yloc, width=60, height=40)
|
|
#self.Label_Veng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
|
|
self.Label_Veng_feed_u.place_forget()
|
|
Y_Veng=Yloc
|
|
|
|
Yloc=Yloc-40
|
|
self.Reng_Button.place (x=0, y=Yloc, width=140, height=40)
|
|
self.Reng_Button_Plus.place (x=240, y=Yloc, width=40, height=40)
|
|
self.Reng_Button_Minus.place (x=140, y=Yloc, width=40, height=40)
|
|
self.Entry_Reng_feed.place( x=180, y=Yloc, width=60, height=40)
|
|
#self.Label_Reng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
|
|
self.Label_Reng_feed_u.place_forget()
|
|
Y_Reng=Yloc
|
|
|
|
if self.comb_vector.get() or self.comb_engrave.get():
|
|
if self.comb_engrave.get():
|
|
self.Veng_Button.place_forget()
|
|
self.Reng_Button.place_forget()
|
|
if self.comb_vector.get():
|
|
self.Vcut_Button.place_forget()
|
|
self.Veng_Button.place_forget()
|
|
|
|
if self.comb_engrave.get():
|
|
if self.comb_vector.get():
|
|
self.Reng_Veng_Vcut_Button.place(x=0, y=Y_Reng, width=140, height=120)
|
|
else:
|
|
self.Reng_Veng_Button.place(x=0, y=Y_Reng, width=140, height=80)
|
|
elif self.comb_vector.get():
|
|
self.Veng_Vcut_Button.place(x=0, y=Y_Veng, width=140, height=80)
|
|
|
|
|
|
else:
|
|
self.Vcut_Button.place_forget()
|
|
self.Vcut_Button_Plus.place_forget()
|
|
self.Vcut_Button_Minus.place_forget()
|
|
self.Entry_Vcut_feed.place_forget()
|
|
self.Label_Vcut_feed_u.place_forget()
|
|
|
|
self.Veng_Button.place_forget()
|
|
self.Veng_Button_Plus.place_forget()
|
|
self.Veng_Button_Minus.place_forget()
|
|
self.Entry_Veng_feed.place_forget()
|
|
self.Label_Veng_feed_u.place_forget()
|
|
|
|
self.Reng_Button.place_forget()
|
|
self.Reng_Button_Plus.place_forget()
|
|
self.Reng_Button_Minus.place_forget()
|
|
self.Entry_Reng_feed.place_forget()
|
|
self.Label_Reng_feed_u.place_forget()
|
|
|
|
self.Reng_Veng_Vcut_Button.place_forget()
|
|
self.Reng_Veng_Button.place_forget()
|
|
self.Veng_Vcut_Button.place_forget()
|
|
|
|
Yloc=Yloc-30
|
|
self.Grun_Button.place (x=0, y=Yloc, width=280, height=40)
|
|
|
|
#if h>=560:
|
|
# Yloc=Yloc-15
|
|
# self.separator2.place(x=x_label_L, y=Yloc,width=w_label+75+40+30, height=2)
|
|
#else:
|
|
# self.separator2.place_forget()
|
|
self.separator2.place_forget()
|
|
|
|
# End Left Column #
|
|
|
|
if self.advanced.get():
|
|
|
|
self.PreviewCanvas.configure( width = self.w-300-wadv-40, height = self.h-50 )
|
|
self.PreviewCanvas_frame.place(x=280+wadv, y=10)
|
|
self.separator_vert.place(x=280, y=10,width=2, height=self.h-50)
|
|
|
|
adv_Yloc=25-10 #15
|
|
self.Label_Advanced_column.place(x=Xadvanced, y=adv_Yloc, width=wadv_use, height=35)
|
|
adv_Yloc=adv_Yloc+40
|
|
self.separator_adv.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
|
|
|
|
if h>=560:
|
|
adv_Yloc=adv_Yloc+10
|
|
self.Label_Halftone_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Halftone_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc+45
|
|
self.Label_Negate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Negate_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc+45
|
|
self.separator_adv2.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
|
|
|
|
adv_Yloc=adv_Yloc+10
|
|
self.Label_Mirror_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Mirror_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc+45
|
|
self.Label_Rotate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Rotate_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc+45
|
|
self.Label_inputCSYS_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_inputCSYS_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc+45
|
|
self.separator_adv3.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
|
|
|
|
adv_Yloc=adv_Yloc+10
|
|
self.Label_Inside_First_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Inside_First_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc+45
|
|
self.Label_Rotary_Enable_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Rotary_Enable_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
else:
|
|
#self.Label_Advanced_column.place_forget()
|
|
#self.separator_adv.place_forget()
|
|
self.Label_Halftone_adv.place_forget()
|
|
self.Checkbutton_Halftone_adv.place_forget()
|
|
self.Label_Negate_adv.place_forget()
|
|
self.Checkbutton_Negate_adv.place_forget()
|
|
self.separator_adv2.place_forget()
|
|
self.Label_Mirror_adv.place_forget()
|
|
self.Checkbutton_Mirror_adv.place_forget()
|
|
self.Label_Rotate_adv.place_forget()
|
|
self.Checkbutton_Rotate_adv.place_forget()
|
|
self.Label_inputCSYS_adv.place_forget()
|
|
self.Checkbutton_inputCSYS_adv.place_forget()
|
|
self.separator_adv3.place_forget()
|
|
self.Label_Inside_First_adv.place_forget()
|
|
self.Checkbutton_Inside_First_adv.place_forget()
|
|
self.Label_Rotary_Enable_adv.place_forget()
|
|
self.Checkbutton_Rotary_Enable_adv.place_forget()
|
|
|
|
adv_Yloc = BUinit
|
|
self.Hide_Adv_Button.place (x=Xadvanced-5, y=adv_Yloc, width=wadv_use+10, height=40)
|
|
|
|
if self.RengData.image != None:
|
|
self.Label_inputCSYS_adv.configure(state="disabled")
|
|
self.Checkbutton_inputCSYS_adv.place_forget()
|
|
else:
|
|
self.Label_inputCSYS_adv.configure(state="normal")
|
|
|
|
if self.GcodeData.ecoords == []:
|
|
#adv_Yloc = adv_Yloc-40
|
|
self.Label_Vcut_passes.place(x=Xadvanced, y=Y_Vcut, width=75, height=40)
|
|
self.Entry_Vcut_passes.place(x=Xadvanced+120, y=Y_Vcut, width=45, height=40)
|
|
self.Vcut_Passes_Button_Plus.place(x=Xadvanced+165, y=Y_Vcut, width=40, height=40)
|
|
self.Vcut_Passes_Button_Minus.place(x=Xadvanced+80, y=Y_Vcut, width=40, height=40)
|
|
|
|
#adv_Yloc=adv_Yloc-30
|
|
self.Label_Veng_passes.place(x=Xadvanced, y=Y_Veng, width=75, height=40)
|
|
self.Entry_Veng_passes.place(x=Xadvanced+120, y=Y_Veng, width=45, height=40)
|
|
self.Veng_Passes_Button_Plus.place(x=Xadvanced+165, y=Y_Veng, width=40, height=40)
|
|
self.Veng_Passes_Button_Minus.place(x=Xadvanced+80, y=Y_Veng, width=40, height=40)
|
|
|
|
#adv_Yloc=adv_Yloc-30
|
|
self.Label_Reng_passes.place(x=Xadvanced, y=Y_Reng, width=75, height=40)
|
|
self.Entry_Reng_passes.place(x=Xadvanced+120, y=Y_Reng, width=45, height=40)
|
|
self.Reng_Passes_Button_Plus.place(x=Xadvanced+165, y=Y_Reng, width=40, height=40)
|
|
self.Reng_Passes_Button_Minus.place(x=Xadvanced+80, y=Y_Reng, width=40, height=40)
|
|
self.Label_Gcde_passes.place_forget()
|
|
self.Entry_Gcde_passes.place_forget()
|
|
adv_Yloc = Y_Reng
|
|
|
|
####
|
|
adv_Yloc=adv_Yloc-15
|
|
self.separator_comb.place(x=Xadvanced-1, y=adv_Yloc, width=wadv_use, height=2)
|
|
|
|
adv_Yloc=adv_Yloc-45
|
|
self.Label_Comb_Vector_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Comb_Vector_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
|
|
adv_Yloc=adv_Yloc-45
|
|
self.Label_Comb_Engrave_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=40)
|
|
self.Checkbutton_Comb_Engrave_adv.place(x=Xadvanced+165, y=adv_Yloc, width=40, height=40)
|
|
####
|
|
|
|
else:
|
|
adv_Yloc=adv_Yloc-40
|
|
self.Label_Gcde_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
|
|
self.Entry_Gcde_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23)
|
|
self.Label_Vcut_passes.place_forget()
|
|
self.Entry_Vcut_passes.place_forget()
|
|
self.Label_Veng_passes.place_forget()
|
|
self.Entry_Veng_passes.place_forget()
|
|
self.Label_Reng_passes.place_forget()
|
|
self.Entry_Reng_passes.place_forget()
|
|
self.Veng_Passes_Button_Plus.place_forget()
|
|
self.Veng_Passes_Button_Minus.place_forget()
|
|
self.Reng_Passes_Button_Plus.place_forget()
|
|
self.Reng_Passes_Button_Minus.place_forget()
|
|
self.Vcut_Passes_Button_Plus.place_forget()
|
|
self.Vcut_Passes_Button_Minus.place_forget()
|
|
|
|
else:
|
|
self.PreviewCanvas_frame.place_forget()
|
|
self.separator_vert.place_forget()
|
|
self.Label_Advanced_column.place_forget()
|
|
self.separator_adv.place_forget()
|
|
self.Label_Halftone_adv.place_forget()
|
|
self.Checkbutton_Halftone_adv.place_forget()
|
|
self.Label_Negate_adv.place_forget()
|
|
self.Checkbutton_Negate_adv.place_forget()
|
|
self.separator_adv2.place_forget()
|
|
self.Label_Mirror_adv.place_forget()
|
|
self.Checkbutton_Mirror_adv.place_forget()
|
|
self.Label_Rotate_adv.place_forget()
|
|
self.Checkbutton_Rotate_adv.place_forget()
|
|
self.Label_inputCSYS_adv.place_forget()
|
|
self.Checkbutton_inputCSYS_adv.place_forget()
|
|
self.separator_adv3.place_forget()
|
|
self.Label_Inside_First_adv.place_forget()
|
|
self.Checkbutton_Inside_First_adv.place_forget()
|
|
|
|
self.Label_Rotary_Enable_adv.place_forget()
|
|
self.Checkbutton_Rotary_Enable_adv.place_forget()
|
|
|
|
self.separator_comb.place_forget()
|
|
self.Label_Comb_Engrave_adv.place_forget()
|
|
self.Checkbutton_Comb_Engrave_adv.place_forget()
|
|
self.Label_Comb_Vector_adv.place_forget()
|
|
self.Checkbutton_Comb_Vector_adv.place_forget()
|
|
|
|
self.Veng_Passes_Button_Plus.place_forget()
|
|
self.Veng_Passes_Button_Minus.place_forget()
|
|
self.Reng_Passes_Button_Plus.place_forget()
|
|
self.Reng_Passes_Button_Minus.place_forget()
|
|
self.Vcut_Passes_Button_Plus.place_forget()
|
|
self.Vcut_Passes_Button_Minus.place_forget()
|
|
|
|
self.Entry_Vcut_passes.place_forget()
|
|
self.Label_Vcut_passes.place_forget()
|
|
self.Entry_Veng_passes.place_forget()
|
|
self.Label_Veng_passes.place_forget()
|
|
self.Entry_Reng_passes.place_forget()
|
|
self.Label_Reng_passes.place_forget()
|
|
self.Label_Gcde_passes.place_forget()
|
|
self.Entry_Gcde_passes.place_forget()
|
|
self.Hide_Adv_Button.place_forget()
|
|
|
|
self.PreviewCanvas.configure( width = self.w-300-40, height = self.h-50 )
|
|
self.PreviewCanvas_frame.place(x=Xvert_sep, y=10)
|
|
self.separator_vert.place_forget()
|
|
|
|
self.Set_Input_States()
|
|
|
|
self.Plot_Data()
|
|
|
|
def Recalculate_RQD_Click(self, event):
|
|
self.menu_View_Refresh()
|
|
|
|
def Set_Input_States(self):
|
|
pass
|
|
|
|
def Set_Input_States_Event(self,event):
|
|
self.Set_Input_States()
|
|
|
|
def Set_Input_States_RASTER(self,event=None):
|
|
if self.halftone.get():
|
|
self.Label_Halftone_DPI.configure(state="normal")
|
|
self.Halftone_DPI_OptionMenu.configure(state="normal")
|
|
self.Label_Halftone_u.configure(state="normal")
|
|
self.Label_bezier_M1.configure(state="normal")
|
|
self.bezier_M1_Slider.configure(state="normal")
|
|
self.Label_bezier_M2.configure(state="normal")
|
|
self.bezier_M2_Slider.configure(state="normal")
|
|
self.Label_bezier_weight.configure(state="normal")
|
|
self.bezier_weight_Slider.configure(state="normal")
|
|
else:
|
|
self.Label_Halftone_DPI.configure(state="disabled")
|
|
self.Halftone_DPI_OptionMenu.configure(state="disabled")
|
|
self.Label_Halftone_u.configure(state="disabled")
|
|
self.Label_bezier_M1.configure(state="disabled")
|
|
self.bezier_M1_Slider.configure(state="disabled")
|
|
self.Label_bezier_M2.configure(state="disabled")
|
|
self.bezier_M2_Slider.configure(state="disabled")
|
|
self.Label_bezier_weight.configure(state="disabled")
|
|
self.bezier_weight_Slider.configure(state="disabled")
|
|
|
|
def Set_Input_States_BATCH(self):
|
|
if self.post_exec.get():
|
|
self.Entry_Batch_Path.configure(state="normal")
|
|
else:
|
|
self.Entry_Batch_Path.configure(state="disabled")
|
|
## def Set_Input_States_Unsharp(self,event=None):
|
|
## if self.unsharp_flag.get():
|
|
## self.Label_Unsharp_Radius.configure(state="normal")
|
|
## self.Label_Unsharp_Radius_u.configure(state="normal")
|
|
## self.Entry_Unsharp_Radius.configure(state="normal")
|
|
## self.Label_Unsharp_Percent.configure(state="normal")
|
|
## self.Label_Unsharp_Percent_u.configure(state="normal")
|
|
## self.Entry_Unsharp_Percent.configure(state="normal")
|
|
## self.Label_Unsharp_Threshold.configure(state="normal")
|
|
## self.Entry_Unsharp_Threshold.configure(state="normal")
|
|
##
|
|
## else:
|
|
## self.Label_Unsharp_Radius.configure(state="disabled")
|
|
## self.Label_Unsharp_Radius_u.configure(state="disabled")
|
|
## self.Entry_Unsharp_Radius.configure(state="disabled")
|
|
## self.Label_Unsharp_Percent.configure(state="disabled")
|
|
## self.Label_Unsharp_Percent_u.configure(state="disabled")
|
|
## self.Entry_Unsharp_Percent.configure(state="disabled")
|
|
## self.Label_Unsharp_Threshold.configure(state="disabled")
|
|
## self.Entry_Unsharp_Threshold.configure(state="disabled")
|
|
|
|
def Set_Input_States_Rotary(self,event=None):
|
|
if self.rotary.get():
|
|
self.Label_Laser_R_Scale.configure(state="normal")
|
|
self.Entry_Laser_R_Scale.configure(state="normal")
|
|
self.Label_Laser_Rapid_Feed.configure(state="normal")
|
|
self.Label_Laser_Rapid_Feed_u.configure(state="normal")
|
|
self.Entry_Laser_Rapid_Feed.configure(state="normal")
|
|
else:
|
|
self.Label_Laser_R_Scale.configure(state="disabled")
|
|
self.Entry_Laser_R_Scale.configure(state="disabled")
|
|
self.Label_Laser_Rapid_Feed.configure(state="disabled")
|
|
self.Label_Laser_Rapid_Feed_u.configure(state="disabled")
|
|
self.Entry_Laser_Rapid_Feed.configure(state="disabled")
|
|
|
|
# def Set_Input_States_RASTER_Event(self,event):
|
|
# self.Set_Input_States_RASTER()
|
|
|
|
def Imaging_Free(self,image_in,bg="#ffffff"):
|
|
image_in = image_in.convert('L')
|
|
wim,him = image_in.size
|
|
image_out=PhotoImage(width=wim,height=him)
|
|
pixel=image_in.load()
|
|
if bg!=None:
|
|
image_out.put(bg, to=(0,0,wim,him))
|
|
for y in range(0,him):
|
|
for x in range(0,wim):
|
|
val=pixel[x,y]
|
|
if val!=255:
|
|
image_out.put("#%02x%02x%02x" %(val,val,val),(x,y))
|
|
return image_out
|
|
|
|
##########################################
|
|
# CANVAS PLOTTING STUFF #
|
|
##########################################
|
|
def Plot_Data(self):
|
|
self.PreviewCanvas.delete(ALL)
|
|
self.calc_button.place_forget()
|
|
|
|
for seg in self.segID:
|
|
self.PreviewCanvas.delete(seg)
|
|
self.segID = []
|
|
|
|
cszw = int(self.PreviewCanvas.cget("width"))
|
|
cszh = int(self.PreviewCanvas.cget("height"))
|
|
buff=10
|
|
wc = float(cszw/2)
|
|
hc = float(cszh/2)
|
|
|
|
maxx = float(self.LaserXsize.get()) / self.units_scale
|
|
minx = 0.0
|
|
maxy = 0.0
|
|
miny = -float(self.LaserYsize.get()) / self.units_scale
|
|
midx=(maxx+minx)/2
|
|
midy=(maxy+miny)/2
|
|
|
|
|
|
if self.inputCSYS.get() and self.RengData.image == None:
|
|
xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
|
|
else:
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
|
|
if (self.HomeUR.get()):
|
|
XlineShift = maxx - self.laserX - (xmax-xmin)
|
|
else:
|
|
XlineShift = self.laserX
|
|
YlineShift = self.laserY
|
|
|
|
if min((xmax-xmin),(ymax-ymin)) > 0 and self.zoom2image.get():
|
|
self.PlotScale = max((xmax-xmin)/(cszw-buff), (ymax-ymin)/(cszh-buff))
|
|
x_lft = minx / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2
|
|
x_rgt = maxx / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2
|
|
y_bot = -miny / self.PlotScale + self.laserY / self.PlotScale + (cszh-(ymax-ymin)/self.PlotScale)/2
|
|
y_top = -maxy / self.PlotScale + self.laserY / self.PlotScale + (cszh-(ymax-ymin)/self.PlotScale)/2
|
|
self.segID.append( self.PreviewCanvas.create_rectangle(
|
|
x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) )
|
|
else:
|
|
self.PlotScale = max((maxx-minx)/(cszw-buff), (maxy-miny)/(cszh-buff))
|
|
x_lft = cszw/2 + (minx-midx) / self.PlotScale
|
|
x_rgt = cszw/2 + (maxx-midx) / self.PlotScale
|
|
y_bot = cszh/2 + (maxy-midy) / self.PlotScale
|
|
y_top = cszh/2 + (miny-midy) / self.PlotScale
|
|
self.segID.append( self.PreviewCanvas.create_rectangle(
|
|
x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) )
|
|
|
|
######################################
|
|
### Plot Raster Image ###
|
|
######################################
|
|
if self.RengData.image != None:
|
|
if self.include_Reng.get():
|
|
try:
|
|
new_SCALE = (1.0/self.PlotScale)/self.input_dpi
|
|
if new_SCALE != self.SCALE:
|
|
self.SCALE = new_SCALE
|
|
nw=int(self.SCALE*self.wim)
|
|
nh=int(self.SCALE*self.him)
|
|
|
|
plot_im = self.RengData.image.convert("L")
|
|
## if self.unsharp_flag.get():
|
|
## from PIL import ImageFilter
|
|
## filter = ImageFilter.UnsharpMask()
|
|
## filter.radius = float(self.unsharp_r.get())
|
|
## filter.percent = int(float(self.unsharp_p.get()))
|
|
## filter.threshold = int(float(self.unsharp_t.get()))
|
|
## plot_im = plot_im.filter(filter)
|
|
|
|
if self.negate.get():
|
|
plot_im = ImageOps.invert(plot_im)
|
|
|
|
if self.halftone.get() == False:
|
|
plot_im = plot_im.point(lambda x: 0 if x<128 else 255, '1')
|
|
plot_im = plot_im.convert("L")
|
|
|
|
if self.mirror.get():
|
|
plot_im = ImageOps.mirror(plot_im)
|
|
|
|
if self.rotate.get():
|
|
plot_im = plot_im.rotate(90,expand=True)
|
|
nh=int(self.SCALE*self.wim)
|
|
nw=int(self.SCALE*self.him)
|
|
|
|
try:
|
|
self.UI_image = ImageTk.PhotoImage(plot_im.resize((nw,nh), Image.ANTIALIAS))
|
|
except:
|
|
debug_message("Imaging_Free Used.")
|
|
self.UI_image = self.Imaging_Free(plot_im.resize((nw,nh), Image.ANTIALIAS))
|
|
except:
|
|
self.SCALE = 1
|
|
debug_message(traceback.format_exc())
|
|
|
|
self.Plot_Raster(self.laserX+.001, self.laserY-.001, x_lft,y_top,self.PlotScale,im=self.UI_image)
|
|
else:
|
|
self.UI_image = None
|
|
|
|
|
|
######################################
|
|
### Plot Reng Coords ###
|
|
######################################
|
|
if self.include_Rpth.get() and self.RengData.ecoords!=[] and self.fastPlot.get() == False:
|
|
loop_old = -1
|
|
|
|
#####
|
|
Xscale = 1/float(self.LaserXscale.get())
|
|
Yscale = 1/float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = 1/float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
######
|
|
|
|
for line in self.RengData.ecoords:
|
|
XY = line
|
|
x1 = XY[0]*Xscale
|
|
y1 = XY[1]*Yscale-ymax
|
|
loop = XY[2]
|
|
color = "black"
|
|
# check and see if we need to move to a new discontinuous start point
|
|
if (loop == loop_old):
|
|
self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, color)
|
|
loop_old = loop
|
|
xold=x1
|
|
yold=y1
|
|
|
|
|
|
######################################
|
|
### Plot Veng Coords ###
|
|
######################################
|
|
if self.include_Veng.get() and self.fastPlot.get() == False:
|
|
loop_old = -1
|
|
|
|
|
|
plot_coords = self.VengData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
plot_coords = self.mirror_rotate_vector_coords(plot_coords)
|
|
|
|
for line in plot_coords:
|
|
XY = line
|
|
x1 = (XY[0]-xmin)
|
|
y1 = (XY[1]-ymax)
|
|
loop = XY[2]
|
|
# check and see if we need to move to a new discontinuous start point
|
|
if (loop == loop_old):
|
|
self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "blue")
|
|
loop_old = loop
|
|
xold=x1
|
|
yold=y1
|
|
|
|
######################################
|
|
### Plot Vcut Coords ###
|
|
######################################
|
|
if self.include_Vcut.get() and self.fastPlot.get() == False:
|
|
loop_old = -1
|
|
|
|
plot_coords = self.VcutData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
plot_coords = self.mirror_rotate_vector_coords(plot_coords)
|
|
|
|
for line in plot_coords:
|
|
XY = line
|
|
x1 = (XY[0]-xmin)
|
|
y1 = (XY[1]-ymax)
|
|
loop = XY[2]
|
|
# check and see if we need to move to a new discontinuous start point
|
|
if (loop == loop_old):
|
|
self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "red")
|
|
loop_old = loop
|
|
xold=x1
|
|
yold=y1
|
|
|
|
######################################
|
|
### Plot Gcode Coords ###
|
|
######################################
|
|
if self.include_Gcde.get() and self.fastPlot.get() == False:
|
|
loop_old = -1
|
|
scale=1
|
|
|
|
plot_coords = self.GcodeData.ecoords
|
|
if self.mirror.get() or self.rotate.get():
|
|
plot_coords = self.mirror_rotate_vector_coords(plot_coords)
|
|
|
|
for line in plot_coords:
|
|
XY = line
|
|
x1 = (XY[0]-xmin)*scale
|
|
y1 = (XY[1]-ymax)*scale
|
|
|
|
loop = XY[2]
|
|
# check and see if we need to move to a new discontinuous start point
|
|
if (loop == loop_old):
|
|
self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "white")
|
|
loop_old = loop
|
|
xold=x1
|
|
yold=y1
|
|
|
|
|
|
######################################
|
|
### Plot Trace Coords ###
|
|
######################################
|
|
if self.trace_window.winfo_exists() and self.fastPlot.get() == False: # or DEBUG:
|
|
#####
|
|
Xscale = 1/float(self.LaserXscale.get())
|
|
Yscale = 1/float(self.LaserYscale.get())
|
|
if self.rotary.get():
|
|
Rscale = 1/float(self.LaserRscale.get())
|
|
Yscale = Yscale*Rscale
|
|
######
|
|
trace_coords = self.make_trace_path()
|
|
for i in range(len(trace_coords)):
|
|
trace_coords[i]=[trace_coords[i][0]*Xscale,trace_coords[i][1]*Yscale,trace_coords[i][2]]
|
|
|
|
for line in trace_coords:
|
|
XY = line
|
|
x1 = (XY[0]-xmin)*scale
|
|
y1 = (XY[1]-ymax)*scale
|
|
loop = XY[2]
|
|
# check and see if we need to move to a new discontinuous start point
|
|
if (loop == loop_old):
|
|
green = "#%02x%02x%02x" % (0, 200, 0)
|
|
self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift,
|
|
self.PlotScale, green, thick=2,tag_value=('LaserTag', 'trace'))
|
|
loop_old = loop
|
|
xold=x1
|
|
yold=y1
|
|
|
|
|
|
######################################
|
|
self.refreshTime()
|
|
dot_col = "grey50"
|
|
xoff = self.pos_offset[0]/1000.0
|
|
yoff = self.pos_offset[1]/1000.0
|
|
|
|
if abs(self.pos_offset[0])+abs(self.pos_offset[1]) > 0:
|
|
head_offset=True
|
|
else:
|
|
head_offset=False
|
|
|
|
self.Plot_circle(self.laserX+xoff,self.laserY+yoff,x_lft,y_top,self.PlotScale,dot_col,radius=5,cross_hair=head_offset)
|
|
|
|
def Plot_Raster(self, XX, YY, Xleft, Ytop, PlotScale, im):
|
|
if (self.HomeUR.get()):
|
|
maxx = float(self.LaserXsize.get()) / self.units_scale
|
|
xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
|
|
xplt = Xleft + ( maxx-XX-(xmax-xmin) )/PlotScale
|
|
else:
|
|
xplt = Xleft + XX/PlotScale
|
|
|
|
yplt = Ytop - YY/PlotScale
|
|
self.segID.append(
|
|
self.PreviewCanvas.create_image(xplt, yplt, anchor=NW, image=self.UI_image,tags='LaserTag')
|
|
)
|
|
|
|
|
|
def offset_eccords(self,ecoords_in,offset_val):
|
|
if not PYCLIPPER:
|
|
return ecoords_in
|
|
|
|
loop_num = ecoords_in[0][2]
|
|
pco = pyclipper.PyclipperOffset()
|
|
ecoords_out=[]
|
|
pyclip_path = []
|
|
for i in range(0,len(ecoords_in)):
|
|
pyclip_path.append([ecoords_in[i][0]*1000,ecoords_in[i][1]*1000])
|
|
|
|
pco.AddPath(pyclip_path, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
|
|
try:
|
|
plot_coords = pco.Execute(offset_val*1000.0)[0]
|
|
plot_coords.append(plot_coords[0])
|
|
except:
|
|
plot_coords=[]
|
|
|
|
for i in range(0,len(plot_coords)):
|
|
ecoords_out.append([plot_coords[i][0]/1000.0,plot_coords[i][1]/1000.0,loop_num])
|
|
return ecoords_out
|
|
|
|
|
|
def Plot_circle(self, XX, YY, Xleft, Ytop, PlotScale, col, radius=0, cross_hair=False):
|
|
circle_tags = ('LaserTag','LaserDot')
|
|
if (self.HomeUR.get()):
|
|
maxx = float(self.LaserXsize.get()) / self.units_scale
|
|
xplt = Xleft + maxx/PlotScale - XX/PlotScale
|
|
else:
|
|
xplt = Xleft + XX/PlotScale
|
|
yplt = Ytop - YY/PlotScale
|
|
|
|
|
|
if cross_hair:
|
|
radius=radius*2
|
|
leg = int(radius*.707)
|
|
self.segID.append(
|
|
self.PreviewCanvas.create_polygon(
|
|
xplt-radius,
|
|
yplt,
|
|
xplt-leg,
|
|
yplt+leg,
|
|
xplt,
|
|
yplt+radius,
|
|
xplt+leg,
|
|
yplt+leg,
|
|
xplt+radius,
|
|
yplt,
|
|
xplt+leg,
|
|
yplt-leg,
|
|
xplt,
|
|
yplt-radius,
|
|
xplt-leg,
|
|
yplt-leg,
|
|
fill=col, outline=col, width = 1, stipple='gray12',tags=circle_tags ))
|
|
|
|
self.segID.append(
|
|
self.PreviewCanvas.create_line( xplt-radius,
|
|
yplt,
|
|
xplt+radius,
|
|
yplt,
|
|
fill=col, capstyle="round", width = 1, tags=circle_tags ))
|
|
self.segID.append(
|
|
self.PreviewCanvas.create_line( xplt,
|
|
yplt-radius,
|
|
xplt,
|
|
yplt+radius,
|
|
fill=col, capstyle="round", width = 1, tags=circle_tags ))
|
|
else:
|
|
self.segID.append(
|
|
self.PreviewCanvas.create_oval(
|
|
xplt-radius,
|
|
yplt-radius,
|
|
xplt+radius,
|
|
yplt+radius,
|
|
fill=col, outline=col, width = 0, stipple='gray50',tags=circle_tags ))
|
|
|
|
|
|
def Plot_Line(self, XX1, YY1, XX2, YY2, Xleft, Ytop, XlineShift, YlineShift, PlotScale, col, thick=0, tag_value='LaserTag'):
|
|
xplt1 = Xleft + (XX1 + XlineShift )/PlotScale
|
|
xplt2 = Xleft + (XX2 + XlineShift )/PlotScale
|
|
yplt1 = Ytop - (YY1 + YlineShift )/PlotScale
|
|
yplt2 = Ytop - (YY2 + YlineShift )/PlotScale
|
|
|
|
self.segID.append(
|
|
self.PreviewCanvas.create_line( xplt1,
|
|
yplt1,
|
|
xplt2,
|
|
yplt2,
|
|
fill=col, capstyle="round", width = thick, tags=tag_value) )
|
|
|
|
################################################################################
|
|
# Temporary Move Window #
|
|
################################################################################
|
|
def move_head_window_temporary(self,new_pos_offset):
|
|
if self.GUI_Disabled:
|
|
return
|
|
dx_inches = round(new_pos_offset[0]/1000.0,3)
|
|
dy_inches = round(new_pos_offset[1]/1000.0,3)
|
|
Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches,no_size=True)
|
|
|
|
pos_offset_X = round((Xnew-self.laserX)*1000.0)
|
|
pos_offset_Y = round((Ynew-self.laserY)*1000.0)
|
|
new_pos_offset = [pos_offset_X,pos_offset_Y]
|
|
|
|
if self.inputCSYS.get() and self.RengData.image == None:
|
|
new_pos_offset = [0,0]
|
|
xdist = -self.pos_offset[0]
|
|
ydist = -self.pos_offset[1]
|
|
else:
|
|
xdist = -self.pos_offset[0] + new_pos_offset[0]
|
|
ydist = -self.pos_offset[1] + new_pos_offset[1]
|
|
|
|
if self.k40 != None:
|
|
if self.Send_Rapid_Move( xdist,ydist ):
|
|
self.pos_offset = new_pos_offset
|
|
self.menu_View_Refresh()
|
|
else:
|
|
self.pos_offset = new_pos_offset
|
|
self.menu_View_Refresh()
|
|
|
|
################################################################################
|
|
# General Settings Window #
|
|
################################################################################
|
|
def GEN_Settings_Window(self):
|
|
gen_width = 560
|
|
gen_settings = Toplevel(width=gen_width, height=575) #460+75)
|
|
gen_settings.grab_set() # Use grab_set to prevent user input in the main window
|
|
gen_settings.focus_set()
|
|
gen_settings.resizable(0,0)
|
|
gen_settings.title('General Settings')
|
|
gen_settings.iconname("General Settings")
|
|
|
|
D_Yloc = 6
|
|
D_dY = 26
|
|
xd_label_L = 12
|
|
|
|
w_label=150
|
|
w_entry=40
|
|
w_units=45
|
|
xd_entry_L=xd_label_L+w_label+10
|
|
xd_units_L=xd_entry_L+w_entry+5
|
|
sep_border=10
|
|
|
|
#Radio Button
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Units = Label(gen_settings,text="Units")
|
|
self.Label_Units.place(x=xd_label_L, y=D_Yloc, width=113, height=21)
|
|
self.Radio_Units_IN = Radiobutton(gen_settings,text="inch", value="in",
|
|
width="100", anchor=W)
|
|
self.Radio_Units_IN.place(x=w_label+22, y=D_Yloc, width=75, height=23)
|
|
self.Radio_Units_IN.configure(variable=self.units, command=self.Entry_units_var_Callback )
|
|
self.Radio_Units_MM = Radiobutton(gen_settings,text="mm", value="mm",
|
|
width="100", anchor=W)
|
|
self.Radio_Units_MM.place(x=w_label+110, y=D_Yloc, width=75, height=23)
|
|
self.Radio_Units_MM.configure(variable=self.units, command=self.Entry_units_var_Callback )
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_init_home = Label(gen_settings,text="Home Upon Initialize")
|
|
self.Label_init_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_init_home = Checkbutton(gen_settings,text="", anchor=W)
|
|
self.Checkbutton_init_home.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_init_home.configure(variable=self.init_home)
|
|
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_post_home = Label(gen_settings,text="After Job Finishes:")
|
|
self.Label_post_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
|
|
Xoption_width = 120
|
|
Xoption_col1 = xd_entry_L
|
|
Xoption_col2 = xd_entry_L+Xoption_width
|
|
Xoption_col3 = xd_entry_L+Xoption_width*2
|
|
|
|
self.Checkbutton_post_home = Checkbutton(gen_settings,text="Unlock Rail", anchor=W)
|
|
self.Checkbutton_post_home.place(x=Xoption_col1, y=D_Yloc, width=Xoption_width, height=23)
|
|
self.Checkbutton_post_home.configure(variable=self.post_home)
|
|
|
|
self.Checkbutton_post_beep = Checkbutton(gen_settings,text="Beep", anchor=W)
|
|
self.Checkbutton_post_beep.place(x=Xoption_col2, y=D_Yloc, width=Xoption_width, height=23)
|
|
self.Checkbutton_post_beep.configure(variable=self.post_beep)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Checkbutton_post_disp = Checkbutton(gen_settings,text="Popup Report", anchor=W)
|
|
self.Checkbutton_post_disp.place(x=Xoption_col1, y=D_Yloc, width=Xoption_width, height=23)
|
|
self.Checkbutton_post_disp.configure(variable=self.post_disp)
|
|
|
|
self.Checkbutton_post_exec = Checkbutton(gen_settings,text="Run Batch File:", anchor=W, command=self.Set_Input_States_BATCH)
|
|
self.Checkbutton_post_exec.place(x=Xoption_col2, y=D_Yloc, width=Xoption_width, height=23)
|
|
self.Checkbutton_post_exec.configure(variable=self.post_exec)
|
|
|
|
|
|
self.Entry_Batch_Path = Entry(gen_settings)
|
|
self.Entry_Batch_Path.place(x=Xoption_col3, y=D_Yloc, width=Xoption_width, height=23)
|
|
self.Entry_Batch_Path.configure(textvariable=self.batch_path)
|
|
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Preprocess_CRC = Label(gen_settings,text="Preprocess CRC Data")
|
|
self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Preprocess_CRC = Checkbutton(gen_settings,text="", anchor=W)
|
|
self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Reduce_Memory = Label(gen_settings,text="Reduce Memory Use")
|
|
self.Label_Reduce_Memory.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Reduce_Memory = Checkbutton(gen_settings,text="(needed for large designs or low memory computers)", anchor=W)
|
|
self.Checkbutton_Reduce_Memory.place(x=xd_entry_L, y=D_Yloc, width=350, height=23)
|
|
self.Checkbutton_Reduce_Memory.configure(variable=self.reduced_mem)
|
|
self.reduced_mem.trace_variable("w", self.Reduced_Memory_Callback)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Wait = Label(gen_settings,text="Wait for Laser to Finish")
|
|
self.Label_Wait.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Wait = Checkbutton(gen_settings,text="(after all data has been sent over USB)", anchor=W)
|
|
self.Checkbutton_Wait.place(x=xd_entry_L, y=D_Yloc, width=350, height=23)
|
|
self.Checkbutton_Wait.configure(variable=self.wait)
|
|
#self.wait.trace_variable("w", self.Wait_Callback)
|
|
|
|
#D_Yloc=D_Yloc+D_dY
|
|
#self.Label_Timeout = Label(gen_settings,text="USB Timeout")
|
|
#self.Label_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
#self.Label_Timeout_u = Label(gen_settings,text="ms", anchor=W)
|
|
#self.Label_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
#self.Entry_Timeout = Entry(gen_settings,width="15")
|
|
#self.Entry_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
#self.Entry_Timeout.configure(textvariable=self.t_timeout)
|
|
#self.t_timeout.trace_variable("w", self.Entry_Timeout_Callback)
|
|
#self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(),2)
|
|
|
|
#D_Yloc=D_Yloc+D_dY
|
|
#self.Label_N_Timeouts = Label(gen_settings,text="Number of Timeouts")
|
|
#self.Label_N_Timeouts.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
#self.Entry_N_Timeouts = Entry(gen_settings,width="15")
|
|
#self.Entry_N_Timeouts.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
#self.Entry_N_Timeouts.configure(textvariable=self.n_timeouts)
|
|
#self.n_timeouts.trace_variable("w", self.Entry_N_Timeouts_Callback)
|
|
#self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY*1.25
|
|
self.gen_separator1 = Frame(gen_settings, height=2, bd=1, relief=SUNKEN)
|
|
self.gen_separator1.place(x=xd_label_L, y=D_Yloc,width=gen_width-40, height=2)
|
|
|
|
D_Yloc=D_Yloc+D_dY*.25
|
|
self.Label_Inkscape_title = Label(gen_settings,text="Inkscape Options")
|
|
self.Label_Inkscape_title.place(x=xd_label_L, y=D_Yloc, width=gen_width-40, height=21)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
font_entry_width=215
|
|
self.Label_Inkscape_Path = Label(gen_settings,text="Inkscape Executable")
|
|
self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Entry_Inkscape_Path = Entry(gen_settings,width="15")
|
|
self.Entry_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=font_entry_width, height=23)
|
|
self.Entry_Inkscape_Path.configure(textvariable=self.inkscape_path)
|
|
self.Entry_Inkscape_Path.bind('<FocusIn>', self.Inkscape_Path_Message)
|
|
self.Inkscape_Path = Button(gen_settings,text="Find Inkscape")
|
|
self.Inkscape_Path.place(x=xd_entry_L+font_entry_width+10, y=D_Yloc, width=110, height=23)
|
|
self.Inkscape_Path.bind("<ButtonRelease-1>", self.Inkscape_Path_Click)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Ink_Timeout = Label(gen_settings,text="Inkscape Timeout")
|
|
self.Label_Ink_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Label_Ink_Timeout_u = Label(gen_settings,text="minutes", anchor=W)
|
|
self.Label_Ink_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units*2, height=21)
|
|
self.Entry_Ink_Timeout = Entry(gen_settings,width="15")
|
|
self.Entry_Ink_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Ink_Timeout.configure(textvariable=self.ink_timeout)
|
|
self.ink_timeout.trace_variable("w", self.Entry_Ink_Timeout_Callback)
|
|
self.entry_set(self.Entry_Ink_Timeout,self.Entry_Ink_Timeout_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY*1.25
|
|
self.gen_separator2 = Frame(gen_settings, height=2, bd=1, relief=SUNKEN)
|
|
self.gen_separator2.place(x=xd_label_L, y=D_Yloc,width=gen_width-40, height=2)
|
|
|
|
D_Yloc=D_Yloc+D_dY*.5
|
|
self.Label_no_com = Label(gen_settings,text="Home in Upper Right")
|
|
self.Label_no_com.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_no_com = Checkbutton(gen_settings,text="", anchor=W)
|
|
self.Checkbutton_no_com.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_no_com.configure(variable=self.HomeUR)
|
|
self.HomeUR.trace_variable("w",self.menu_View_Refresh_Callback)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Board_Name = Label(gen_settings,text="Board Name", anchor=CENTER )
|
|
self.Board_Name_OptionMenu = OptionMenu(gen_settings, self.board_name,
|
|
"LASER-M2",
|
|
"LASER-M1",
|
|
"LASER-M",
|
|
"LASER-B2",
|
|
"LASER-B1",
|
|
"LASER-B",
|
|
"LASER-A")
|
|
self.Label_Board_Name.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Board_Name_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry*3, height=23)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_Area_Width = Label(gen_settings,text="Laser Area Width")
|
|
self.Label_Laser_Area_Width.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Label_Laser_Area_Width_u = Label(gen_settings,textvariable=self.units, anchor=W)
|
|
self.Label_Laser_Area_Width_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
self.Entry_Laser_Area_Width = Entry(gen_settings,width="15")
|
|
self.Entry_Laser_Area_Width.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Laser_Area_Width.configure(textvariable=self.LaserXsize)
|
|
self.LaserXsize.trace_variable("w", self.Entry_Laser_Area_Width_Callback)
|
|
self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_Area_Height = Label(gen_settings,text="Laser Area Height")
|
|
self.Label_Laser_Area_Height.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Label_Laser_Area_Height_u = Label(gen_settings,textvariable=self.units, anchor=W)
|
|
self.Label_Laser_Area_Height_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
self.Entry_Laser_Area_Height = Entry(gen_settings,width="15")
|
|
self.Entry_Laser_Area_Height.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Laser_Area_Height.configure(textvariable=self.LaserYsize)
|
|
self.LaserYsize.trace_variable("w", self.Entry_Laser_Area_Height_Callback)
|
|
self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_X_Scale = Label(gen_settings,text="X Scale Factor")
|
|
self.Label_Laser_X_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Entry_Laser_X_Scale = Entry(gen_settings,width="15")
|
|
self.Entry_Laser_X_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Laser_X_Scale.configure(textvariable=self.LaserXscale)
|
|
self.LaserXscale.trace_variable("w", self.Entry_Laser_X_Scale_Callback)
|
|
self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_Y_Scale = Label(gen_settings,text="Y Scale Factor")
|
|
self.Label_Laser_Y_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Entry_Laser_Y_Scale = Entry(gen_settings,width="15")
|
|
self.Entry_Laser_Y_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Laser_Y_Scale.configure(textvariable=self.LaserYscale)
|
|
self.LaserYscale.trace_variable("w", self.Entry_Laser_Y_Scale_Callback)
|
|
self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY+10
|
|
self.Label_SaveConfig = Label(gen_settings,text="Configuration File")
|
|
self.Label_SaveConfig.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
|
|
self.GEN_SaveConfig = Button(gen_settings,text="Save")
|
|
self.GEN_SaveConfig.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=21, anchor="nw")
|
|
self.GEN_SaveConfig.bind("<ButtonRelease-1>", self.Write_Config_File)
|
|
|
|
## Buttons ##
|
|
gen_settings.update_idletasks()
|
|
Ybut=int(gen_settings.winfo_height())-30
|
|
Xbut=int(gen_settings.winfo_width()/2)
|
|
|
|
self.GEN_Close = Button(gen_settings,text="Close")
|
|
self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
|
|
self.GEN_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
|
|
|
|
self.Set_Input_States_BATCH()
|
|
|
|
################################################################################
|
|
# Raster Settings Window #
|
|
################################################################################
|
|
def RASTER_Settings_Window(self):
|
|
Wset=425+280
|
|
Hset=330 #260
|
|
raster_settings = Toplevel(width=Wset, height=Hset)
|
|
raster_settings.grab_set() # Use grab_set to prevent user input in the main window
|
|
raster_settings.focus_set()
|
|
raster_settings.resizable(0,0)
|
|
raster_settings.title('Raster Settings')
|
|
raster_settings.iconname("Raster Settings")
|
|
|
|
D_Yloc = 6
|
|
D_dY = 24
|
|
xd_label_L = 12
|
|
|
|
w_label=155
|
|
w_entry=60
|
|
w_units=35
|
|
xd_entry_L=xd_label_L+w_label+10
|
|
xd_units_L=xd_entry_L+w_entry+5
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Rstep = Label(raster_settings,text="Scanline Step", anchor=CENTER )
|
|
self.Label_Rstep.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Label_Rstep_u = Label(raster_settings,text="in", anchor=W)
|
|
self.Label_Rstep_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
self.Entry_Rstep = Entry(raster_settings,width="15")
|
|
self.Entry_Rstep.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Rstep.configure(textvariable=self.rast_step)
|
|
self.rast_step.trace_variable("w", self.Entry_Rstep_Callback)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_EngraveUP = Label(raster_settings,text="Engrave Bottom Up")
|
|
self.Checkbutton_EngraveUP = Checkbutton(raster_settings,text=" ", anchor=W)
|
|
self.Checkbutton_EngraveUP.configure(variable=self.engraveUP)
|
|
self.Label_EngraveUP.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_EngraveUP.place(x=w_label+22, y=D_Yloc, width=75, height=23)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Halftone = Label(raster_settings,text="Halftone (Dither)")
|
|
self.Label_Halftone.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Halftone = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_RASTER)
|
|
self.Checkbutton_Halftone.place(x=w_label+22, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_Halftone.configure(variable=self.halftone)
|
|
self.halftone.trace_variable("w", self.menu_View_Refresh_Callback)
|
|
|
|
############
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Halftone_DPI = Label(raster_settings,text="Halftone Resolution", anchor=CENTER )
|
|
|
|
if self.reduced_mem.get():
|
|
if self.ht_size == "1000": self.ht_size = "500"
|
|
if self.ht_size == "333": self.ht_size = "500"
|
|
if self.ht_size == "200": self.ht_size = "250"
|
|
if self.ht_size == "143": self.ht_size = "167"
|
|
self.Halftone_DPI_OptionMenu = OptionMenu(raster_settings, self.ht_size,
|
|
"500",
|
|
"250",
|
|
"167",
|
|
"125")
|
|
else:
|
|
self.Halftone_DPI_OptionMenu = OptionMenu(raster_settings, self.ht_size,
|
|
"1000",
|
|
"500",
|
|
"333",
|
|
"250",
|
|
"200",
|
|
"167",
|
|
"143",
|
|
"125")
|
|
|
|
self.Label_Halftone_DPI.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Halftone_DPI_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry+30, height=23)
|
|
|
|
self.Label_Halftone_u = Label(raster_settings,text="dpi", anchor=W)
|
|
self.Label_Halftone_u.place(x=xd_units_L+30, y=D_Yloc, width=w_units, height=21)
|
|
|
|
############
|
|
D_Yloc=D_Yloc+D_dY+5
|
|
self.Label_bezier_M1 = Label(raster_settings,
|
|
text="Slope, Black (%.1f)"%(self.bezier_M1_default),
|
|
anchor=CENTER )
|
|
self.bezier_M1_Slider = Scale(raster_settings, from_=1, to=50, resolution=0.1, \
|
|
orient=HORIZONTAL, variable=self.bezier_M1)
|
|
self.bezier_M1_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
|
|
D_Yloc=D_Yloc+21
|
|
self.Label_bezier_M1.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.bezier_M1.trace_variable("w", self.bezier_M1_Callback)
|
|
|
|
D_Yloc=D_Yloc+D_dY-8
|
|
self.Label_bezier_M2 = Label(raster_settings,
|
|
text="Slope, White (%.2f)"%(self.bezier_M2_default),
|
|
anchor=CENTER )
|
|
self.bezier_M2_Slider = Scale(raster_settings, from_=0.0, to=1, \
|
|
orient=HORIZONTAL,resolution=0.01, variable=self.bezier_M2)
|
|
self.bezier_M2_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
|
|
D_Yloc=D_Yloc+21
|
|
self.Label_bezier_M2.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.bezier_M2.trace_variable("w", self.bezier_M2_Callback)
|
|
|
|
D_Yloc=D_Yloc+D_dY-8
|
|
self.Label_bezier_weight = Label(raster_settings,
|
|
text="Transition (%.1f)"%(self.bezier_M1_default),
|
|
anchor=CENTER )
|
|
self.bezier_weight_Slider = Scale(raster_settings, from_=0, to=10, resolution=0.1, \
|
|
orient=HORIZONTAL, variable=self.bezier_weight)
|
|
self.bezier_weight_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
|
|
D_Yloc=D_Yloc+21
|
|
self.Label_bezier_weight.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.bezier_weight.trace_variable("w", self.bezier_weight_Callback)
|
|
|
|
## show_unsharp = False
|
|
## if DEBUG and show_unsharp:
|
|
## D_Yloc=D_Yloc+D_dY
|
|
## self.Label_UnsharpMask = Label(raster_settings,text="Unsharp Mask")
|
|
## self.Label_UnsharpMask.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
## self.Checkbutton_UnsharpMask = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_Unsharp)
|
|
## self.Checkbutton_UnsharpMask.place(x=w_label+22, y=D_Yloc, width=75, height=23)
|
|
## self.Checkbutton_UnsharpMask.configure(variable=self.unsharp_flag)
|
|
## self.unsharp_flag.trace_variable("w", self.menu_View_Refresh_Callback)
|
|
##
|
|
## D_Yloc=D_Yloc+D_dY
|
|
## self.Label_Unsharp_Radius = Label(raster_settings,text="Unsharp Mask Radius", anchor=CENTER )
|
|
## self.Label_Unsharp_Radius.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
## self.Label_Unsharp_Radius_u = Label(raster_settings,text="Pixels", anchor=W)
|
|
## self.Label_Unsharp_Radius_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
## self.Entry_Unsharp_Radius = Entry(raster_settings,width="15")
|
|
## self.Entry_Unsharp_Radius.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
## self.Entry_Unsharp_Radius.configure(textvariable=self.unsharp_r)
|
|
## self.unsharp_r.trace_variable("w", self.Entry_Unsharp_Radius_Callback)
|
|
##
|
|
## D_Yloc=D_Yloc+D_dY
|
|
## self.Label_Unsharp_Percent = Label(raster_settings,text="Unsharp Mask Percent", anchor=CENTER )
|
|
## self.Label_Unsharp_Percent.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
## self.Label_Unsharp_Percent_u = Label(raster_settings,text="%", anchor=W)
|
|
## self.Label_Unsharp_Percent_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
## self.Entry_Unsharp_Percent = Entry(raster_settings,width="15")
|
|
## self.Entry_Unsharp_Percent.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
## self.Entry_Unsharp_Percent.configure(textvariable=self.unsharp_p)
|
|
## self.unsharp_p.trace_variable("w", self.Entry_Unsharp_Percent_Callback)
|
|
##
|
|
## D_Yloc=D_Yloc+D_dY
|
|
## self.Label_Unsharp_Threshold = Label(raster_settings,text="Unsharp Mask Threshold", anchor=CENTER )
|
|
## self.Label_Unsharp_Threshold.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
## #self.Label_Unsharp_Threshold_u = Label(raster_settings,text="Pixels", anchor=W)
|
|
## #self.Label_Unsharp_Threshold_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
## self.Entry_Unsharp_Threshold = Entry(raster_settings,width="15")
|
|
## self.Entry_Unsharp_Threshold.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
## self.Entry_Unsharp_Threshold.configure(textvariable=self.unsharp_t)
|
|
## self.unsharp_t.trace_variable("w", self.Entry_Unsharp_Threshold_Callback)
|
|
|
|
# Bezier Canvas
|
|
self.Bezier_frame = Frame(raster_settings, bd=1, relief=SUNKEN)
|
|
self.Bezier_frame.place(x=Wset-280, y=10, height=265, width=265)
|
|
self.BezierCanvas = Canvas(self.Bezier_frame, background="white")
|
|
self.BezierCanvas.pack(side=LEFT, fill=BOTH, expand=1)
|
|
self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="grey75", capstyle="round", width = 2, tags='perm')
|
|
|
|
|
|
M1 = self.bezier_M1_default
|
|
M2 = self.bezier_M2_default
|
|
w = self.bezier_weight_default
|
|
num = 10
|
|
x,y = self.generate_bezier(M1,M2,w,n=num)
|
|
for i in range(0,num):
|
|
self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="grey85", stipple='gray25',\
|
|
capstyle="round", width = 2, tags='perm')
|
|
|
|
|
|
## Buttons ##
|
|
raster_settings.update_idletasks()
|
|
Ybut=int(raster_settings.winfo_height())-30
|
|
Xbut=int(raster_settings.winfo_width()/2)
|
|
|
|
self.RASTER_Close = Button(raster_settings,text="Close")
|
|
self.RASTER_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
|
|
self.RASTER_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
|
|
|
|
self.bezier_M1_Callback()
|
|
self.Set_Input_States_RASTER()
|
|
#if DEBUG and show_unsharp:
|
|
# self.Set_Input_States_Unsharp()
|
|
|
|
|
|
################################################################################
|
|
# Rotary Settings Window #
|
|
################################################################################
|
|
def ROTARY_Settings_Window(self):
|
|
rotary_settings = Toplevel(width=350, height=175)
|
|
rotary_settings.grab_set() # Use grab_set to prevent user input in the main window
|
|
rotary_settings.focus_set()
|
|
rotary_settings.resizable(0,0)
|
|
rotary_settings.title('Rotary Settings')
|
|
rotary_settings.iconname("Rotary Settings")
|
|
|
|
D_Yloc = 6
|
|
D_dY = 30
|
|
xd_label_L = 12
|
|
|
|
w_label=180
|
|
w_entry=40
|
|
w_units=45
|
|
xd_entry_L=xd_label_L+w_label+10
|
|
xd_units_L=xd_entry_L+w_entry+5
|
|
sep_border=10
|
|
|
|
|
|
D_Yloc=D_Yloc+D_dY-15
|
|
self.Label_Rotary_Enable = Label(rotary_settings,text="Use Rotary Settings")
|
|
self.Label_Rotary_Enable.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Rotary_Enable = Checkbutton(rotary_settings,text="", anchor=W, command=self.Set_Input_States_Rotary)
|
|
self.Checkbutton_Rotary_Enable.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_Rotary_Enable.configure(variable=self.rotary)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_R_Scale = Label(rotary_settings,text="Rotary Scale Factor (Y axis)")
|
|
self.Label_Laser_R_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Entry_Laser_R_Scale = Entry(rotary_settings,width="15")
|
|
self.Entry_Laser_R_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Laser_R_Scale.configure(textvariable=self.LaserRscale)
|
|
self.LaserRscale.trace_variable("w", self.Entry_Laser_R_Scale_Callback)
|
|
self.entry_set(self.Entry_Laser_R_Scale,self.Entry_Laser_R_Scale_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_Rapid_Feed = Label(rotary_settings,text="Rapid Speed (default=0)")
|
|
self.Label_Laser_Rapid_Feed.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Label_Laser_Rapid_Feed_u = Label(rotary_settings,textvariable=self.funits, anchor=W)
|
|
self.Label_Laser_Rapid_Feed_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
self.Entry_Laser_Rapid_Feed = Entry(rotary_settings,width="15")
|
|
self.Entry_Laser_Rapid_Feed.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_Laser_Rapid_Feed.configure(textvariable=self.rapid_feed)
|
|
self.rapid_feed.trace_variable("w", self.Entry_Laser_Rapid_Feed_Callback)
|
|
self.entry_set(self.Entry_Laser_Rapid_Feed,self.Entry_Laser_Rapid_Feed_Check(),2)
|
|
|
|
## Buttons ##
|
|
rotary_settings.update_idletasks()
|
|
Ybut=int(rotary_settings.winfo_height())-30
|
|
Xbut=int(rotary_settings.winfo_width()/2)
|
|
|
|
self.GEN_Close = Button(rotary_settings,text="Close")
|
|
self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
|
|
self.GEN_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
|
|
|
|
self.Set_Input_States_Rotary()
|
|
|
|
################################################################################
|
|
# Toggle Fullscreen #
|
|
################################################################################
|
|
|
|
def Toggle_Fullscreen(self, dummy=None):
|
|
if (root.attributes('-fullscreen')):
|
|
root.attributes('-fullscreen', False)
|
|
else:
|
|
root.attributes('-fullscreen', True)
|
|
|
|
################################################################################
|
|
# Trace Send Window #
|
|
################################################################################
|
|
|
|
def TRACE_Settings_Window(self, dummy=None):
|
|
if self.GUI_Disabled:
|
|
return
|
|
trace_window = Toplevel(width=350, height=180)
|
|
self.trace_window=trace_window
|
|
trace_window.grab_set() # Use grab_set to prevent user input in the main window during calculations
|
|
trace_window.resizable(0,0)
|
|
trace_window.title('Trace Boundary')
|
|
trace_window.iconname("Trace Boundary")
|
|
|
|
def Close_Click():
|
|
win_id=self.grab_current()
|
|
self.PreviewCanvas.delete('trace')
|
|
win_id.destroy()
|
|
|
|
def Close_and_Send_Click():
|
|
win_id=self.grab_current()
|
|
self.PreviewCanvas.delete('trace')
|
|
win_id.destroy()
|
|
self.Trace_Eng()
|
|
|
|
D_Yloc = 0
|
|
D_dY = 28
|
|
xd_label_L = 12
|
|
|
|
w_label=225
|
|
w_entry=40
|
|
w_units=50
|
|
xd_entry_L=xd_label_L+w_label+10
|
|
xd_units_L=xd_entry_L+w_entry+5
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Laser_Trace = Label(trace_window,text="Laser 'On' During Trace")
|
|
self.Label_Laser_Trace.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Laser_Trace = Checkbutton(trace_window,text="", anchor=W)
|
|
self.Checkbutton_Laser_Trace.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_Laser_Trace.configure(variable=self.trace_w_laser)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Trace_Gap = Label(trace_window,text="Gap Between Design and Trace")
|
|
self.Label_Trace_Gap.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Entry_Trace_Gap = Entry(trace_window,width="15")
|
|
self.Entry_Trace_Gap.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Label_Trace_Gap_u = Label(trace_window,textvariable=self.units, anchor=W)
|
|
self.Label_Trace_Gap_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
self.Entry_Trace_Gap.configure(textvariable=self.trace_gap,justify='center')
|
|
self.trace_gap.trace_variable("w", self.Entry_Trace_Gap_Callback)
|
|
self.entry_set(self.Entry_Trace_Gap,self.Entry_Trace_Gap_Check(),2)
|
|
if not PYCLIPPER:
|
|
self.Label_Trace_Gap.configure(state="disabled")
|
|
self.Label_Trace_Gap_u.configure(state="disabled")
|
|
self.Entry_Trace_Gap.configure(state="disabled")
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Trace_Button = Button(trace_window,text="Trace Boundary With Laser Head",command=Close_and_Send_Click)
|
|
self.Trace_Button.place(x=xd_label_L, y=D_Yloc, width=w_label, height=23)
|
|
|
|
self.Entry_Trace_Speed = Entry(trace_window,width="15")
|
|
self.Entry_Trace_Speed.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
green = "#%02x%02x%02x" % (0, 200, 0)
|
|
self.Entry_Trace_Speed.configure(textvariable=self.trace_speed,justify='center',fg=green)
|
|
self.trace_speed.trace_variable("w", self.Entry_Trace_Speed_Callback)
|
|
self.entry_set(self.Entry_Trace_Speed,self.Entry_Trace_Speed_Check(),2)
|
|
self.Label_Trace_Speed_u = Label(trace_window,textvariable=self.funits, anchor=W)
|
|
self.Label_Trace_Speed_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
|
|
|
|
|
|
## Buttons ##
|
|
trace_window.update_idletasks()
|
|
Ybut=int(trace_window.winfo_height())-30
|
|
Xbut=int(trace_window.winfo_width()/2)
|
|
|
|
self.Trace_Close = Button(trace_window,text="Cancel",command=Close_Click)
|
|
self.Trace_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
|
|
################################################################################
|
|
|
|
################################################################################
|
|
# EGV Send Window #
|
|
################################################################################
|
|
def EGV_Send_Window(self,EGV_filename):
|
|
|
|
egv_send = Toplevel(width=400, height=180)
|
|
egv_send.grab_set() # Use grab_set to prevent user input in the main window during calculations
|
|
egv_send.resizable(0,0)
|
|
egv_send.title('EGV Send')
|
|
egv_send.iconname("EGV Send")
|
|
|
|
D_Yloc = 0
|
|
D_dY = 28
|
|
xd_label_L = 12
|
|
|
|
w_label=150
|
|
w_entry=40
|
|
w_units=35
|
|
xd_entry_L=xd_label_L+w_label+10
|
|
xd_units_L=xd_entry_L+w_entry+5
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_Preprocess_CRC = Label(egv_send,text="Preprocess CRC Data")
|
|
self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Checkbutton_Preprocess_CRC = Checkbutton(egv_send,text="", anchor=W)
|
|
self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
|
|
self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
self.Label_N_EGV_Passes = Label(egv_send,text="Number of EGV Passes")
|
|
self.Label_N_EGV_Passes.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
self.Entry_N_EGV_Passes = Entry(egv_send,width="15")
|
|
self.Entry_N_EGV_Passes.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
|
|
self.Entry_N_EGV_Passes.configure(textvariable=self.n_egv_passes)
|
|
self.n_egv_passes.trace_variable("w", self.Entry_N_EGV_Passes_Callback)
|
|
self.entry_set(self.Entry_N_EGV_Passes,self.Entry_N_EGV_Passes_Check(),2)
|
|
|
|
D_Yloc=D_Yloc+D_dY
|
|
font_entry_width=215
|
|
self.Label_Inkscape_Path = Label(egv_send,text="EGV File:")
|
|
self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
|
|
|
|
EGV_Name = os.path.basename(EGV_filename)
|
|
self.Label_Inkscape_Path = Label(egv_send,text=EGV_Name,anchor="w") #,bg="yellow")
|
|
self.Label_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=200, height=21,anchor="nw")
|
|
|
|
## Buttons ##
|
|
egv_send.update_idletasks()
|
|
Ybut=int(egv_send.winfo_height())-30
|
|
Xbut=int(egv_send.winfo_width()/2)
|
|
|
|
self.EGV_Close = Button(egv_send,text="Cancel")
|
|
self.EGV_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="e")
|
|
self.EGV_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
|
|
|
|
def Close_and_Send_Click():
|
|
win_id=self.grab_current()
|
|
win_id.destroy()
|
|
self.Open_EGV(EGV_filename, n_passes=int( float(self.n_egv_passes.get()) ))
|
|
|
|
self.EGV_Send = Button(egv_send,text="Send EGV Data",command=Close_and_Send_Click)
|
|
self.EGV_Send.place(x=Xbut, y=Ybut, width=130, height=30, anchor="w")
|
|
################################################################################
|
|
|
|
|
|
################################################################################
|
|
# Function for outputting messages to different locations #
|
|
# depending on what options are enabled #
|
|
################################################################################
|
|
def fmessage(text,newline=True):
|
|
global QUIET
|
|
if (not QUIET):
|
|
if newline==True:
|
|
try:
|
|
sys.stdout.write(text)
|
|
sys.stdout.write("\n")
|
|
debug_message(traceback.format_exc())
|
|
except:
|
|
debug_message(traceback.format_exc())
|
|
pass
|
|
else:
|
|
try:
|
|
sys.stdout.write(text)
|
|
debug_message(traceback.format_exc())
|
|
except:
|
|
debug_message(traceback.format_exc())
|
|
pass
|
|
|
|
################################################################################
|
|
# Message Box #
|
|
################################################################################
|
|
def message_box(title,message):
|
|
title = "%s (K40 Whisperer V%s)" %(title,version)
|
|
if VERSION == 3:
|
|
tkinter.messagebox.showinfo(title,message)
|
|
else:
|
|
tkMessageBox.showinfo(title,message)
|
|
pass
|
|
|
|
################################################################################
|
|
# Message Box ask OK/Cancel #
|
|
################################################################################
|
|
def message_ask_ok_cancel(title, mess):
|
|
if VERSION == 3:
|
|
result=tkinter.messagebox.askokcancel(title, mess)
|
|
else:
|
|
result=tkMessageBox.askokcancel(title, mess)
|
|
return result
|
|
|
|
################################################################################
|
|
# Debug Message Box #
|
|
################################################################################
|
|
def debug_message(message):
|
|
global DEBUG
|
|
title = "Debug Message"
|
|
if DEBUG:
|
|
if VERSION == 3:
|
|
tkinter.messagebox.showinfo(title,message)
|
|
else:
|
|
tkMessageBox.showinfo(title,message)
|
|
pass
|
|
|
|
################################################################################
|
|
# Choose Units Dialog #
|
|
################################################################################
|
|
if VERSION < 3:
|
|
import tkSimpleDialog
|
|
else:
|
|
import tkinter.simpledialog as tkSimpleDialog
|
|
|
|
class UnitsDialog(tkSimpleDialog.Dialog):
|
|
def body(self, master):
|
|
self.resizable(0,0)
|
|
self.title('Units')
|
|
self.iconname("Units")
|
|
|
|
self.uom = StringVar()
|
|
self.uom.set("Millimeters")
|
|
|
|
Label(master, text="Select DXF Import Units:").grid(row=0)
|
|
Radio_Units_IN = Radiobutton(master,text="Inches", value="Inches")
|
|
Radio_Units_MM = Radiobutton(master,text="Millimeters", value="Millimeters")
|
|
Radio_Units_CM = Radiobutton(master,text="Centimeters", value="Centimeters")
|
|
|
|
Radio_Units_IN.grid(row=1, sticky=W)
|
|
Radio_Units_MM.grid(row=2, sticky=W)
|
|
Radio_Units_CM.grid(row=3, sticky=W)
|
|
|
|
Radio_Units_IN.configure(variable=self.uom)
|
|
Radio_Units_MM.configure(variable=self.uom)
|
|
Radio_Units_CM.configure(variable=self.uom)
|
|
|
|
def apply(self):
|
|
self.result = self.uom.get()
|
|
return
|
|
|
|
|
|
class toplevel_dummy():
|
|
def winfo_exists(self):
|
|
return False
|
|
|
|
class pxpiDialog(tkSimpleDialog.Dialog):
|
|
|
|
def __init__(self,
|
|
parent,
|
|
units = "mm",
|
|
SVG_Size =None,
|
|
SVG_ViewBox =None,
|
|
SVG_inkscape_version=None):
|
|
|
|
self.result = None
|
|
self.svg_pxpi = StringVar()
|
|
self.other = StringVar()
|
|
self.svg_width = StringVar()
|
|
self.svg_height = StringVar()
|
|
self.svg_units = StringVar()
|
|
self.fixed_size = False
|
|
self.svg_units.set(units)
|
|
if units=="mm":
|
|
self.scale=1.0
|
|
else:
|
|
self.scale=1/25.4
|
|
|
|
|
|
###################################
|
|
## Set initial pxpi #
|
|
###################################
|
|
pxpi = 72.0
|
|
if SVG_inkscape_version != None:
|
|
if SVG_inkscape_version >=.92:
|
|
pxpi = 96.0
|
|
else:
|
|
pxpi = 90.0
|
|
|
|
self.svg_pxpi.set("%d"%(pxpi))
|
|
self.other.set("%d"%(pxpi))
|
|
|
|
###################################
|
|
## Set minx/miny #
|
|
###################################
|
|
if SVG_ViewBox!=None and SVG_ViewBox[0]!=None and SVG_ViewBox[1]!=None:
|
|
self.minx_pixels = SVG_ViewBox[0]
|
|
self.miny_pixels = SVG_ViewBox[1]
|
|
else:
|
|
self.minx_pixels = 0.0
|
|
self.miny_pixels = 0.0
|
|
|
|
###################################
|
|
## Set Initial Size #
|
|
###################################
|
|
if SVG_Size!=None and SVG_Size[2]!=None and SVG_Size[3]!=None:
|
|
self.width_pixels = SVG_Size[2]
|
|
self.height_pixels = SVG_Size[3]
|
|
elif SVG_ViewBox!=None and SVG_ViewBox[2]!=None and SVG_ViewBox[3]!=None:
|
|
self.width_pixels = SVG_ViewBox[2]
|
|
self.height_pixels = SVG_ViewBox[3]
|
|
else:
|
|
self.width_pixels = 500.0
|
|
self.height_pixels = 500.0
|
|
###################################
|
|
## Set Initial Size #
|
|
###################################
|
|
if SVG_Size[0]!=None and SVG_Size[1]!=None:
|
|
width = SVG_Size[0]
|
|
height = SVG_Size[1]
|
|
self.fixed_size=True
|
|
else:
|
|
width = self.width_pixels/float(self.svg_pxpi.get())*25.4
|
|
height = self.height_pixels/float(self.svg_pxpi.get())*25.4
|
|
|
|
self.svg_width.set("%f" %(width*self.scale))
|
|
self.svg_height.set("%f" %(height*self.scale))
|
|
###################################
|
|
tkSimpleDialog.Dialog.__init__(self, parent)
|
|
|
|
|
|
def body(self, master):
|
|
self.resizable(0,0)
|
|
self.title('SVG Import Scale:')
|
|
self.iconname("SVG Scale")
|
|
|
|
###########################################################################
|
|
def Entry_custom_Check():
|
|
try:
|
|
value = float(self.other.get())
|
|
if value <= 0.0:
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_custom_Callback(varName, index, mode):
|
|
if Entry_custom_Check() > 0:
|
|
Entry_Custom_pxpi.configure( bg = 'red' )
|
|
else:
|
|
Entry_Custom_pxpi.configure( bg = 'white' )
|
|
pxpi = float(self.other.get())
|
|
width = self.width_pixels/pxpi*25.4
|
|
height = self.height_pixels/pxpi*25.4
|
|
if self.fixed_size:
|
|
pass
|
|
else:
|
|
Set_Value(width=width*self.scale,height=height*self.scale)
|
|
self.svg_pxpi.set("custom")
|
|
###################################################
|
|
def Entry_Width_Check():
|
|
try:
|
|
value = float(self.svg_width.get())/self.scale
|
|
if value <= 0.0:
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Width_Callback(varName, index, mode):
|
|
if Entry_Width_Check() > 0:
|
|
Entry_Custom_Width.configure( bg = 'red' )
|
|
else:
|
|
Entry_Custom_Width.configure( bg = 'white' )
|
|
width = float(self.svg_width.get())/self.scale
|
|
pxpi = self.width_pixels*25.4/width
|
|
height = self.height_pixels/pxpi*25.4
|
|
Set_Value(other=pxpi,height=height*self.scale)
|
|
self.svg_pxpi.set("custom")
|
|
###################################################
|
|
def Entry_Height_Check():
|
|
try:
|
|
value = float(self.svg_height.get())
|
|
if value <= 0.0:
|
|
return 2 # Value is invalid number
|
|
except:
|
|
return 3 # Value not a number
|
|
return 0 # Value is a valid number
|
|
def Entry_Height_Callback(varName, index, mode):
|
|
if Entry_Height_Check() > 0:
|
|
Entry_Custom_Height.configure( bg = 'red' )
|
|
else:
|
|
Entry_Custom_Height.configure( bg = 'white' )
|
|
height = float(self.svg_height.get())/self.scale
|
|
pxpi = self.height_pixels*25.4/height
|
|
width = self.width_pixels/pxpi*25.4
|
|
Set_Value(other=pxpi,width=width*self.scale)
|
|
self.svg_pxpi.set("custom")
|
|
###################################################
|
|
def SVG_pxpi_callback(varName, index, mode):
|
|
if self.svg_pxpi.get() == "custom":
|
|
try:
|
|
pxpi=float(self.other.get())
|
|
except:
|
|
pass
|
|
else:
|
|
pxpi=float(self.svg_pxpi.get())
|
|
width = self.width_pixels/pxpi*25.4
|
|
height = self.height_pixels/pxpi*25.4
|
|
if self.fixed_size:
|
|
Set_Value(other=pxpi)
|
|
else:
|
|
Set_Value(other=pxpi,width=width*self.scale,height=height*self.scale)
|
|
|
|
###########################################################################
|
|
|
|
def Set_Value(other=None,width=None,height=None):
|
|
self.svg_pxpi.trace_vdelete("w",self.trace_id_svg_pxpi)
|
|
self.other.trace_vdelete("w",self.trace_id_pxpi)
|
|
self.svg_width.trace_vdelete("w",self.trace_id_width)
|
|
self.svg_height.trace_vdelete("w",self.trace_id_height)
|
|
self.update_idletasks()
|
|
|
|
if other != None:
|
|
self.other.set("%f" %(other))
|
|
if width != None:
|
|
self.svg_width.set("%f" %(width))
|
|
if height != None:
|
|
self.svg_height.set("%f" %(height))
|
|
|
|
self.trace_id_svg_pxpi = self.svg_pxpi.trace_variable("w", SVG_pxpi_callback)
|
|
self.trace_id_pxpi = self.other.trace_variable("w", Entry_custom_Callback)
|
|
self.trace_id_width = self.svg_width.trace_variable("w", Entry_Width_Callback)
|
|
self.trace_id_height = self.svg_height.trace_variable("w", Entry_Height_Callback)
|
|
self.update_idletasks()
|
|
|
|
###########################################################################
|
|
t0="This dialog opens if the SVG file you are opening\n"
|
|
t1="does not contain enough information to determine\n"
|
|
t2="the intended physical size of the design.\n"
|
|
t3="Select an SVG Import Scale:\n"
|
|
Title_Text0 = Label(master, text=t0+t1+t2, anchor=W)
|
|
Title_Text1 = Label(master, text=t3, anchor=W)
|
|
|
|
Radio_SVG_pxpi_96 = Radiobutton(master,text=" 96 units/in", value="96")
|
|
Label_SVG_pxpi_96 = Label(master,text="(File saved with Inkscape v0.92 or newer)", anchor=W)
|
|
|
|
Radio_SVG_pxpi_90 = Radiobutton(master,text=" 90 units/in", value="90")
|
|
Label_SVG_pxpi_90 = Label(master,text="(File saved with Inkscape v0.91 or older)", anchor=W)
|
|
|
|
Radio_SVG_pxpi_72 = Radiobutton(master,text=" 72 units/in", value="72")
|
|
Label_SVG_pxpi_72 = Label(master,text="(File saved with Adobe Illustrator)", anchor=W)
|
|
|
|
Radio_Res_Custom = Radiobutton(master,text=" Custom:", value="custom")
|
|
Bottom_row = Label(master, text=" ")
|
|
|
|
|
|
Entry_Custom_pxpi = Entry(master,width="10")
|
|
Entry_Custom_pxpi.configure(textvariable=self.other)
|
|
Label_pxpi_units = Label(master,text="units/in", anchor=W)
|
|
self.trace_id_pxpi = self.other.trace_variable("w", Entry_custom_Callback)
|
|
|
|
Label_Width = Label(master,text="Width", anchor=W)
|
|
Entry_Custom_Width = Entry(master,width="10")
|
|
Entry_Custom_Width.configure(textvariable=self.svg_width)
|
|
Label_Width_units = Label(master,textvariable=self.svg_units, anchor=W)
|
|
self.trace_id_width = self.svg_width.trace_variable("w", Entry_Width_Callback)
|
|
|
|
Label_Height = Label(master,text="Height", anchor=W)
|
|
Entry_Custom_Height = Entry(master,width="10")
|
|
Entry_Custom_Height.configure(textvariable=self.svg_height)
|
|
Label_Height_units = Label(master,textvariable=self.svg_units, anchor=W)
|
|
self.trace_id_height = self.svg_height.trace_variable("w", Entry_Height_Callback)
|
|
|
|
if self.fixed_size == True:
|
|
Entry_Custom_Width.configure(state="disabled")
|
|
Entry_Custom_Height.configure(state="disabled")
|
|
###########################################################################
|
|
rn=0
|
|
Title_Text0.grid(row=rn,column=0,columnspan=5, sticky=W)
|
|
|
|
rn=rn+1
|
|
Title_Text1.grid(row=rn,column=0,columnspan=5, sticky=W)
|
|
|
|
rn=rn+1
|
|
Radio_SVG_pxpi_96.grid( row=rn, sticky=W)
|
|
Label_SVG_pxpi_96.grid( row=rn, column=1,columnspan=50, sticky=W)
|
|
|
|
rn=rn+1
|
|
Radio_SVG_pxpi_90.grid( row=rn, sticky=W)
|
|
Label_SVG_pxpi_90.grid( row=rn, column=1,columnspan=50, sticky=W)
|
|
|
|
rn=rn+1
|
|
Radio_SVG_pxpi_72.grid( row=rn, column=0, sticky=W)
|
|
Label_SVG_pxpi_72.grid( row=rn, column=1,columnspan=50, sticky=W)
|
|
|
|
rn=rn+1
|
|
Radio_Res_Custom.grid( row=rn, column=0, sticky=W)
|
|
Entry_Custom_pxpi.grid( row=rn, column=1, sticky=E)
|
|
Label_pxpi_units.grid( row=rn, column=2, sticky=W)
|
|
|
|
rn=rn+1
|
|
Label_Width.grid( row=rn, column=0, sticky=E)
|
|
Entry_Custom_Width.grid( row=rn, column=1, sticky=E)
|
|
Label_Width_units.grid( row=rn, column=2, sticky=W)
|
|
|
|
rn=rn+1
|
|
Label_Height.grid( row=rn, column=0, sticky=E)
|
|
Entry_Custom_Height.grid( row=rn, column=1, sticky=E)
|
|
Label_Height_units.grid( row=rn, column=2, sticky=W)
|
|
|
|
rn=rn+1
|
|
Bottom_row.grid(row=rn,columnspan=50)
|
|
|
|
Radio_SVG_pxpi_96.configure (variable=self.svg_pxpi)
|
|
Radio_SVG_pxpi_90.configure (variable=self.svg_pxpi)
|
|
Radio_SVG_pxpi_72.configure (variable=self.svg_pxpi)
|
|
Radio_Res_Custom.configure (variable=self.svg_pxpi)
|
|
self.trace_id_svg_pxpi = self.svg_pxpi.trace_variable("w", SVG_pxpi_callback)
|
|
###########################################################################
|
|
|
|
def apply(self):
|
|
width = float(self.svg_width.get())/self.scale
|
|
height = float(self.svg_height.get())/self.scale
|
|
pxpi = float(self.other.get())
|
|
viewbox = [self.minx_pixels, self.miny_pixels, width/25.4*pxpi, height/25.4*pxpi]
|
|
self.result = pxpi,viewbox
|
|
return
|
|
|
|
################################################################################
|
|
# Startup Application #
|
|
################################################################################
|
|
|
|
root = Tk()
|
|
app = Application(root)
|
|
app.master.title(title_text)
|
|
app.master.iconname("K40")
|
|
app.master.minsize(800,560)
|
|
app.master.geometry("800x560")
|
|
|
|
try:
|
|
try:
|
|
import tkFont
|
|
default_font = tkFont.nametofont("TkDefaultFont")
|
|
except:
|
|
import tkinter.font
|
|
default_font = tkinter.font.nametofont("TkDefaultFont")
|
|
|
|
default_font.configure(size=9)
|
|
default_font.configure(family='arial')
|
|
#print(default_font.cget("size"))
|
|
#print(default_font.cget("family"))
|
|
except:
|
|
debug_message("Font Set Failed.")
|
|
|
|
################################## Set Icon ########################################
|
|
Icon_Set=False
|
|
|
|
try:
|
|
#debug_message("Icon set %s" %(sys.argv[0]))
|
|
root.iconbitmap(default="icon_32.png")
|
|
#debug_message("Icon set worked %s" %(sys.argv[0]))
|
|
Icon_Set=True
|
|
except:
|
|
debug_message(traceback.format_exc())
|
|
Icon_Set=False
|
|
|
|
if not Icon_Set:
|
|
try:
|
|
scorch_ico_B64=b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAACoAAAAqAF59LPGAAAA\
|
|
GXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAACgBJREFUWIWdl31wXNV5h59z7r37\
|
|
ra/dlSxpLXtlI9kBbGMHu3EJTmJiEhdHgEAJUM8AKZ06zSRT0hqStGNiSGYweEg7TDsDTDtOJ0PB\
|
|
qqKMksmS4JiQMMShfNiAHUvY+rBWXn3s6mOl3dXuvfec/rGSLBcITM/+ce/eufP+nnPueX/ve4TW\
|
|
mo8zEolEZaFQ2NPU1PQ5v9+/KT0yvmY6M12F1oSqK7L1qxvPFwqFkxcuXHjJsqyft7W1zX6cuOKj\
|
|
ALq7u1tjsdiD6eT4nYlne/zn3uwjPTyOdhQCAYBGI0xBdNUKrtjcyu672gp1q+qfHRoaOnTbbbe9\
|
|
9/8C6Ozs9NfW1j4yk5r6u/989Blj+J1BPNrEg4WBXBJfHBqNi6KETQmbupYY9/7T3zjR1XU/HBgY\
|
|
OHDPPffMf2yArq6uluZ480//+VuPXtn3ymn8yoOJuSArlokvXvUShEaj0Dg4FGSJ1k9fxf1PfOe1\
|
|
gaGBW9rb21MfCdDT07O5Jlh97NC+g+HsuQxeLCTyMnHxvvmXEfSyn0KjUBSxCTXX8OBTD6VmCtkv\
|
|
trW1vf2hAF1dXS111bUnDtyxP0zaxlqY9SUAuST+QZ9gCUKUAdyFq6NtRMTie/91KDU2Nb6lo6Nj\
|
|
9H0AR44c8W3auOm1h+54YMPce5OYGBgL0osQH4YQWTWP0JrptIc12zJUr8wSb5njV0cbSfZW4WqF\
|
|
qx388QoePnr4rf6B/us6OjoKAOYiSTwe//6//P1jG7LvZfBgLhOXGEi8Pk0g6JKbtoiusLn6xmHm\
|
|
Jk0Mj40/aLNt+xSJ7gZ8VbNUaIs6kWdspJr5pjp8IxPgQm4wy5MPHN5870P7vg08tLQC3d3drUaJ\
|
|
M4f/8qDhdcu73MDA54H4hkkMZfGJT00TrBBUeBxefSnEF3Zf4Pe/rcVVLtFKRUmXkEUfqSmBz4Tf\
|
|
D62mprnEmdImom+cQ7kllHKZF0W+9aMDecer1nZ0dIyaALFY7MHH73vY8LjmsnkLVjbN8tWv9PPK\
|
|
H6K01IfJ+bdw8tUJ5ufPk+gOU8hUI615hooGqYsxVChDqRQmE5FIK4D9dhFzVQFpSFAGWoBXWTx3\
|
|
+EjgH545cAD4WzORSFQyr+4ceye5sOPF0jc3XYfjiSBnhyqZtDdzy2MHGdg+S2p0mlVjo7zyzWdA\
|
|
CNbdcR3eL+2gKAWOAas1BB2N/8VX6Ls4hpXJkx2fQiuFRpA6NUxmZOLunlTPg2axWLzp5eeP+a3L\
|
|
8rx8NzBYR/9gHUIK4rs38h9Fi/GGOJlaRc3IOLbQXHX7dQzubWM03nxZVpgCtjVE2VfIcuyH/03v\
|
|
zBzKttEILEyOHU0Erv/K5//CjMViO5Mn+9+X5YsrAQJvJMD8tquZCwQIagefBL8UYEgC11yBb+1q\
|
|
4ihqXn8DcyxFaWUTxc2bCK5Zzfw7bzM3PYt29GXxL7zVT+P9jTtlIBDYlOkfW0qs5UmmAQeXbfv2\
|
|
YHxmO6t9Fqt8Fs1+C78pmQ1K8AvW+C3W+C2CwyO8/cxPqR4bZ6XXwmtIhs4OMdKXxLGdy+Jn+sfw\
|
|
+XwbzczI+FptX8rq5eIaxZodV1J1w58RNTTu7DRGRQiAGQ+UvJKQIwjjAHARwex4jiBQiwMujGVn\
|
|
mc8XMdQl4xYIVMllPDnaIvPZfMUlT1usbqCFBp9ky94baFkXp0mVqDl7lrgJcROCGnw2eA2WnnkN\
|
|
AVIQEJeeeQCUWrBLvaQhEMzPFipMIf6vq5ffsYVi663XM/zmGJnB41TVOkzncpx+NUtFyIPrzHLN\
|
|
rk8yfWGKnm+8QFW9hSMnUQLSvWl+88iLOI7Gb869P/7iRjVNzEBlcBYILzo6QqAEXPX5FNHGEwTE\
|
|
RX536CAggYqFjWmjCRDf20BpWjD1Mx8ZRxO5SaO1Yq5fM54om+zq2wWXl7tL/4JVoawZboyeNywZ\
|
|
1g5oIVFCoCSs3zBJ6/o0nU/cx9pmjYlEFSXuqKdMX+cSaaiisjJEzaoKsql5lN9DpLGaSo9FQC68\
|
|
h4CFQnUJQWN6DKpXhM+Z+Xz+ZF1LbOvo2RRSaJQhcQ2IR+cxcxrr0xIjPITtamqIEnnyCgDytyYp\
|
|
VeTZcuN2Um/kGR2fJn98LX41QPrMr1kj9xIwqhjpfZcpNU2U6mXFGupbV5LP50+ZyWTyePPWlr9O\
|
|
9V5ES4EyBLnaEPNZQXpYsFU9xdNPb0cIRdvuL7FSSEbsn/Dai4Pkgl6yoxOE3TwR8UmqMr9ggjT3\
|
|
6jDPyyOIDWEmz/yRu9ww3TKHH3MJIb61hZGRkV9Lx3F+vvPLX8hrNI5lkL66iaqQTe9pH089t51j\
|
|
rzUS9BYxhUXal+PN+88Qapqibcwi1DvIxI9eYP1vB3jX+zTPRU8hm+CJ8Bl2Bny4/YNkCzlmRBGF\
|
|
WmpUELCz48a84zgJ4+jRo6XMzOSac6f6toy5YFdX4ArJ+JCCUjWzcxG08mAgSfYO03fyLK3jBR53\
|
|
3mWdqEUXC1xRDJIuzHLWzlKbs9iba+Qm9SJ9huaqko/nxQj1OrwAoGj+VCt/fttnj+zatatLaK3p\
|
|
6upqqTSDZx6946AJEmFa5BvDOIZEuC41UzamLtcHLQTFuSFuKUV40pukvRRGacX/mNNMSPB6a8ja\
|
|
M1T6o1SIAJ5sAeG4aOXgahdtwP6jD9s5Cuvb29v7lzqil19++bGux5/d/+6vTiGFgSENhDQRhslc\
|
|
tZeipZBKEMkZCK0YKV6k1lOHBgxpYkhzaYOhXKZCUJUpIueLaMdGaRdXu2zYcy3t++96dMeOHd9h\
|
|
IbkBGBgYOHDfD77+h9j6GNq1UY4NdglKRSon5qgbLRGetJnxlMgEXHyRBixMvJgYWiy1oVq7KK1Q\
|
|
XhPhOGjt4qJQ2qX+EzHuffhrJ3K53PeWPG95U9rZ2VnftGLl64fuPBDLjs6UGxMhkMJACgnCQEgJ\
|
|
QuBaBlM1Jq4BlpJUzLpoQ5btVikmG0PUnB8H20a5DpUrKvn2898fnZhJX7tnz56RDwQA6Onp2bgi\
|
|
Upd4ct+hxtTpZLkzEAtHESEQQiJEGQIp0FJi+0yytUGUZSCVpiKVZSoeofrsMNq2WdFazzf+7YGL\
|
|
E9PpL958883vXOb6H3Qw6ezsrF3Xuq7r3//xX68//cKb4GqEKLdpiIVTkQCEREsJErQQaCkoVvmZ\
|
|
WxnF9VpE3uhlww0b+atHvnait6/31uXt+J8EAEgkEt5AIPDd4lR+f+djP/b3n+gtl4rFlVjIiHIU\
|
|
yiYmBFqUrbbpyibu+u7ddqA2dDifzx/cvXt38YN0PvJw2tnZWR+Pxw/MpbN3Hz/6y8Dg6+cY60vi\
|
|
lNyFCGUIw2uyojVG87Ut7Lx9Vz4Urfzx8PDwofb29v4/Ff8jAZaBhDwez00NDQ2fCwaD10yNZtbm\
|
|
Z3JVAIGq4ExNfeR8oVB4K5lMvmTb9i86Ojo+vA4vG/8LxNOT3rL519MAAAAASUVORK5CYII='
|
|
|
|
icon_im =PhotoImage(data=scorch_ico_B64, format='png')
|
|
root.call('wm', 'iconphoto', root._w, '-default', icon_im)
|
|
except:
|
|
pass
|
|
#####################################################################################
|
|
|
|
|
|
if LOAD_MSG != "":
|
|
message_box("K40 Whisperer",LOAD_MSG)
|
|
|
|
opts, args = None, None
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[1:], "hpd",["help", "pi", "debug"])
|
|
except:
|
|
print('Unable interpret command line options')
|
|
sys.exit()
|
|
|
|
for option, value in opts:
|
|
if option in ('-h','--help'):
|
|
print(' ')
|
|
print('Usage: python k40_whisperer.py [-h -p]')
|
|
print('-h : print this help (also --help)')
|
|
print('-p : Small screen option (for small raspberry pi display) (also --pi)')
|
|
sys.exit()
|
|
elif option in ('-p','--pi'):
|
|
print("pi mode")
|
|
app.master.minsize(480,320)
|
|
app.master.geometry("480x320")
|
|
elif option in ('-d','--debug'):
|
|
DEBUG=True
|
|
|
|
if DEBUG:
|
|
import inspect
|
|
debug_message("Debuging is turned on.")
|
|
|
|
web_interface = ""
|
|
with open('interface.html', 'r') as file:
|
|
web_interface = file.read()
|
|
|
|
class MyHandler(BaseHTTPRequestHandler):
|
|
def do_HEAD(self):
|
|
self.send_response(200)
|
|
|
|
def do_GET(self):
|
|
|
|
parts = self.path.split('/');
|
|
|
|
if (parts[1] == "cmd"):
|
|
self.send_response(200)
|
|
self.send_header("Content-type", "text/plain")
|
|
|
|
if (parts[2] == "move"):
|
|
app.Rapid_Move(float(parts[3]), float(parts[4]))
|
|
self.end_headers()
|
|
self.wfile.write(bytes("OK", "utf-8"))
|
|
return
|
|
|
|
self.send_response(500)
|
|
self.end_headers()
|
|
self.wfile.write(bytes("INVALID COMMAND", "utf-8"))
|
|
return
|
|
|
|
self.send_response(200)
|
|
self.send_header("Content-type", "text/html")
|
|
self.end_headers()
|
|
self.wfile.write(bytes(web_interface, "utf-8"))
|
|
self.wfile.flush()
|
|
|
|
httpd = ThreadingHTTPServer(('', 8000), MyHandler)
|
|
|
|
def start_server():
|
|
httpd.serve_forever()
|
|
|
|
server_thread = threading.Thread(target=start_server)
|
|
server_thread.start()
|
|
|
|
#root.attributes('-fullscreen', True)
|
|
sw, sh = root.winfo_screenwidth(), root.winfo_screenheight()
|
|
root.geometry("%dx%d+0+0" % (sw, sh))
|
|
root.mainloop()
|
|
|
|
httpd.shutdown()
|