k40whisperer_turbo/k40_whisperer.py

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()