Advertisement
j0h

MOD_k40_whisperer.py

j0h
Feb 19th, 2024 (edited)
1,059
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 263.62 KB | None | 0 0
  1. #!/usr/bin/python3
  2. """
  3.    K40 Whisperer CLI Mod laser photobooth
  4.  
  5.    Copyright (C) <2017-2023>  <Scorch>
  6.    This program is free software: you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation, either version 3 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  
  19. """
  20. version = '0.69'
  21. title_text = "K40 Whisperer V"+version
  22.  
  23. import sys
  24. from math import *
  25. from egv import egv
  26. from nano_library import K40_CLASS
  27. from dxf import DXF_CLASS
  28. from svg_reader import SVG_READER
  29. from svg_reader import SVG_TEXT_EXCEPTION
  30. from svg_reader import SVG_PXPI_EXCEPTION
  31. from g_code_library import G_Code_Rip
  32. from interpolate import interpolate
  33. from ecoords import ECoord
  34. from convex_hull import hull2D
  35. from embedded_images import K40_Whisperer_Images
  36.  
  37. import inkex
  38. import simplestyle
  39. import simpletransform
  40. import cubicsuperpath
  41. import cspsubdiv
  42. import traceback
  43. import struct
  44.  
  45. DEBUG = False
  46.  
  47. if DEBUG:
  48.     import inspect
  49.    
  50. VERSION = sys.version_info[0]
  51. LOAD_MSG = ""
  52.  
  53. if VERSION == 3:
  54.     from tkinter import *
  55.     from tkinter.filedialog import *
  56.     import tkinter.messagebox
  57.     MAXINT = sys.maxsize
  58.    
  59. else:
  60.     from Tkinter import *
  61.     from tkFileDialog import *
  62.     import tkMessageBox
  63.     MAXINT = sys.maxint
  64.  
  65. if VERSION < 3 and sys.version_info[1] < 6:
  66.     def next(item):
  67.         #return item.next()
  68.         return item.__next__()
  69.    
  70. try:
  71.     import psyco
  72.     psyco.full()
  73.     LOAD_MSG = LOAD_MSG+"\nPsyco Loaded\n"
  74. except:
  75.     pass
  76.  
  77. import math
  78. from time import time
  79. import os
  80. import re
  81. import binascii
  82. import getopt
  83. import operator
  84. import webbrowser
  85. from PIL import Image
  86. from PIL import ImageOps
  87. from PIL import ImageFilter
  88.  
  89. try:
  90.     Image.warnings.simplefilter('ignore', Image.DecompressionBombWarning)
  91. except:
  92.     pass
  93. try:
  94.     from PIL import ImageTk
  95.     from PIL import _imaging
  96. except:
  97.     pass #Don't worry everything will still work
  98.  
  99. try:
  100.     Image.LANCZOS
  101. except:
  102.     Image.LANCZOS=Image.ANTIALIAS
  103.  
  104. PYCLIPPER=True
  105. try:
  106.     import pyclipper
  107. except:
  108.     print("Unable to load Pyclipper library (Offset trace outline will not work without it)")
  109.     PYCLIPPER = False
  110.  
  111. try:
  112.     os.chdir(os.path.dirname(__file__))
  113. except:
  114.     pass
  115.  
  116. QUIET = False
  117.    
  118. ################################################################################
  119. class Application(Frame):
  120.     def __init__(self, master):
  121.         self.trace_window = toplevel_dummy()
  122.         Frame.__init__(self, master)
  123.         self.w = 780
  124.         self.h = 490
  125.         frame = Frame(master, width= self.w, height=self.h)
  126.         self.master = master
  127.         self.x = -1
  128.         self.y = -1
  129.         self.createWidgets()
  130.         self.micro = False
  131.        
  132.  
  133.     def resetPath(self):
  134.         self.RengData  = ECoord()
  135.         self.VengData  = ECoord()
  136.         self.VcutData  = ECoord()
  137.         self.GcodeData = ECoord()
  138.         self.SCALE = 1
  139.         self.Design_bounds = (0,0,0,0)
  140.         self.UI_image = None
  141.         #if self.HomeUR.get():
  142.         self.move_head_window_temporary([0.0,0.0])
  143.         #else:
  144.         #    self.move_head_window_temporary([0.0,0.0])
  145.            
  146.         self.pos_offset=[0.0,0.0]
  147.        
  148.     def createWidgets(self):
  149.         self.initComplete = 0
  150.         self.stop=[True]
  151.        
  152.         self.k40 = None
  153.         self.run_time = 0
  154.        
  155.         self.master.bind("<Configure>", self.Master_Configure)
  156.         self.master.bind('<Enter>', self.bindConfigure)
  157.         self.master.bind('<F1>', self.KEY_F1) #About
  158.         self.master.bind('<F2>', self.KEY_F2) #Advanced Config
  159.         self.master.bind('<F3>', self.KEY_F3) #Raster settings
  160.         self.master.bind('<F4>', self.KEY_F4) #rotary settings
  161.         self.master.bind('<F5>', self.KEY_F5)
  162.         self.master.bind('<F6>', self.KEY_F6) #advanced runtime settings
  163.         self.master.bind('<Home>', self.Home)
  164.  
  165.         self.master.bind('<Control-R>', self.Raster_Eng)
  166.         self.master.bind('<Control-V>', self.Vector_Eng)
  167.         #self.master.bind('<Control-C>', self.Vector_Cut)
  168.         self.master.bind('<Control-G>', self.Gcode_Cut)
  169.  
  170.         self.master.bind('<Control-Left>'  , self.Move_Left)
  171.         self.master.bind('<Control-Right>' , self.Move_Right)
  172.         self.master.bind('<Control-Up>'    , self.Move_Up)
  173.         self.master.bind('<Control-Down>'  , self.Move_Down)
  174.        
  175.         self.master.bind('<Control-Home>'  , self.Move_UL)
  176.         self.master.bind('<Control-Prior>' , self.Move_UR)
  177.         self.master.bind('<Control-Next>'  , self.Move_LR)
  178.         self.master.bind('<Control-End>'   , self.Move_LL)
  179.         self.master.bind('<Control-Clear>' , self.Move_CC)
  180.  
  181.         self.master.bind('<Control-Key-4>' , self.Move_Left)
  182.         self.master.bind('<Control-6>'     , self.Move_Right)
  183.         self.master.bind('<Control-8>'     , self.Move_Up)
  184.         self.master.bind('<Control-Key-2>' , self.Move_Down)
  185.        
  186.         self.master.bind('<Control-7>'     , self.Move_UL)
  187.         self.master.bind('<Control-9>'     , self.Move_UR)
  188.         self.master.bind('<Control-Key-3>' , self.Move_LR)
  189.         self.master.bind('<Control-Key-1>' , self.Move_LL)
  190.         self.master.bind('<Control-Key-5>' , self.Move_CC)
  191.  
  192.         #####
  193.  
  194.         self.master.bind('<Alt-Control-Left>' , self.Move_Arb_Left)
  195.         self.master.bind('<Alt-Control-Right>', self.Move_Arb_Right)
  196.         self.master.bind('<Alt-Control-Up>'   , self.Move_Arb_Up)
  197.         self.master.bind('<Alt-Control-Down>' , self.Move_Arb_Down)
  198.  
  199.         self.master.bind('<Alt-Control-Key-4>', self.Move_Arb_Left)
  200.         self.master.bind('<Alt-Control-6>'    , self.Move_Arb_Right)
  201.         self.master.bind('<Alt-Control-8>'    , self.Move_Arb_Up)
  202.         self.master.bind('<Alt-Control-Key-2>', self.Move_Arb_Down)
  203.  
  204.  
  205.         self.master.bind('<Alt-Left>' , self.Move_Arb_Left)
  206.         self.master.bind('<Alt-Right>', self.Move_Arb_Right)
  207.         self.master.bind('<Alt-Up>'   , self.Move_Arb_Up)
  208.         self.master.bind('<Alt-Down>' , self.Move_Arb_Down)
  209.  
  210.         self.master.bind('<Alt-Key-4>', self.Move_Arb_Left)
  211.         self.master.bind('<Alt-6>'    , self.Move_Arb_Right)
  212.         self.master.bind('<Alt-8>'    , self.Move_Arb_Up)
  213.         self.master.bind('<Alt-Key-2>', self.Move_Arb_Down)
  214.  
  215.         #####
  216.         self.master.bind('<Control-i>' , self.Initialize_Laser)
  217.         self.master.bind('<Control-f>' , self.Unfreeze_Laser)
  218.         self.master.bind('<Control-o>' , self.menu_File_Open_Design)
  219.         self.master.bind('<Control-l>' , self.menu_Reload_Design)
  220.         self.master.bind('<Control-h>' , self.Home)
  221.         self.master.bind('<Control-u>' , self.Unlock)
  222.         self.master.bind('<Escape>'    , self.Stop)
  223.         self.master.bind('<Control-t>' , self.TRACE_Settings_Window)
  224.  
  225.         self.include_Reng = BooleanVar()
  226.         self.include_Rpth = BooleanVar()
  227.         self.include_Veng = BooleanVar()
  228.         self.include_Vcut = BooleanVar()
  229.         self.include_Gcde = BooleanVar()
  230.         self.include_Time = BooleanVar()
  231.  
  232.         self.advanced = BooleanVar()
  233.        
  234.         self.halftone     = BooleanVar()
  235.         self.mirror       = BooleanVar()
  236.         self.rotate       = BooleanVar()
  237.         self.negate       = BooleanVar()
  238.         self.inputCSYS    = BooleanVar()
  239.         self.HomeUR       = BooleanVar()
  240.         self.engraveUP    = BooleanVar()
  241.         self.init_home    = BooleanVar()
  242.         self.post_home    = BooleanVar()
  243.         self.post_beep    = BooleanVar()
  244.         self.post_disp    = BooleanVar()
  245.         self.post_exec    = BooleanVar()
  246.        
  247.         self.pre_pr_crc   = BooleanVar()
  248.         self.inside_first = BooleanVar()
  249.         self.rotary       = BooleanVar()
  250.         self.reduced_mem  = BooleanVar()
  251.         self.wait         = BooleanVar()
  252.        
  253.  
  254.         self.ht_size    = StringVar()
  255.         self.Reng_feed  = StringVar()
  256.         self.Veng_feed  = StringVar()
  257.         self.Vcut_feed  = StringVar()
  258.  
  259.         self.Reng_passes = StringVar()
  260.         self.Veng_passes = StringVar()
  261.         self.Vcut_passes = StringVar()
  262.         self.Gcde_passes = StringVar()
  263.        
  264.        
  265.         self.board_name = StringVar()
  266.         self.units      = StringVar()
  267.         self.jog_step   = StringVar()
  268.         self.rast_step  = StringVar()
  269.         self.funits     = StringVar()
  270.        
  271.  
  272.         self.bezier_M1     = StringVar()
  273.         self.bezier_M2     = StringVar()
  274.         self.bezier_weight = StringVar()
  275.  
  276. ##        self.unsharp_flag = BooleanVar()
  277. ##        self.unsharp_r    = StringVar()
  278. ##        self.unsharp_p    = StringVar()
  279. ##        self.unsharp_t    = StringVar()
  280. ##        self.unsharp_flag.set(False)
  281. ##        self.unsharp_r.set("40")
  282. ##        self.unsharp_p.set("350")
  283. ##        self.unsharp_t.set("3")
  284.  
  285.         self.LaserXsize = StringVar()
  286.         self.LaserYsize = StringVar()
  287.  
  288.         self.LaserXscale = StringVar()
  289.         self.LaserYscale = StringVar()
  290.         self.LaserRscale = StringVar()
  291.  
  292.         self.rapid_feed = StringVar()
  293.  
  294.         self.gotoX = StringVar()
  295.         self.gotoY = StringVar()
  296.  
  297.         self.n_egv_passes = StringVar()
  298.  
  299.         self.inkscape_path = StringVar()
  300.         self.batch_path    = StringVar()
  301.         self.ink_timeout   = StringVar()
  302.        
  303.         self.t_timeout  = StringVar()
  304.         self.n_timeouts  = StringVar()
  305.        
  306.         self.Reng_time = StringVar()
  307.         self.Veng_time = StringVar()
  308.         self.Vcut_time = StringVar()
  309.         self.Gcde_time = StringVar()
  310.  
  311.         self.comb_engrave = BooleanVar()
  312.         self.comb_vector  = BooleanVar()
  313.         self.zoom2image   = BooleanVar()
  314.  
  315.         self.trace_w_laser  = BooleanVar()
  316.         self.trace_gap      = StringVar()
  317.         self.trace_speed    = StringVar()
  318.        
  319.         ###########################################################################
  320.         #                         INITILIZE VARIABLES                             #
  321.         #    if you want to change a default setting this is the place to do it   #
  322.         ###########################################################################
  323.         self.include_Reng.set(1)
  324.         self.include_Rpth.set(0)
  325.         self.include_Veng.set(1)
  326.         self.include_Vcut.set(1)
  327.         self.include_Gcde.set(1)
  328.         self.include_Time.set(0)
  329.         self.advanced.set(0)
  330.        
  331.         self.halftone.set(1)
  332.         self.mirror.set(0)
  333.         self.rotate.set(0)
  334.         self.negate.set(0)
  335.         self.inputCSYS.set(0)
  336.         self.HomeUR.set(0)
  337.         self.engraveUP.set(0)
  338.         self.init_home.set(1)
  339.         self.post_home.set(0)
  340.         self.post_beep.set(0)
  341.         self.post_disp.set(0)
  342.         self.post_exec.set(0)
  343.        
  344.         self.pre_pr_crc.set(1)
  345.         self.inside_first.set(1)
  346.         self.rotary.set(0)
  347.         self.reduced_mem.set(0)
  348.         self.wait.set(1)
  349.        
  350.         self.ht_size.set(500)
  351.  
  352.         self.Reng_feed.set("100")
  353.         self.Veng_feed.set("20")
  354.         self.Vcut_feed.set("10")
  355.         self.Reng_passes.set("1")
  356.         self.Veng_passes.set("1")
  357.         self.Vcut_passes.set("1")
  358.         self.Gcde_passes.set("1")
  359.        
  360.        
  361.         self.jog_step.set("10.0")
  362.         self.rast_step.set("0.002")
  363.        
  364.         self.bezier_weight.set("3.5")
  365.         self.bezier_M1.set("2.5")
  366.         self.bezier_M2.set("0.50")
  367.  
  368.         self.bezier_weight_default = float(self.bezier_weight.get())
  369.         self.bezier_M1_default     = float(self.bezier_M1.get())
  370.         self.bezier_M2_default     = float(self.bezier_M2.get())
  371.        
  372.                                        
  373.         self.board_name.set("LASER-M2") # Options are
  374.                                         #    "LASER-M2",
  375.                                         #    "LASER-M1",
  376.                                         #    "LASER-M",
  377.                                         #    "LASER-B2",
  378.                                         #    "LASER-B1",
  379.                                         #    "LASER-B",
  380.                                         #    "LASER-A"
  381.  
  382.  
  383.         self.units.set("in")            # Options are "in" and "mm"
  384.  
  385.         self.ink_timeout.set("3")
  386.         self.t_timeout.set("200")
  387.         self.n_timeouts.set("30")
  388.  
  389.         self.HOME_DIR    = os.path.expanduser("~/photoBooth")
  390.        
  391.         if not os.path.isdir(self.HOME_DIR):
  392.             self.HOME_DIR = ""
  393.  
  394.         self.DESIGN_FILE = (self.HOME_DIR+"/None")
  395.         self.EGV_FILE    = None
  396.        
  397.         self.aspect_ratio =  0
  398.         self.segID   = []
  399.        
  400.         self.LaserXsize.set("325")
  401.         self.LaserYsize.set("220")
  402.        
  403.         self.LaserXscale.set("1.000")
  404.         self.LaserYscale.set("1.000")
  405.         self.LaserRscale.set("1.000")
  406.  
  407.         self.rapid_feed.set("0.0")
  408.  
  409.         self.gotoX.set("0.0")
  410.         self.gotoY.set("0.0")
  411.  
  412.         self.n_egv_passes.set("1")
  413.  
  414.         self.comb_engrave.set(0)
  415.         self.comb_vector.set(0)
  416.         self.zoom2image.set(0)
  417.  
  418.  
  419.         self.trace_w_laser.set(0)
  420.         self.trace_gap.set(0)
  421.         self.trace_speed.set(50)
  422.        
  423.         self.laserX    = 0.0
  424.         self.laserY    = 0.0
  425.         self.PlotScale = 1.0
  426.         self.GUI_Disabled = False
  427.  
  428.         # PAN and ZOOM STUFF
  429.         self.panx = 0
  430.         self.panx = 0
  431.         self.lastx = 0
  432.         self.lasty = 0
  433.         self.move_start_x = 0
  434.         self.move_start_y = 0
  435.  
  436.        
  437.         self.RengData  = ECoord()
  438.         self.VengData  = ECoord()
  439.         self.VcutData  = ECoord()
  440.         self.GcodeData = ECoord()
  441.         self.SCALE = 1
  442.         self.Design_bounds = (0,0,0,0)
  443.         self.UI_image = None
  444.         self.pos_offset=[0.0,0.0]
  445.         self.inkscape_warning = False
  446.        
  447.         # Derived variables
  448.         if self.units.get() == 'in':
  449.             self.funits.set('in/min')
  450.             self.units_scale = 1.0
  451.         else:
  452.             self.units.set('mm')
  453.             self.funits.set('mm/s')
  454.             self.units_scale = 25.4
  455.        
  456.         self.statusMessage = StringVar()
  457.         self.statusMessage.set("Welcome to K40 Whisperer")
  458.        
  459.        
  460.         self.Reng_time.set("0")
  461.         self.Veng_time.set("0")
  462.         self.Vcut_time.set("0")
  463.         self.Gcde_time.set("0")
  464.  
  465.         self.min_vector_speed = 1.1 #in/min
  466.         self.min_raster_speed = 12  #in/min
  467.        
  468.         ##########################################################################
  469.         ###                     END INITILIZING VARIABLES                      ###
  470.         ##########################################################################
  471.  
  472.         # make a Status Bar
  473.         self.statusbar = Label(self.master, textvariable=self.statusMessage, \
  474.                                    bd=1, relief=SUNKEN , height=1)
  475.         self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM)
  476.        
  477.  
  478.         # Canvas
  479.         lbframe = Frame( self.master )
  480.         self.PreviewCanvas_frame = lbframe
  481.         self.PreviewCanvas = Canvas(lbframe, width=self.w-(220+20), height=self.h-200, background="grey75")
  482.         self.PreviewCanvas.pack(side=LEFT, fill=BOTH, expand=1)
  483.         self.PreviewCanvas_frame.place(x=230, y=10)
  484.  
  485.         self.PreviewCanvas.tag_bind('LaserTag',"<1>"              , self.mousePanStart)
  486.         self.PreviewCanvas.tag_bind('LaserTag',"<B1-Motion>"      , self.mousePan)
  487.         self.PreviewCanvas.tag_bind('LaserTag',"<ButtonRelease-1>", self.mousePanStop)
  488.  
  489.         self.PreviewCanvas.tag_bind('LaserDot',"<3>"              , self.right_mousePanStart)
  490.         self.PreviewCanvas.tag_bind('LaserDot',"<B3-Motion>"      , self.right_mousePan)
  491.         self.PreviewCanvas.tag_bind('LaserDot',"<ButtonRelease-3>", self.right_mousePanStop)
  492.  
  493.         # Left Column #
  494.         self.separator1 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  495.         self.separator2 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  496.         self.separator3 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  497.         self.separator4 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  498.        
  499.         self.Label_Reng_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
  500.         self.Entry_Reng_feed   = Entry(self.master,width="15")
  501.         self.Entry_Reng_feed.configure(textvariable=self.Reng_feed,justify='center',fg="black")
  502.         self.Reng_feed.trace_variable("w", self.Entry_Reng_feed_Callback)
  503.         self.NormalColor =  self.Entry_Reng_feed.cget('bg')
  504.  
  505.         self.Label_Veng_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
  506.         self.Entry_Veng_feed   = Entry(self.master,width="15")
  507.         self.Entry_Veng_feed.configure(textvariable=self.Veng_feed,justify='center',fg="blue")
  508.         self.Veng_feed.trace_variable("w", self.Entry_Veng_feed_Callback)
  509.         self.NormalColor =  self.Entry_Veng_feed.cget('bg')
  510.  
  511.         self.Label_Vcut_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
  512.         self.Entry_Vcut_feed   = Entry(self.master,width="15")
  513.         self.Entry_Vcut_feed.configure(textvariable=self.Vcut_feed,justify='center',fg="red")
  514.         self.Vcut_feed.trace_variable("w", self.Entry_Vcut_feed_Callback)
  515.         self.NormalColor =  self.Entry_Vcut_feed.cget('bg')
  516.  
  517.         # Buttons
  518.         self.Reng_Button  = Button(self.master,text="Raster Engrave", command=self.Raster_Eng)
  519.         self.Veng_Button  = Button(self.master,text="Vector Engrave", command=self.Vector_Eng)
  520.         self.Vcut_Button  = Button(self.master,text="Vector Cut"    , command=self.Vector_Cut)
  521.         self.Grun_Button  = Button(self.master,text="Run G-Code"    , command=self.Gcode_Cut)
  522.  
  523.  
  524.         self.Reng_Veng_Button      = Button(self.master,text="Raster and\nVector Engrave", command=self.Raster_Vector_Eng)
  525.         self.Veng_Vcut_Button      = Button(self.master,text="Vector Engrave\nand Cut", command=self.Vector_Eng_Cut)
  526.         self.Reng_Veng_Vcut_Button = Button(self.master,text="Raster Engrave\nVector Engrave\nand\nVector Cut", command=self.Raster_Vector_Cut)
  527.        
  528.         self.Label_Position_Control = Label(self.master,text="Position Controls:", anchor=W)
  529.        
  530.         self.Initialize_Button = Button(self.master,text="Initialize Laser Cutter", command=self.Initialize_Laser)
  531.  
  532.         self.Open_Button       = Button(self.master,text="Open\nDesign File",   command=self.menu_File_Open_Design)
  533.         self.Reload_Button     = Button(self.master,text="Reload\nDesign File", command=self.menu_Reload_Design)
  534.        
  535.         self.Home_Button       = Button(self.master,text="Home",            command=self.Home)
  536.         self.UnLock_Button     = Button(self.master,text="Unlock Rail",     command=self.Unlock)
  537.         self.Stop_Button       = Button(self.master,text="Pause/Stop",      command=self.Stop)
  538.  
  539.         try:            
  540.             self.left_image  = PhotoImage(data=K40_Whisperer_Images.left_B64,  format='gif')
  541.             self.right_image = PhotoImage(data=K40_Whisperer_Images.right_B64, format='gif')
  542.             self.up_image    = PhotoImage(data=K40_Whisperer_Images.up_B64,    format='gif')
  543.             self.down_image  = PhotoImage(data=K40_Whisperer_Images.down_B64,  format='gif')
  544.            
  545.             self.Right_Button   = Button(self.master,image=self.right_image, command=self.Move_Right)
  546.             self.Left_Button    = Button(self.master,image=self.left_image,  command=self.Move_Left)
  547.             self.Up_Button      = Button(self.master,image=self.up_image,    command=self.Move_Up)
  548.             self.Down_Button    = Button(self.master,image=self.down_image,  command=self.Move_Down)
  549.  
  550.             self.UL_image  = PhotoImage(data=K40_Whisperer_Images.UL_B64, format='gif')
  551.             self.UR_image  = PhotoImage(data=K40_Whisperer_Images.UR_B64, format='gif')
  552.             self.LR_image  = PhotoImage(data=K40_Whisperer_Images.LR_B64, format='gif')
  553.             self.LL_image  = PhotoImage(data=K40_Whisperer_Images.LL_B64, format='gif')
  554.             self.CC_image  = PhotoImage(data=K40_Whisperer_Images.CC_B64, format='gif')
  555.  
  556.             self.UL_Button = Button(self.master,image=self.UL_image, command=self.Move_UL)
  557.             self.UR_Button = Button(self.master,image=self.UR_image, command=self.Move_UR)
  558.             self.LR_Button = Button(self.master,image=self.LR_image, command=self.Move_LR)
  559.             self.LL_Button = Button(self.master,image=self.LL_image, command=self.Move_LL)
  560.             self.CC_Button = Button(self.master,image=self.CC_image, command=self.Move_CC)
  561.            
  562.         except:
  563.             self.Right_Button   = Button(self.master,text=">",          command=self.Move_Right)
  564.             self.Left_Button    = Button(self.master,text="<",          command=self.Move_Left)
  565.             self.Up_Button      = Button(self.master,text="^",          command=self.Move_Up)
  566.             self.Down_Button    = Button(self.master,text="v",          command=self.Move_Down)
  567.  
  568.             self.UL_Button = Button(self.master,text=" ", command=self.Move_UL)
  569.             self.UR_Button = Button(self.master,text=" ", command=self.Move_UR)
  570.             self.LR_Button = Button(self.master,text=" ", command=self.Move_LR)
  571.             self.LL_Button = Button(self.master,text=" ", command=self.Move_LL)
  572.             self.CC_Button = Button(self.master,text=" ", command=self.Move_CC)
  573.  
  574.         self.Label_Step   = Label(self.master,text="Jog Step", anchor=CENTER )
  575.         self.Label_Step_u = Label(self.master,textvariable=self.units, anchor=W)
  576.         self.Entry_Step   = Entry(self.master,width="15")
  577.         self.Entry_Step.configure(textvariable=self.jog_step, justify='center')
  578.         self.jog_step.trace_variable("w", self.Entry_Step_Callback)
  579.  
  580.         ###########################################################################
  581.         self.GoTo_Button    = Button(self.master,text="Move To", command=self.GoTo)
  582.        
  583.         self.Entry_GoToX   = Entry(self.master,width="15",justify='center')
  584.         self.Entry_GoToX.configure(textvariable=self.gotoX)
  585.         self.gotoX.trace_variable("w", self.Entry_GoToX_Callback)
  586.         self.Entry_GoToY   = Entry(self.master,width="15",justify='center')
  587.         self.Entry_GoToY.configure(textvariable=self.gotoY)
  588.         self.gotoY.trace_variable("w", self.Entry_GoToY_Callback)
  589.        
  590.         self.Label_GoToX   = Label(self.master,text="X", anchor=CENTER )
  591.         self.Label_GoToY   = Label(self.master,text="Y", anchor=CENTER )
  592.         ###########################################################################
  593.         # End Left Column #
  594.  
  595.         # Advanced Column     #
  596.         self.separator_vert = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  597.         self.Label_Advanced_column = Label(self.master,text="Advanced Settings",anchor=CENTER)
  598.         self.separator_adv = Frame(self.master, height=2, bd=1, relief=SUNKEN)      
  599.  
  600.         self.Label_Halftone_adv = Label(self.master,text="Halftone (Dither)")
  601.         self.Checkbutton_Halftone_adv = Checkbutton(self.master,text=" ", anchor=W)
  602.         self.Checkbutton_Halftone_adv.configure(variable=self.halftone)
  603.         self.halftone.trace_variable("w", self.View_Refresh_and_Reset_RasterPath) #self.menu_View_Refresh_Callback
  604.  
  605.         self.Label_Negate_adv = Label(self.master,text="Invert Raster Color")
  606.         self.Checkbutton_Negate_adv = Checkbutton(self.master,text=" ", anchor=W)
  607.         self.Checkbutton_Negate_adv.configure(variable=self.negate)
  608.         self.negate.trace_variable("w", self.View_Refresh_and_Reset_RasterPath)
  609.  
  610.         self.separator_adv2 = Frame(self.master, height=2, bd=1, relief=SUNKEN)  
  611.  
  612.         self.Label_Mirror_adv = Label(self.master,text="Mirror Design")
  613.         self.Checkbutton_Mirror_adv = Checkbutton(self.master,text=" ", anchor=W)
  614.         self.Checkbutton_Mirror_adv.configure(variable=self.mirror)
  615.         self.mirror.trace_variable("w", self.View_Refresh_and_Reset_RasterPath)
  616.  
  617.         self.Label_Rotate_adv = Label(self.master,text="Rotate Design")
  618.         self.Checkbutton_Rotate_adv = Checkbutton(self.master,text=" ", anchor=W)
  619.         self.Checkbutton_Rotate_adv.configure(variable=self.rotate)
  620.         self.rotate.trace_variable("w", self.View_Refresh_and_Reset_RasterPath)
  621.  
  622.         self.separator_adv3 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  623.        
  624.         self.Label_inputCSYS_adv = Label(self.master,text="Use Input CSYS")
  625.         self.Checkbutton_inputCSYS_adv = Checkbutton(self.master,text=" ", anchor=W)
  626.         self.Checkbutton_inputCSYS_adv.configure(variable=self.inputCSYS)
  627.         self.inputCSYS.trace_variable("w", self.menu_View_inputCSYS_Refresh_Callback)
  628.  
  629.         self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First")
  630.         self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ", anchor=W)
  631.         self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first)
  632.         self.inside_first.trace_variable("w", self.menu_Inside_First_Callback)
  633.  
  634.         self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First")
  635.         self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ", anchor=W)
  636.         self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first)
  637.  
  638.         self.Label_Rotary_Enable_adv = Label(self.master,text="Use Rotary Settings")
  639.         self.Checkbutton_Rotary_Enable_adv = Checkbutton(self.master,text="")
  640.         self.Checkbutton_Rotary_Enable_adv.configure(variable=self.rotary)
  641.         self.rotary.trace_variable("w", self.Reset_RasterPath_and_Update_Time)
  642.  
  643.  
  644.         #####
  645.         self.separator_comb = Frame(self.master, height=2, bd=1, relief=SUNKEN)  
  646.  
  647.         self.Label_Comb_Engrave_adv = Label(self.master,text="Group Engrave Tasks")
  648.         self.Checkbutton_Comb_Engrave_adv = Checkbutton(self.master,text=" ", anchor=W)
  649.         self.Checkbutton_Comb_Engrave_adv.configure(variable=self.comb_engrave)
  650.         self.comb_engrave.trace_variable("w", self.menu_View_Refresh_Callback)
  651.  
  652.         self.Label_Comb_Vector_adv = Label(self.master,text="Group Vector Tasks")
  653.         self.Checkbutton_Comb_Vector_adv = Checkbutton(self.master,text=" ", anchor=W)
  654.         self.Checkbutton_Comb_Vector_adv.configure(variable=self.comb_vector)
  655.         self.comb_vector.trace_variable("w", self.menu_View_Refresh_Callback)
  656.         #####
  657.        
  658.         self.Label_Reng_passes = Label(self.master,text="Raster Eng. Passes")
  659.         self.Entry_Reng_passes   = Entry(self.master,width="15")
  660.         self.Entry_Reng_passes.configure(textvariable=self.Reng_passes,justify='center',fg="black")
  661.         self.Reng_passes.trace_variable("w", self.Entry_Reng_passes_Callback)
  662.         self.NormalColor =  self.Entry_Reng_passes.cget('bg')
  663.  
  664.         self.Label_Veng_passes = Label(self.master,text="Vector Eng. Passes")
  665.         self.Entry_Veng_passes   = Entry(self.master,width="15")
  666.         self.Entry_Veng_passes.configure(textvariable=self.Veng_passes,justify='center',fg="blue")
  667.         self.Veng_passes.trace_variable("w", self.Entry_Veng_passes_Callback)
  668.         self.NormalColor =  self.Entry_Veng_passes.cget('bg')
  669.  
  670.         self.Label_Vcut_passes = Label(self.master,text="Vector Cut Passes")
  671.         self.Entry_Vcut_passes   = Entry(self.master,width="15")
  672.         self.Entry_Vcut_passes.configure(textvariable=self.Vcut_passes,justify='center',fg="red")
  673.         self.Vcut_passes.trace_variable("w", self.Entry_Vcut_passes_Callback)
  674.         self.NormalColor =  self.Entry_Vcut_passes.cget('bg')
  675.  
  676.         self.Label_Gcde_passes = Label(self.master,text="G-Code Passes")
  677.         self.Entry_Gcde_passes   = Entry(self.master,width="15")
  678.         self.Entry_Gcde_passes.configure(textvariable=self.Gcde_passes,justify='center',fg="black")
  679.         self.Gcde_passes.trace_variable("w", self.Entry_Gcde_passes_Callback)
  680.         self.NormalColor =  self.Entry_Gcde_passes.cget('bg')
  681.  
  682.        
  683.         self.Hide_Adv_Button = Button(self.master,text="Hide Advanced", command=self.Hide_Advanced)
  684.                
  685.         # End Right Column #
  686.         self.calc_button = Button(self.master,text="Calculate Raster Time", command=self.menu_Calc_Raster_Time)
  687.  
  688.         #GEN Setting Window Entry initializations
  689.         self.Entry_Sspeed    = Entry()
  690.         self.Entry_BoxGap    = Entry()
  691.         self.Entry_ContAngle = Entry()
  692.  
  693.         # Make Menu Bar
  694.         self.menuBar = Menu(self.master, relief = "raised", bd=2)
  695.  
  696.        
  697.  
  698.  
  699.         top_File = Menu(self.menuBar, tearoff=0)
  700.         top_File.add("command", label = "Save Settings File", command = self.menu_File_Save)
  701.         top_File.add("command", label = "Read Settings File", command = self.menu_File_Open_Settings_File)
  702.  
  703.         top_File.add_separator()
  704.         top_File.add("command", label = "Open Design (SVG/DXF/G-Code)"  , command = self.menu_File_Open_Design)
  705.         top_File.add("command", label = "Reload Design"          , command = self.menu_Reload_Design)
  706.  
  707.         top_File.add_separator()    
  708.         top_File.add("command", label = "Send EGV File to Laser"             , command = self.menu_File_Open_EGV)
  709.  
  710.         SaveEGVmenu = Menu(self.master, relief = "raised", bd=2, tearoff=0)
  711.         top_File.add_cascade(label="Save EGV File", menu=SaveEGVmenu)        
  712.         SaveEGVmenu.add("command", label = "Raster Engrave"     , command = self.menu_File_Raster_Engrave)
  713.         SaveEGVmenu.add("command", label = "Vector Engrave"     , command = self.menu_File_Vector_Engrave)
  714.         SaveEGVmenu.add("command", label = "Vector Cut"         , command = self.menu_File_Vector_Cut)
  715.         SaveEGVmenu.add("command", label = "G-Code Operations"  , command = self.menu_File_G_Code)
  716.         SaveEGVmenu.add_separator()  
  717.         SaveEGVmenu.add("command", label = "Raster and Vector Engrave"             , command = self.menu_File_Raster_Vector_Engrave)
  718.         SaveEGVmenu.add("command", label = "Vector Engrave and Cut"                , command = self.menu_File_Vector_Engrave_Cut)
  719.         SaveEGVmenu.add("command", label = "Raster, Vector Engrave and Vector Cut" , command = self.menu_File_Raster_Vector_Cut)
  720.        
  721.    
  722.         top_File.add_separator()
  723.         top_File.add("command", label = "Exit"              , command = self.menu_File_Quit)
  724.        
  725.         self.menuBar.add("cascade", label="File", menu=top_File)
  726.  
  727.         #top_Edit = Menu(self.menuBar, tearoff=0)
  728.         #self.menuBar.add("cascade", label="Edit", menu=top_Edit)
  729.  
  730.         top_View = Menu(self.menuBar, tearoff=0)
  731.         top_View.add("command", label = "Refresh   <F5>", command = self.menu_View_Refresh)
  732.         top_View.add_separator()
  733.         top_View.add_checkbutton(label = "Show Raster Image"  ,  variable=self.include_Reng ,command= self.menu_View_Refresh)
  734.         if DEBUG:
  735.             top_View.add_checkbutton(label = "Show Raster Paths" ,variable=self.include_Rpth ,command= self.menu_View_Refresh)
  736.        
  737.         top_View.add_checkbutton(label = "Show Vector Engrave",   variable=self.include_Veng ,command= self.menu_View_Refresh)
  738.         top_View.add_checkbutton(label = "Show Vector Cut"    ,   variable=self.include_Vcut ,command= self.menu_View_Refresh)
  739.         top_View.add_checkbutton(label = "Show G-Code Paths"  ,   variable=self.include_Gcde ,command= self.menu_View_Refresh)
  740.         top_View.add_separator()
  741.         top_View.add_checkbutton(label = "Show Time Estimates",   variable=self.include_Time ,command= self.menu_View_Refresh)
  742.         top_View.add_checkbutton(label = "Zoom to Design Size",   variable=self.zoom2image   ,command= self.menu_View_Refresh)
  743.  
  744.         #top_View.add_separator()
  745.         #top_View.add("command", label = "computeAccurateReng",command= self.computeAccurateReng)
  746.         #top_View.add("command", label = "computeAccurateVeng",command= self.computeAccurateVeng)
  747.         #top_View.add("command", label = "computeAccurateVcut",command= self.computeAccurateVcut)
  748.  
  749.         self.menuBar.add("cascade", label="View", menu=top_View)
  750.  
  751.         top_Tools = Menu(self.menuBar, tearoff=0)
  752.         self.menuBar.add("cascade", label="Tools", menu=top_Tools)
  753.         USBmenu = Menu(self.master, relief = "raised", bd=2, tearoff=0)
  754.          
  755.         top_Tools.add("command", label = "Calculate Raster Time", command = self.menu_Calc_Raster_Time)
  756.         top_Tools.add("command", label = "Trace Design Boundary <Ctrl-t>", command = self.TRACE_Settings_Window)
  757.         top_Tools.add_separator()
  758.         top_Tools.add("command", label = "Initialize Laser <Ctrl-i>", command = self.Initialize_Laser)
  759.         top_Tools.add("command", label = "Unfreeze Laser <Ctrl-f>"  , command = self.Unfreeze_Laser)
  760.         top_Tools.add_cascade(label="USB", menu=USBmenu)
  761.         USBmenu.add("command", label = "Reset USB", command = self.Reset)
  762.         USBmenu.add("command", label = "Release USB", command = self.Release_USB)
  763.  
  764.                    
  765.  
  766.         #top_USB = Menu(self.menuBar, tearoff=0)
  767.         #top_USB.add("command", label = "Reset USB", command = self.Reset)
  768.         #top_USB.add("command", label = "Release USB", command = self.Release_USB)
  769.         #top_USB.add("command", label = "Initialize Laser", command = self.Initialize_Laser)
  770.         #self.menuBar.add("cascade", label="USB", menu=top_USB)
  771.        
  772.  
  773.         top_Settings = Menu(self.menuBar, tearoff=0)
  774.         top_Settings.add("command", label = "General Settings <F2>", command = self.GEN_Settings_Window)
  775.         top_Settings.add("command", label = "Raster Settings <F3>",  command = self.RASTER_Settings_Window)
  776.         top_Settings.add("command", label = "Rotary Settings <F4>",  command = self.ROTARY_Settings_Window)
  777.         top_Settings.add_separator()
  778.         top_Settings.add_checkbutton(label = "Advanced Settings <F6>", variable=self.advanced ,command= self.menu_View_Refresh)
  779.        
  780.         self.menuBar.add("cascade", label="Settings", menu=top_Settings)
  781.        
  782.         top_Help = Menu(self.menuBar, tearoff=0)
  783.         top_Help.add("command", label = "About (e-mail)", command = self.menu_Help_About)
  784.         top_Help.add("command", label = "K40 Whisperer Web Page", command = self.menu_Help_Web)
  785.         top_Help.add("command", label = "Manual (Web Page)", command = self.menu_Help_Manual)
  786.         self.menuBar.add("cascade", label="Help", menu=top_Help)
  787.  
  788.         self.master.config(menu=self.menuBar)
  789.  
  790.         ##########################################################################
  791.         #                  Config File and command line options                  #
  792.         ##########################################################################
  793.         config_file = "k40_whisperer.txt"
  794.         home_config1 = self.HOME_DIR + "/" + config_file
  795.         if ( os.path.isfile(config_file) ):
  796.             self.Open_Settings_File(config_file)
  797.         elif ( os.path.isfile(home_config1) ):
  798.             self.Open_Settings_File(home_config1)
  799. #Lovejoy
  800.         arguments = len(sys.argv) - 1
  801.         if arguments >=1:
  802.         # read commandline arguments, first
  803.             fullCmdArguments = sys.argv
  804.  
  805.         # - further arguments
  806.             argumentList = fullCmdArguments[1:]
  807.         #opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
  808.             unixOptions = "cghHio:rsnvVux:y:"  
  809.             gnuOptions = ["help","go","stop","home","init","open","cut","raster", "vector", "verbose","unlock"]  
  810.  
  811.             try:  
  812.                 arguments, values = getopt.getopt(argumentList, unixOptions, gnuOptions)
  813.             except getopt.error as err:  
  814.             # output error, and return with an error code
  815.                 print (str(err))
  816.                 sys.exit(2)
  817.  
  818.             # evaluate given options
  819.             for currentArgument, currentValue in arguments:  
  820.                 if currentArgument in ("-i", "--init"):
  821.                     print ("initializing the laser")
  822.                     self.Initialize_Laser()
  823.                     #sage()
  824.                     #command=self.Initialize_Laser
  825.                 elif currentArgument in ("-H", "--home"):
  826.                     print ("move to the home position")
  827.                     self.Home()
  828.                 elif currentArgument in ("-h", "--help"):
  829.                     print ("CLI arguments are as follows")
  830.                     print ("-g --go     Starts the job with whatever other arguments")
  831.                     print ("-s --stop   Stops the job, doesnt go home, or un initialize")
  832.                     print ("-H --home   Sends the cutting head to the home [0,0] position")
  833.                     print ("-i --init   Initializes the laser, or prints errors if it fails")
  834.                     print ("-o --open   Requires an SVG file to open")
  835.                     print ("-h --help   Prints this dialog")
  836.                     print ("-c --cut    Tell the laser to cut")
  837.                     print ("-r --raster Raster Engrave")
  838.                     print ("-v --vector Vector Engrave")
  839.                     print ("-V          Verbose mode lo U wish.. I guess I could set debug mode")
  840.                     print ("-u --unlock Unlock the print head")
  841.                     print ("-x <Number> move to X-Cordinate ")
  842.                     print ("-y <Number> move to Y-Cordinate ")
  843.                     print (" ")
  844.                     print (" ")
  845.                     print ("Example Useage: $python k40_whisperer.py -i -H -o c.svg -r ")
  846.                     exit()
  847.                 elif currentArgument in ("-o", "--open"):
  848.                     print (("opening an svg (%s)") % (currentValue))
  849.                     self.Open_SVG(currentValue)
  850.                      #self.Open_SVG(filename)
  851.                     self.send_data("Vector_Cut", currentValue)
  852.                 elif currentArgument in ("-g", "--go"):
  853.                     print ("Start cutting or moving the head")
  854.                     #This option doesn't translate into a direct action like the other functions do.
  855.                 elif currentArgument in ("-s", "--stop"):
  856.                     print ("Stop Cutting::dont check or make a pop up, just stop")
  857.                     self.CLI_Stop()
  858.                     #self.Stop()
  859.                 elif currentArgument in ("-u", "--unlock"):
  860.                     print ("unlocked the print head")
  861.                     self.Unlock()
  862.                 elif currentArgument in ("-c", "cut"):
  863.                     print ("cuts the open svg file")
  864.                     self.Vector_Cut()
  865.                 elif currentArgument in ("-r", "--raster"):
  866.                     print ("raster Engraves the opened file")
  867.                     self.Raster_Eng()
  868.                 elif currentArgument in ("-v", "--vector"):
  869.                     print ("Vector Engraves the opend file")
  870.                     #self.Vector_Eng()
  871.                     output_filename=currentValue
  872.                     self.Vector_Cut()
  873.                     self.send_data("Vector_Cut", output_filename)
  874.                 elif currentArgument in ("-V"):
  875.                     print ("Verbose mode lol u wish, well, there is debug mode")
  876.                     print ("Version 0.19 K40_whisperer source")
  877.                     print ("Version 0.0  K40 CLI source")
  878.                 elif currentArgument in ("x"):
  879.                     print ("Move to X Coordinate " % (currentValue))
  880.                     self.gotoX.set(currentValue)
  881.                     self.GoTo()
  882.                 elif currentArgument in ("y"):
  883.                     print("Move to Y Coordnate %s" % (currentValue))
  884.                     self.gotoY.set(currentValue)
  885.                     self.GoTo()
  886.  
  887.                 else:
  888.                     print ("FOILED! put in some args if you want CLI mode")
  889.                    
  890. #Lovejoy
  891.  
  892. #        opts, args = None, None
  893. #        try:
  894. #            opts, args = getopt.getopt(sys.argv[1:], "ho:",["help", "other_option"])
  895. #        except:
  896. #            debug_message('Unable interpret command line options')
  897. #            sys.exit()
  898. #        for option, value in opts:
  899. ##            if option in ('-h','--help'):
  900. ##                fmessage(' ')
  901. ##                fmessage('Usage: python .py [-g file]')
  902. ##                fmessage('-o    : unknown other option (also --other_option)')
  903. ##                fmessage('-h    : print this help (also --help)\n')
  904. ##                sys.exit()
  905. #            if option in ('-m','--micro'):
  906. #                self.micro = True
  907.  
  908.         ##########################################################################
  909.  
  910. ################################################################################
  911.     def entry_set(self, val2, calc_flag=0, new=0):
  912.         if calc_flag == 0 and new==0:
  913.             try:
  914.                 self.statusbar.configure( bg = 'yellow' )
  915.                 val2.configure( bg = 'yellow' )
  916.                 self.statusMessage.set(" Recalculation required.")
  917.             except:
  918.                 pass
  919.         elif calc_flag == 3:
  920.             try:
  921.                 val2.configure( bg = 'red' )
  922.                 self.statusbar.configure( bg = 'red' )
  923.                 self.statusMessage.set(" Value should be a number. ")
  924.             except:
  925.                 pass
  926.         elif calc_flag == 2:
  927.             try:
  928.                 self.statusbar.configure( bg = 'red' )
  929.                 val2.configure( bg = 'red' )
  930.             except:
  931.                 pass
  932.         elif (calc_flag == 0 or calc_flag == 1) and new==1 :
  933.             try:
  934.                 self.statusbar.configure( bg = 'white' )
  935.                 self.statusMessage.set(" ")
  936.                 val2.configure( bg = 'white' )
  937.             except:
  938.                 pass
  939.         elif (calc_flag == 1) and new==0 :
  940.             try:
  941.                 self.statusbar.configure( bg = 'white' )
  942.                 self.statusMessage.set(" ")
  943.                 val2.configure( bg = 'white' )
  944.             except:
  945.                 pass
  946.  
  947.         elif (calc_flag == 0 or calc_flag == 1) and new==2:
  948.             return 0
  949.         return 1
  950.  
  951. ################################################################################
  952.     def Write_Config_File(self, event):
  953.        
  954.         config_data = self.WriteConfig()
  955.         config_file = "k40_whisperer.txt"
  956.         configname_full = self.HOME_DIR + "/" + config_file
  957.  
  958.         current_name = event.widget.winfo_parent()
  959.         win_id = event.widget.nametowidget(current_name)
  960.  
  961.         if ( os.path.isfile(configname_full) ):
  962.             try:
  963.                 win_id.withdraw()
  964.             except:
  965.                 pass
  966.  
  967.             if not message_ask_ok_cancel("Replace", "Replace Exiting Configuration File?\n"+configname_full):
  968.                 try:
  969.                     win_id.deiconify()
  970.                 except:
  971.                     pass
  972.                 return
  973.         try:
  974.             fout = open(configname_full,'w')
  975.         except:
  976.             self.statusMessage.set("Unable to open file for writing: %s" %(configname_full))
  977.             self.statusbar.configure( bg = 'red' )
  978.             return
  979.         for line in config_data:
  980.             try:
  981.                 fout.write(line+'\n')
  982.             except:
  983.                 fout.write('(skipping line)\n')
  984.         fout.close
  985.         self.statusMessage.set("Configuration File Saved: %s" %(configname_full))
  986.         self.statusbar.configure( bg = 'white' )
  987.         try:
  988.             win_id.deiconify()
  989.         except:
  990.             pass
  991.  
  992.     ################################################################################
  993.     def WriteConfig(self):
  994.         global Zero
  995.         header = []
  996.         header.append('( K40 Whisperer Settings: '+version+' )')
  997.         header.append('( by Scorch - 2019 )')
  998.         header.append("(=========================================================)")
  999.         # BOOL
  1000.         header.append('(k40_whisperer_set include_Reng  %s )'  %( int(self.include_Reng.get())  ))
  1001.         header.append('(k40_whisperer_set include_Veng  %s )'  %( int(self.include_Veng.get())  ))
  1002.         header.append('(k40_whisperer_set include_Vcut  %s )'  %( int(self.include_Vcut.get())  ))
  1003.         header.append('(k40_whisperer_set include_Gcde  %s )'  %( int(self.include_Gcde.get())  ))
  1004.         header.append('(k40_whisperer_set include_Time  %s )'  %( int(self.include_Time.get())  ))
  1005.        
  1006.         header.append('(k40_whisperer_set halftone      %s )'  %( int(self.halftone.get())      ))
  1007.         header.append('(k40_whisperer_set HomeUR        %s )'  %( int(self.HomeUR.get())        ))
  1008.         header.append('(k40_whisperer_set inputCSYS     %s )'  %( int(self.inputCSYS.get())     ))
  1009.         header.append('(k40_whisperer_set advanced      %s )'  %( int(self.advanced.get())      ))
  1010.         header.append('(k40_whisperer_set mirror        %s )'  %( int(self.mirror.get())        ))
  1011.         header.append('(k40_whisperer_set rotate        %s )'  %( int(self.rotate.get())        ))
  1012.         header.append('(k40_whisperer_set negate        %s )'  %( int(self.negate.get())        ))
  1013.        
  1014.         header.append('(k40_whisperer_set engraveUP     %s )'  %( int(self.engraveUP.get())     ))
  1015.         header.append('(k40_whisperer_set init_home     %s )'  %( int(self.init_home.get())     ))
  1016.         header.append('(k40_whisperer_set post_home     %s )'  %( int(self.post_home.get())     ))
  1017.         header.append('(k40_whisperer_set post_beep     %s )'  %( int(self.post_beep.get())     ))
  1018.         header.append('(k40_whisperer_set post_disp     %s )'  %( int(self.post_disp.get())     ))
  1019.         header.append('(k40_whisperer_set post_exec     %s )'  %( int(self.post_exec.get())     ))
  1020.        
  1021.         header.append('(k40_whisperer_set pre_pr_crc    %s )'  %( int(self.pre_pr_crc.get())    ))
  1022.         header.append('(k40_whisperer_set inside_first  %s )'  %( int(self.inside_first.get())  ))
  1023.  
  1024.         header.append('(k40_whisperer_set comb_engrave  %s )'  %( int(self.comb_engrave.get())  ))
  1025.         header.append('(k40_whisperer_set comb_vector   %s )'  %( int(self.comb_vector.get())   ))
  1026.         header.append('(k40_whisperer_set zoom2image    %s )'  %( int(self.zoom2image.get())    ))
  1027.         header.append('(k40_whisperer_set rotary        %s )'  %( int(self.rotary.get())        ))
  1028.         header.append('(k40_whisperer_set reduced_mem   %s )'  %( int(self.reduced_mem.get())   ))
  1029.         header.append('(k40_whisperer_set wait          %s )'  %( int(self.wait.get())          ))
  1030.  
  1031.         header.append('(k40_whisperer_set trace_w_laser %s )'  %( int(self.trace_w_laser.get()) ))
  1032.  
  1033.         # STRING.get()
  1034.         header.append('(k40_whisperer_set board_name    %s )'  %( self.board_name.get()     ))
  1035.         header.append('(k40_whisperer_set units         %s )'  %( self.units.get()          ))
  1036.         header.append('(k40_whisperer_set Reng_feed     %s )'  %( self.Reng_feed.get()      ))
  1037.         header.append('(k40_whisperer_set Veng_feed     %s )'  %( self.Veng_feed.get()      ))
  1038.         header.append('(k40_whisperer_set Vcut_feed     %s )'  %( self.Vcut_feed.get()      ))
  1039.         header.append('(k40_whisperer_set jog_step      %s )'  %( self.jog_step.get()       ))
  1040.  
  1041.         header.append('(k40_whisperer_set Reng_passes   %s )'  %( self.Reng_passes.get()    ))
  1042.         header.append('(k40_whisperer_set Veng_passes   %s )'  %( self.Veng_passes.get()    ))
  1043.         header.append('(k40_whisperer_set Vcut_passes   %s )'  %( self.Vcut_passes.get()    ))
  1044.         header.append('(k40_whisperer_set Gcde_passes   %s )'  %( self.Gcde_passes.get()    ))
  1045.  
  1046.         header.append('(k40_whisperer_set rast_step     %s )'  %( self.rast_step.get()      ))
  1047.         header.append('(k40_whisperer_set ht_size       %s )'  %( self.ht_size.get()        ))
  1048.        
  1049.         header.append('(k40_whisperer_set LaserXsize    %s )'  %( self.LaserXsize.get()     ))
  1050.         header.append('(k40_whisperer_set LaserYsize    %s )'  %( self.LaserYsize.get()     ))
  1051.         header.append('(k40_whisperer_set LaserXscale   %s )'  %( self.LaserXscale.get()    ))
  1052.         header.append('(k40_whisperer_set LaserYscale   %s )'  %( self.LaserYscale.get()    ))
  1053.         header.append('(k40_whisperer_set LaserRscale   %s )'  %( self.LaserRscale.get()    ))
  1054.         header.append('(k40_whisperer_set rapid_feed   %s )'  %( self.rapid_feed.get()      ))
  1055.        
  1056.         header.append('(k40_whisperer_set gotoX         %s )'  %( self.gotoX.get()          ))
  1057.         header.append('(k40_whisperer_set gotoY         %s )'  %( self.gotoY.get()          ))
  1058.  
  1059.         header.append('(k40_whisperer_set bezier_M1     %s )'  %( self.bezier_M1.get()      ))
  1060.         header.append('(k40_whisperer_set bezier_M2     %s )'  %( self.bezier_M2.get()      ))
  1061.         header.append('(k40_whisperer_set bezier_weight %s )'  %( self.bezier_weight.get()  ))
  1062.  
  1063.         header.append('(k40_whisperer_set trace_gap     %s )'  %( self.trace_gap.get()      ))
  1064.         header.append('(k40_whisperer_set trace_speed   %s )'  %( self.trace_speed.get()    ))      
  1065.        
  1066. ##        header.append('(k40_whisperer_set unsharp_flag  %s )'  %( int(self.unsharp_flag.get())  ))
  1067. ##        header.append('(k40_whisperer_set unsharp_r     %s )'  %( self.unsharp_r.get()      ))
  1068. ##        header.append('(k40_whisperer_set unsharp_p     %s )'  %( self.unsharp_p.get()      ))
  1069. ##        header.append('(k40_whisperer_set unsharp_t     %s )'  %( self.unsharp_t.get()      ))
  1070.  
  1071.         header.append('(k40_whisperer_set t_timeout     %s )'  %( self.t_timeout.get()      ))
  1072.         header.append('(k40_whisperer_set n_timeouts    %s )'  %( self.n_timeouts.get()     ))
  1073.  
  1074.         header.append('(k40_whisperer_set ink_timeout   %s )'  %( self.ink_timeout.get()    ))
  1075.  
  1076.        
  1077.         header.append('(k40_whisperer_set designfile    \042%s\042 )' %( self.DESIGN_FILE   ))
  1078.         header.append('(k40_whisperer_set inkscape_path \042%s\042 )' %( self.inkscape_path.get() ))
  1079.         header.append('(k40_whisperer_set batch_path    \042%s\042 )' %( self.batch_path.get() ))
  1080.  
  1081.  
  1082.         self.jog_step
  1083.         header.append("(=========================================================)")
  1084.  
  1085.         return header
  1086.         ######################################################
  1087.  
  1088.     def Quit_Click(self, event):
  1089.         self.statusMessage.set("Exiting!")
  1090.         self.Release_USB
  1091.         root.destroy()
  1092.  
  1093.     def mousePanStart(self,event):
  1094.         self.panx = event.x
  1095.         self.pany = event.y
  1096.         self.move_start_x = event.x
  1097.         self.move_start_y = event.y
  1098.        
  1099.     def mousePan(self,event):
  1100.         all = self.PreviewCanvas.find_all()
  1101.         dx = event.x-self.panx
  1102.         dy = event.y-self.pany
  1103.  
  1104.         self.PreviewCanvas.move('LaserTag', dx, dy)
  1105.         self.lastx = self.lastx + dx
  1106.         self.lasty = self.lasty + dy
  1107.         self.panx = event.x
  1108.         self.pany = event.y
  1109.        
  1110.     def mousePanStop(self,event):
  1111.         Xold = round(self.laserX,3)
  1112.         Yold = round(self.laserY,3)
  1113.  
  1114.         can_dx = event.x-self.move_start_x
  1115.         can_dy = -(event.y-self.move_start_y)
  1116.        
  1117.         dx = can_dx*self.PlotScale
  1118.         dy = can_dy*self.PlotScale
  1119.         if self.HomeUR.get():
  1120.             dx = -dx
  1121.         self.laserX,self.laserY = self.XY_in_bounds(dx,dy)
  1122.         DXmils = round((self.laserX - Xold)*1000.0,0)
  1123.         DYmils = round((self.laserY - Yold)*1000.0,0)
  1124.        
  1125.         if self.Send_Rapid_Move(DXmils,DYmils):
  1126.             self.menu_View_Refresh()
  1127.  
  1128.     def right_mousePanStart(self,event):
  1129.         self.s_panx = event.x
  1130.         self.s_pany = event.y
  1131.         self.s_move_start_x = event.x
  1132.         self.s_move_start_y = event.y
  1133.        
  1134.     def right_mousePan(self,event):
  1135.         all = self.PreviewCanvas.find_all()
  1136.         dx = event.x-self.s_panx
  1137.         dy = event.y-self.s_pany
  1138.  
  1139.         self.PreviewCanvas.move('LaserDot', dx, dy)
  1140.         self.s_lastx = self.lastx + dx
  1141.         self.s_lasty = self.lasty + dy
  1142.         self.s_panx = event.x
  1143.         self.s_pany = event.y
  1144.        
  1145.     def right_mousePanStop(self,event):
  1146.         Xold = round(self.laserX,3)
  1147.         Yold = round(self.laserY,3)
  1148.         can_dx =   event.x-self.s_move_start_x
  1149.         can_dy = -(event.y-self.s_move_start_y)
  1150.        
  1151.         dx = can_dx*self.PlotScale
  1152.         dy = can_dy*self.PlotScale
  1153.            
  1154.         DX =  round(dx*1000)
  1155.         DY =  round(dy*1000)
  1156.         self.Move_Arbitrary(DX,DY)
  1157.         self.menu_View_Refresh()
  1158.  
  1159.     def LASER_Size(self):
  1160.         MINX = 0.0
  1161.         MAXY = 0.0
  1162.         if self.units.get()=="in":
  1163.             MAXX =  float(self.LaserXsize.get())
  1164.             MINY = -float(self.LaserYsize.get())
  1165.         else:
  1166.             MAXX =  float(self.LaserXsize.get())/25.4
  1167.             MINY = -float(self.LaserYsize.get())/25.4
  1168.  
  1169.         return (MAXX-MINX,MAXY-MINY)
  1170.  
  1171.  
  1172.     def XY_in_bounds(self,dx_inches,dy_inches, no_size=False):
  1173.         MINX = 0.0
  1174.         MAXY = 0.0
  1175.         if self.units.get()=="in":
  1176.             MAXX =  float(self.LaserXsize.get())
  1177.             MINY = -float(self.LaserYsize.get())
  1178.         else:
  1179.             MAXX =  float(self.LaserXsize.get())/25.4
  1180.             MINY = -float(self.LaserYsize.get())/25.4
  1181.  
  1182.         if (self.inputCSYS.get() and self.RengData.image == None) or no_size:
  1183.             xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  1184.         else:
  1185.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  1186.        
  1187.         X = self.laserX + dx_inches
  1188.         Y = self.laserY + dy_inches
  1189.         ################
  1190.         dx=xmax-xmin
  1191.         dy=ymax-ymin
  1192.         if X < MINX:
  1193.             X = MINX
  1194.         if X+dx > MAXX:
  1195.             X = MAXX-dx
  1196.            
  1197.         if Y-dy < MINY:
  1198.             Y = MINY+dy
  1199.         if Y > MAXY:
  1200.             Y = MAXY
  1201.         ################
  1202.         if not no_size:
  1203.             XOFF = self.pos_offset[0]/1000.0
  1204.             YOFF = self.pos_offset[1]/1000.0
  1205.             if X+XOFF < MINX:
  1206.                 X= X +(MINX-(X+XOFF))
  1207.             if X+XOFF > MAXX:
  1208.                 X= X -((X+XOFF)-MAXX)
  1209.             if Y+YOFF < MINY:
  1210.                 Y= Y + (MINY-(Y+YOFF))
  1211.             if Y+YOFF > MAXY:
  1212.                 Y= Y -((Y+YOFF)-MAXY)
  1213.         ################
  1214.         X = round(X,3)
  1215.         Y = round(Y,3)
  1216.         return X,Y
  1217.  
  1218. ##    def computeAccurateVeng(self):
  1219. ##        self.update_gui("Optimize vector engrave.")
  1220. ##        self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords),data_sorted=True)
  1221. ##        self.refreshTime()
  1222. ##            
  1223. ##    def computeAccurateVcut(self):
  1224. ##        self.update_gui("Optimize vector cut.")
  1225. ##        self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True)
  1226. ##        self.refreshTime()
  1227. ##
  1228. ##    def computeAccurateReng(self):
  1229. ##        self.update_gui("Calculating Raster engrave.")
  1230. ##        if self.RengData.image != None:        
  1231. ##            if self.RengData.ecoords == []:
  1232. ##                self.make_raster_coords()
  1233. ##        self.RengData.sorted = True
  1234. ##        self.refreshTime()
  1235.  
  1236.  
  1237.     def format_time(self,time_in_seconds):
  1238.         # format the duration from seconds to something human readable
  1239.         if time_in_seconds !=None and time_in_seconds >=0 :
  1240.             s = round(time_in_seconds)
  1241.             m,s=divmod(s,60)
  1242.             h,m=divmod(m,60)
  1243.             res = ""
  1244.             if h > 0:
  1245.                 res =  "%dh " %(h)
  1246.             if m > 0:
  1247.                 res += "%dm " %(m)
  1248.             if h == 0:
  1249.                 res += "%ds " %(s)
  1250.             #L=len(res)
  1251.             #for i in range(L,8):
  1252.             #    res =  res+" "
  1253.             return res
  1254.         else :
  1255.             return "?"
  1256.  
  1257.     def refreshTime(self):
  1258.         if not self.include_Time.get():
  1259.             return
  1260.         if self.units.get() == 'in':
  1261.             factor =  60.0
  1262.         else :
  1263.             factor = 25.4
  1264.  
  1265.         Raster_eng_feed = float(self.Reng_feed.get()) / factor
  1266.         Vector_eng_feed = float(self.Veng_feed.get()) / factor
  1267.         Vector_cut_feed = float(self.Vcut_feed.get()) / factor
  1268.        
  1269.         Raster_eng_passes = float(self.Reng_passes.get())
  1270.         Vector_eng_passes = float(self.Veng_passes.get())
  1271.         Vector_cut_passes = float(self.Vcut_passes.get())
  1272.         Gcode_passes      = float(self.Gcde_passes.get())
  1273.  
  1274.         rapid_feed = 100.0 / 25.4   # 100 mm/s move feed to be confirmed
  1275.  
  1276.         if self.RengData.rpaths:
  1277.             Reng_time=0
  1278.         else:
  1279.             Reng_time  = None
  1280.         Veng_time  = 0
  1281.         Vcut_time  = 0
  1282.        
  1283.         if self.RengData.len!=None:
  1284.             # these equations are a terrible hack based on measured raster engraving times
  1285.             # to be fixed someday
  1286.             if Raster_eng_feed*60.0 <= 300:
  1287.                 accel_time=8.3264*(Raster_eng_feed*60.0)**(-0.7451)
  1288.             else:
  1289.                 accel_time=2.5913*(Raster_eng_feed*60.0)**(-0.4795)
  1290.                
  1291.             t_accel = self.RengData.n_scanlines * accel_time
  1292.             Reng_time  =  ( (self.RengData.len)/Raster_eng_feed ) * Raster_eng_passes + t_accel
  1293.         if self.VengData.len!=None:
  1294.             Veng_time  =  (self.VengData.len / Vector_eng_feed + self.VengData.move / rapid_feed) * Vector_eng_passes
  1295.         if self.VcutData.len!=None:
  1296.             Vcut_time  =  (self.VcutData.len / Vector_cut_feed + self.VcutData.move / rapid_feed) * Vector_cut_passes
  1297.            
  1298.         Gcode_time =  self.GcodeData.gcode_time * Gcode_passes
  1299.  
  1300.         self.Reng_time.set("Raster Engrave: %s" %(self.format_time(Reng_time)))  
  1301.         self.Veng_time.set("Vector Engrave: %s" %(self.format_time(Veng_time)))
  1302.         self.Vcut_time.set("    Vector Cut: %s" %(self.format_time(Vcut_time)))
  1303.         self.Gcde_time.set("         Gcode: %s" %(self.format_time(Gcode_time)))
  1304.        
  1305.         ##########################################
  1306.         cszw = int(self.PreviewCanvas.cget("width"))
  1307.         cszh = int(self.PreviewCanvas.cget("height"))
  1308.         HUD_vspace = 15
  1309.         HUD_X = cszw-5
  1310.         HUD_Y = cszh-5
  1311.  
  1312.         w = int(self.master.winfo_width())
  1313.         h = int(self.master.winfo_height())
  1314.         HUD_X2 = w-20
  1315.         HUD_Y2 = h-75
  1316.        
  1317.         self.PreviewCanvas.delete("HUD")
  1318.         self.calc_button.place_forget()
  1319.        
  1320.         if self.GcodeData.ecoords == []:
  1321.             self.PreviewCanvas.create_text(HUD_X, HUD_Y             , fill = "red"  ,text =self.Vcut_time.get(), anchor="se",tags="HUD")
  1322.             self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace  , fill = "blue" ,text =self.Veng_time.get(), anchor="se",tags="HUD")
  1323.            
  1324.             if (Reng_time==None):
  1325.                 #try:
  1326.                 #    self.calc_button.place_forget()
  1327.                 #except:
  1328.                 #    pass
  1329.                 #self.calc_button = Button(self.master,text="Calculate Raster Time", command=self.menu_Calc_Raster_Time)
  1330.                 self.calc_button.place(x=HUD_X2, y=HUD_Y2, width=120+20, height=17, anchor="se")  
  1331.             else:
  1332.                 self.calc_button.place_forget()
  1333.                 self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace*2, fill = "black",
  1334.                                                text =self.Reng_time.get(), anchor="se",tags="HUD")          
  1335.         else:
  1336.             self.PreviewCanvas.create_text(HUD_X, HUD_Y, fill = "black",text =self.Gcde_time.get(), anchor="se",tags="HUD")
  1337.         ##########################################
  1338.  
  1339.  
  1340.     def Settings_ReLoad_Click(self, event):
  1341.         win_id=self.grab_current()
  1342.  
  1343.     def Close_Current_Window_Click(self,event=None):
  1344.         current_name = event.widget.winfo_parent()
  1345.         win_id = event.widget.nametowidget(current_name)
  1346.         win_id.destroy()
  1347.        
  1348.     # Left Column #
  1349.     #############################
  1350.     def Entry_Reng_feed_Check(self):
  1351.         try:
  1352.             value = float(self.Reng_feed.get())
  1353.             vfactor=(25.4/60.0)/self.feed_factor()
  1354.             low_limit = self.min_raster_speed*vfactor
  1355.             if  value < low_limit:
  1356.                 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
  1357.                 return 2 # Value is invalid number
  1358.         except:
  1359.             return 3     # Value not a number
  1360.         self.refreshTime()
  1361.         return 0         # Value is a valid number
  1362.     def Entry_Reng_feed_Callback(self, varName, index, mode):
  1363.         self.entry_set(self.Entry_Reng_feed, self.Entry_Reng_feed_Check(), new=1)        
  1364.     #############################
  1365.     def Entry_Veng_feed_Check(self):
  1366.         try:
  1367.             value = float(self.Veng_feed.get())
  1368.             vfactor=(25.4/60.0)/self.feed_factor()
  1369.             low_limit = self.min_vector_speed*vfactor
  1370.             if  value < low_limit:
  1371.                 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
  1372.                 return 2 # Value is invalid number
  1373.         except:
  1374.             return 3     # Value not a number
  1375.         self.refreshTime()
  1376.         return 0         # Value is a valid number
  1377.     def Entry_Veng_feed_Callback(self, varName, index, mode):
  1378.         self.entry_set(self.Entry_Veng_feed, self.Entry_Veng_feed_Check(), new=1)
  1379.     #############################
  1380.     def Entry_Vcut_feed_Check(self):
  1381.         try:
  1382.             value = float(self.Vcut_feed.get())
  1383.             vfactor=(25.4/60.0)/self.feed_factor()
  1384.             low_limit = self.min_vector_speed*vfactor
  1385.             if  value < low_limit:
  1386.                 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
  1387.                 return 2 # Value is invalid number
  1388.         except:
  1389.             return 3     # Value not a number
  1390.         self.refreshTime()
  1391.         return 0         # Value is a valid number
  1392.     def Entry_Vcut_feed_Callback(self, varName, index, mode):
  1393.         self.entry_set(self.Entry_Vcut_feed, self.Entry_Vcut_feed_Check(), new=1)
  1394.        
  1395.     #############################
  1396.     def Entry_Step_Check(self):
  1397.         try:
  1398.             value = float(self.jog_step.get())
  1399.             if  value <= 0.0:
  1400.                 self.statusMessage.set(" Step should be greater than 0.0 ")
  1401.                 return 2 # Value is invalid number
  1402.         except:
  1403.             return 3     # Value not a number
  1404.         return 0         # Value is a valid number
  1405.     def Entry_Step_Callback(self, varName, index, mode):
  1406.         self.entry_set(self.Entry_Step, self.Entry_Step_Check(), new=1)
  1407.  
  1408.  
  1409.     #############################
  1410.     def Entry_GoToX_Check(self):
  1411.         try:
  1412.             value = float(self.gotoX.get())
  1413.             if  (value < 0.0) and (not self.HomeUR.get()):
  1414.                 self.statusMessage.set(" Value should be greater than 0.0 ")
  1415.                 return 2 # Value is invalid number
  1416.             elif (value > 0.0) and self.HomeUR.get():
  1417.                 self.statusMessage.set(" Value should be less than 0.0 ")
  1418.                 return 2 # Value is invalid number
  1419.         except:
  1420.             return 3     # Value not a number
  1421.         return 0         # Value is a valid number
  1422.     def Entry_GoToX_Callback(self, varName, index, mode):
  1423.         self.entry_set(self.Entry_GoToX, self.Entry_GoToX_Check(), new=1)
  1424.  
  1425.     #############################
  1426.     def Entry_GoToY_Check(self):
  1427.         try:
  1428.             value = float(self.gotoY.get())
  1429.             if  value > 0.0:
  1430.                 self.statusMessage.set(" Value should be less than 0.0 ")
  1431.                 return 2 # Value is invalid number
  1432.         except:
  1433.             return 3     # Value not a number
  1434.         return 0         # Value is a valid number
  1435.     def Entry_GoToY_Callback(self, varName, index, mode):
  1436.         self.entry_set(self.Entry_GoToY, self.Entry_GoToY_Check(), new=1)
  1437.        
  1438.     #############################
  1439.     def Entry_Rstep_Check(self):
  1440.         try:
  1441.             value = self.get_raster_step_1000in()
  1442.             if  value <= 0 or value > 63:
  1443.                 self.statusMessage.set(" Step should be between 0.001 and 0.063 in")
  1444.                 return 2 # Value is invalid number
  1445.         except:
  1446.             return 3     # Value not a number
  1447.         return 0         # Value is a valid number
  1448.     def Entry_Rstep_Callback(self, varName, index, mode):
  1449.         self.RengData.reset_path()
  1450.         self.refreshTime()
  1451.         self.entry_set(self.Entry_Rstep, self.Entry_Rstep_Check(), new=1)
  1452.  
  1453. ##    #############################
  1454. ##    def Entry_Unsharp_Radius_Check(self):
  1455. ##        try:
  1456. ##            value = float(self.unsharp_r.get())
  1457. ##            if  value <= 0:
  1458. ##                self.statusMessage.set(" Radius should be greater than zero.")
  1459. ##                return 2 # Value is invalid number
  1460. ##        except:
  1461. ##            return 3     # Value not a number
  1462. ##        self.menu_View_Refresh_Callback()
  1463. ##        return 0         # Value is a valid number
  1464. ##    def Entry_Unsharp_Radius_Callback(self, varName, index, mode):
  1465. ##        self.entry_set(self.Entry_Unsharp_Radius, self.Entry_Unsharp_Radius_Check(), new=1)
  1466. ##        
  1467. ##
  1468. ##    #############################
  1469. ##    def Entry_Unsharp_Percent_Check(self):
  1470. ##        try:
  1471. ##            value = float(self.unsharp_p.get())
  1472. ##            if  value <= 0:
  1473. ##                self.statusMessage.set(" Percent should be greater than zero.")
  1474. ##                return 2 # Value is invalid number
  1475. ##        except:
  1476. ##            return 3     # Value not a number
  1477. ##        self.menu_View_Refresh_Callback()
  1478. ##        return 0         # Value is a valid number
  1479. ##    def Entry_Unsharp_Percent_Callback(self, varName, index, mode):
  1480. ##        self.entry_set(self.Entry_Unsharp_Percent, self.Entry_Unsharp_Percent_Check(), new=1)
  1481. ##        
  1482. ##    #############################
  1483. ##    def Entry_Unsharp_Threshold_Check(self):
  1484. ##        try:
  1485. ##            value = float(self.unsharp_t.get())
  1486. ##            if  value < 0:
  1487. ##                self.statusMessage.set(" Threshold should be greater than or equal to zero.")
  1488. ##                return 2 # Value is invalid number
  1489. ##        except:
  1490. ##            return 3     # Value not a number
  1491. ##        self.menu_View_Refresh_Callback()
  1492. ##        return 0         # Value is a valid number
  1493. ##    def Entry_Unsharp_Threshold_Callback(self, varName, index, mode):
  1494. ##        self.entry_set(self.Entry_Unsharp_Threshold, self.Entry_Unsharp_Threshold_Check(), new=1)
  1495.  
  1496.     #############################
  1497.     # End Left Column #
  1498.     #############################
  1499.     def bezier_weight_Callback(self, varName=None, index=None, mode=None):
  1500.         self.Reset_RasterPath_and_Update_Time()
  1501.         self.bezier_plot()
  1502.        
  1503.     def bezier_M1_Callback(self, varName=None, index=None, mode=None):
  1504.         self.Reset_RasterPath_and_Update_Time()
  1505.         self.bezier_plot()
  1506.  
  1507.     def bezier_M2_Callback(self, varName=None, index=None, mode=None):
  1508.         self.Reset_RasterPath_and_Update_Time()
  1509.         self.bezier_plot()
  1510.  
  1511.     def bezier_plot(self):
  1512.         self.BezierCanvas.delete('bez')
  1513.  
  1514.         #self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="black", capstyle="round", width = 2, tags='bez')
  1515.         M1 = float(self.bezier_M1.get())
  1516.         M2 = float(self.bezier_M2.get())
  1517.         w  = float(self.bezier_weight.get())
  1518.         num = 10
  1519.         x,y = self.generate_bezier(M1,M2,w,n=num)
  1520.         for i in range(0,num):
  1521.             self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="black", \
  1522.                                            capstyle="round", width = 2, tags='bez')
  1523.         self.BezierCanvas.create_text(128, 0, text="Output Level vs. Input Level",anchor="n", tags='bez')
  1524.  
  1525.  
  1526.     #############################
  1527.     def Entry_Ink_Timeout_Check(self):
  1528.         try:
  1529.             value = float(self.ink_timeout.get())
  1530.             if  value < 0.0:
  1531.                 self.statusMessage.set(" Timeout should be 0 or greater")
  1532.                 return 2 # Value is invalid number
  1533.         except:
  1534.             return 3     # Value not a number
  1535.         return 0         # Value is a valid number
  1536.     def Entry_Ink_Timeout_Callback(self, varName, index, mode):
  1537.         self.entry_set(self.Entry_Ink_Timeout,self.Entry_Ink_Timeout_Check(), new=1)
  1538.        
  1539.      
  1540.     #############################
  1541.     def Entry_Timeout_Check(self):
  1542.         try:
  1543.             value = float(self.t_timeout.get())
  1544.             if  value <= 0.0:
  1545.                 self.statusMessage.set(" Timeout should be greater than 0 ")
  1546.                 return 2 # Value is invalid number
  1547.         except:
  1548.             return 3     # Value not a number
  1549.         return 0         # Value is a valid number
  1550.     def Entry_Timeout_Callback(self, varName, index, mode):
  1551.         self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(), new=1)
  1552.  
  1553.     #############################
  1554.     def Entry_N_Timeouts_Check(self):
  1555.         try:
  1556.             value = float(self.n_timeouts.get())
  1557.             if  value <= 0.0:
  1558.                 self.statusMessage.set(" N_Timeouts should be greater than 0 ")
  1559.                 return 2 # Value is invalid number
  1560.         except:
  1561.             return 3     # Value not a number
  1562.         return 0         # Value is a valid number
  1563.     def Entry_N_Timeouts_Callback(self, varName, index, mode):
  1564.         self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(), new=1)
  1565.    
  1566.     #############################
  1567.     def Entry_N_EGV_Passes_Check(self):
  1568.         try:
  1569.             value = int(self.n_egv_passes.get())
  1570.             if  value < 1:
  1571.                 self.statusMessage.set(" EGV passes should be 1 or higher")
  1572.                 return 2 # Value is invalid number
  1573.         except:
  1574.             return 3     # Value not a number
  1575.         return 0         # Value is a valid number
  1576.     def Entry_N_EGV_Passes_Callback(self, varName, index, mode):
  1577.         self.entry_set(self.Entry_N_EGV_Passes,self.Entry_N_EGV_Passes_Check(), new=1)
  1578.        
  1579.     #############################
  1580.     def Entry_Laser_Area_Width_Check(self):
  1581.         try:
  1582.             value = float(self.LaserXsize.get())
  1583.             if  value <= 0.0:
  1584.                 self.statusMessage.set(" Width should be greater than 0 ")
  1585.                 return 2 # Value is invalid number
  1586.         except:
  1587.             return 3     # Value not a number
  1588.         return 0         # Value is a valid number
  1589.     def Entry_Laser_Area_Width_Callback(self, varName, index, mode):
  1590.         self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(), new=1)
  1591.  
  1592.     #############################
  1593.     def Entry_Laser_Area_Height_Check(self):
  1594.         try:
  1595.             value = float(self.LaserYsize.get())
  1596.             if  value <= 0.0:
  1597.                 self.statusMessage.set(" Height should be greater than 0 ")
  1598.                 return 2 # Value is invalid number
  1599.         except:
  1600.             return 3     # Value not a number
  1601.         return 0         # Value is a valid number
  1602.     def Entry_Laser_Area_Height_Callback(self, varName, index, mode):
  1603.         self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(), new=1)
  1604.  
  1605.  
  1606.     #############################
  1607.     def Entry_Laser_X_Scale_Check(self):
  1608.         try:
  1609.             value = float(self.LaserXscale.get())
  1610.             if  value <= 0.0:
  1611.                 self.statusMessage.set(" X scale factor should be greater than 0 ")
  1612.                 return 2 # Value is invalid number
  1613.         except:
  1614.             return 3     # Value not a number
  1615.         self.Reset_RasterPath_and_Update_Time()
  1616.         return 0         # Value is a valid number
  1617.     def Entry_Laser_X_Scale_Callback(self, varName, index, mode):
  1618.         self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(), new=1)
  1619.     #############################
  1620.     def Entry_Laser_Y_Scale_Check(self):
  1621.         try:
  1622.             value = float(self.LaserYscale.get())
  1623.             if  value <= 0.0:
  1624.                 self.statusMessage.set(" Y scale factor should be greater than 0 ")
  1625.                 return 2 # Value is invalid number
  1626.         except:
  1627.             return 3     # Value not a number
  1628.         self.Reset_RasterPath_and_Update_Time()
  1629.         return 0         # Value is a valid number
  1630.     def Entry_Laser_Y_Scale_Callback(self, varName, index, mode):
  1631.         self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(), new=1)
  1632.  
  1633.     #############################
  1634.     def Entry_Laser_R_Scale_Check(self):
  1635.         try:
  1636.             value = float(self.LaserRscale.get())
  1637.             if  value <= 0.0:
  1638.                 self.statusMessage.set(" Rotary scale factor should be greater than 0 ")
  1639.                 return 2 # Value is invalid number
  1640.         except:
  1641.             return 3     # Value not a number
  1642.         self.Reset_RasterPath_and_Update_Time()
  1643.         return 0         # Value is a valid number
  1644.     def Entry_Laser_R_Scale_Callback(self, varName, index, mode):
  1645.         self.entry_set(self.Entry_Laser_R_Scale,self.Entry_Laser_R_Scale_Check(), new=1)
  1646.        
  1647.     #############################
  1648.     def Entry_Laser_Rapid_Feed_Check(self):
  1649.         try:
  1650.             value = float(self.rapid_feed.get())
  1651.             vfactor=(25.4/60.0)/self.feed_factor()
  1652.             low_limit = 1.0*vfactor
  1653.             if  value !=0 and value < low_limit:
  1654.                 self.statusMessage.set(" Rapid feed should be greater than or equal to %f (or 0 for default speed) " %(low_limit))
  1655.                 return 2 # Value is invalid number
  1656.         except:
  1657.             return 3     # Value not a number
  1658.         return 0         # Value is a valid number
  1659.     def Entry_Laser_Rapid_Feed_Callback(self, varName, index, mode):
  1660.         self.entry_set(self.Entry_Laser_Rapid_Feed,self.Entry_Laser_Rapid_Feed_Check(), new=1)
  1661.  
  1662.     # Advanced Column #
  1663.     #############################
  1664.     def Entry_Reng_passes_Check(self):
  1665.         try:
  1666.             value = int(self.Reng_passes.get())
  1667.             if  value < 1:
  1668.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1669.                 return 2 # Value is invalid number
  1670.         except:
  1671.             return 3     # Value not a number
  1672.         self.refreshTime()
  1673.         return 0         # Value is a valid number
  1674.     def Entry_Reng_passes_Callback(self, varName, index, mode):
  1675.         self.entry_set(self.Entry_Reng_passes, self.Entry_Reng_passes_Check(), new=1)        
  1676.     #############################
  1677.     def Entry_Veng_passes_Check(self):
  1678.         try:
  1679.             value = int(self.Veng_passes.get())
  1680.             if  value < 1:
  1681.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1682.                 return 2 # Value is invalid number
  1683.         except:
  1684.             return 3     # Value not a number
  1685.         self.refreshTime()
  1686.         return 0         # Value is a valid number
  1687.     def Entry_Veng_passes_Callback(self, varName, index, mode):
  1688.         self.entry_set(self.Entry_Veng_passes, self.Entry_Veng_passes_Check(), new=1)
  1689.     #############################
  1690.     def Entry_Vcut_passes_Check(self):
  1691.         try:
  1692.             value = int(self.Vcut_passes.get())
  1693.             if  value < 1:
  1694.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1695.                 return 2 # Value is invalid number
  1696.         except:
  1697.             return 3     # Value not a number
  1698.         self.refreshTime()
  1699.         return 0         # Value is a valid number
  1700.     def Entry_Vcut_passes_Callback(self, varName, index, mode):
  1701.         self.entry_set(self.Entry_Vcut_passes, self.Entry_Vcut_passes_Check(), new=1)
  1702.        
  1703.     #############################
  1704.     def Entry_Gcde_passes_Check(self):
  1705.         try:
  1706.             value = int(self.Gcde_passes.get())
  1707.             if  value < 1:
  1708.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1709.                 return 2 # Value is invalid number
  1710.         except:
  1711.             return 3     # Value not a number
  1712.         self.refreshTime()
  1713.         return 0         # Value is a valid number
  1714.     def Entry_Gcde_passes_Callback(self, varName, index, mode):
  1715.         self.entry_set(self.Entry_Gcde_passes, self.Entry_Gcde_passes_Check(), new=1)
  1716.        
  1717.     #############################
  1718.  
  1719.     def Entry_Trace_Gap_Check(self):
  1720.         try:
  1721.             value = float(self.trace_gap.get())
  1722.         except:
  1723.             return 3     # Value not a number
  1724.         self.menu_View_Refresh()
  1725.         return 0         # Value is a valid number
  1726.     def Entry_Trace_Gap_Callback(self, varName, index, mode):
  1727.         self.entry_set(self.Entry_Trace_Gap, self.Entry_Trace_Gap_Check(), new=1)
  1728.        
  1729.     #############################
  1730.  
  1731.     def Entry_Trace_Speed_Check(self):
  1732.         try:
  1733.             value = float(self.trace_speed.get())
  1734.             vfactor=(25.4/60.0)/self.feed_factor()
  1735.             low_limit = self.min_vector_speed*vfactor
  1736.             if  value < low_limit:
  1737.                 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit))
  1738.                 return 2 # Value is invalid number
  1739.         except:
  1740.             return 3     # Value not a number
  1741.         self.refreshTime()
  1742.         return 0         # Value is a valid number
  1743.     def Entry_Trace_Speed_Callback(self, varName, index, mode):
  1744.         self.entry_set(self.Entry_Trace_Speed, self.Entry_Trace_Speed_Check(), new=1)
  1745.        
  1746.     #############################
  1747.     def Inkscape_Path_Click(self, event):
  1748.         self.Inkscape_Path_Message()
  1749.         win_id=self.grab_current()
  1750.         newfontdir = askopenfilename(filetypes=[("Executable Files",("inkscape.exe","*inkscape*")),\
  1751.                                                 ("All Files","*")],\
  1752.                                                  initialdir=self.inkscape_path.get())
  1753.         if newfontdir != "" and newfontdir != ():
  1754.             if type(newfontdir) is not str:
  1755.                 newfontdir = newfontdir.encode("utf-8")
  1756.             self.inkscape_path.set(newfontdir)
  1757.            
  1758.         try:
  1759.             win_id.withdraw()
  1760.             win_id.deiconify()
  1761.         except:
  1762.             pass
  1763.  
  1764.     def Inkscape_Path_Message(self, event=None):
  1765.         if self.inkscape_warning == False:
  1766.             self.inkscape_warning = True
  1767.             msg1 = "Beware:"
  1768.             msg2 = "Most people should leave the 'Inkscape Executable' entry field blank. "
  1769.             msg3 = "K40 Whisperer will find Inkscape in one of the the standard locations after you install Inkscape."
  1770.             message_box(msg1, msg2+msg3)
  1771.            
  1772.            
  1773.     def Entry_units_var_Callback(self):
  1774.         if (self.units.get() == 'in') and (self.funits.get()=='mm/s'):
  1775.             self.funits.set('in/min')
  1776.             self.Scale_Linear_Inputs('in')
  1777.         elif (self.units.get() == 'mm') and (self.funits.get()=='in/min'):
  1778.             self.funits.set('mm/s')
  1779.             self.Scale_Linear_Inputs('mm')
  1780.            
  1781.     def Scale_Linear_Inputs(self, new_units=None):
  1782.         if new_units=='in':
  1783.             self.units_scale = 1.0
  1784.             factor  = 1/25.4
  1785.             vfactor = 60.0/25.4
  1786.         elif new_units=='mm':
  1787.             factor  = 25.4
  1788.             vfactor = 25.4/60.0
  1789.             self.units_scale = 25.4
  1790.         else:
  1791.             return
  1792.         self.LaserXsize.set ( self.Scale_Text_Value('%.2f',self.LaserXsize.get()  ,factor ) )
  1793.         self.LaserYsize.set ( self.Scale_Text_Value('%.2f',self.LaserYsize.get()  ,factor ) )
  1794.         self.jog_step.set   ( self.Scale_Text_Value('%.3f',self.jog_step.get()    ,factor ) )
  1795.         self.gotoX.set      ( self.Scale_Text_Value('%.3f',self.gotoX.get()       ,factor ) )
  1796.         self.gotoY.set      ( self.Scale_Text_Value('%.3f',self.gotoY.get()       ,factor ) )
  1797.         self.Reng_feed.set  ( self.Scale_Text_Value('%.1f',self.Reng_feed.get()   ,vfactor) )
  1798.         self.Veng_feed.set  ( self.Scale_Text_Value('%.1f',self.Veng_feed.get()   ,vfactor) )
  1799.         self.Vcut_feed.set  ( self.Scale_Text_Value('%.1f',self.Vcut_feed.get()   ,vfactor) )
  1800.         self.trace_speed.set( self.Scale_Text_Value('%.1f',self.trace_speed.get() ,vfactor) )
  1801.         self.rapid_feed.set ( self.Scale_Text_Value('%.1f',self.rapid_feed.get()  ,vfactor) )
  1802.  
  1803.     def Scale_Text_Value(self,format_txt,Text_Value,factor):
  1804.         try:
  1805.             return format_txt %(float(Text_Value)*factor )
  1806.         except:
  1807.             return ''
  1808.  
  1809.     def menu_File_Open_Settings_File(self,event=None):
  1810.         init_dir = os.path.dirname(self.DESIGN_FILE)
  1811.         if ( not os.path.isdir(init_dir) ):
  1812.             init_dir = self.HOME_DIR
  1813.         fileselect = askopenfilename(filetypes=[("Settings Files","*.txt"),\
  1814.                                                 ("All Files","*")],\
  1815.                                                  initialdir=init_dir)
  1816.         if fileselect != '' and fileselect != ():
  1817.             self.Open_Settings_File(fileselect)
  1818.  
  1819.     def Reduced_Memory_Callback(self, varName, index, mode):
  1820.         if self.RengData.image != None:
  1821.              self.menu_Reload_Design()
  1822.              #print("Reload_Design")
  1823.    
  1824.     def menu_Reload_Design(self,event=None):
  1825.         if self.GUI_Disabled:
  1826.             return
  1827.         file_full = self.DESIGN_FILE
  1828.         file_name = os.path.basename(file_full)
  1829.         if ( os.path.isfile(file_full) ):
  1830.             filename = file_full
  1831.         elif ( os.path.isfile( file_name ) ):
  1832.             filename = file_name
  1833.         elif ( os.path.isfile( self.HOME_DIR+"/"+file_name ) ):
  1834.             filename = self.HOME_DIR+"/"+file_name
  1835.         else:
  1836.             self.statusMessage.set("file not found: %s" %(os.path.basename(file_full)) )
  1837.             self.statusbar.configure( bg = 'red' )
  1838.             return
  1839.        
  1840.         Name, fileExtension = os.path.splitext(filename)
  1841.         TYPE=fileExtension.upper()
  1842.         if TYPE=='.DXF':
  1843.             self.Open_DXF(filename)
  1844.         elif TYPE=='.SVG':
  1845.             self.Open_SVG(filename)
  1846.         elif TYPE=='.EGV':
  1847.             self.EGV_Send_Window(filename)
  1848.         else:
  1849.             self.Open_G_Code(filename)
  1850.         self.menu_View_Refresh()
  1851.        
  1852.        
  1853.  
  1854.     def menu_File_Open_Design(self,event=None):
  1855.         if self.GUI_Disabled:
  1856.             return
  1857.         init_dir = os.path.dirname(self.DESIGN_FILE)
  1858.         if ( not os.path.isdir(init_dir) ):
  1859.             init_dir = self.HOME_DIR
  1860.  
  1861.         design_types = ("Design Files", ("*.svg","*.dxf"))
  1862.         gcode_types  = ("G-Code Files", ("*.ngc","*.gcode","*.g","*.tap"))
  1863.        
  1864.         Name, fileExtension = os.path.splitext(self.DESIGN_FILE)
  1865.         TYPE=fileExtension.upper()
  1866.         if TYPE != '.DXF' and TYPE!='.SVG' and TYPE!='.EGV' and TYPE!='':
  1867.             default_types = gcode_types
  1868.         else:
  1869.             default_types = design_types
  1870.        
  1871.         fileselect = askopenfilename(filetypes=[default_types,
  1872.                                             ("G-Code Files ", ("*.ngc","*.gcode","*.g","*.tap")),\
  1873.                                             ("DXF Files ","*.dxf"),\
  1874.                                             ("SVG Files ","*.svg"),\
  1875.                                             ("All Files ","*"),\
  1876.                                             ("Design Files ", ("*.svg","*.dxf"))],\
  1877.                                             initialdir=init_dir)
  1878.  
  1879.         if fileselect == () or (not os.path.isfile(fileselect)):
  1880.             return
  1881.            
  1882.         Name, fileExtension = os.path.splitext(fileselect)
  1883.         self.update_gui("Opening '%s'" % fileselect )
  1884.         TYPE=fileExtension.upper()
  1885.         if TYPE=='.DXF':
  1886.             self.Open_DXF(fileselect)
  1887.         elif TYPE=='.SVG':
  1888.             self.Open_SVG(fileselect)
  1889.         else:
  1890.             self.Open_G_Code(fileselect)
  1891.  
  1892.            
  1893.         self.DESIGN_FILE = fileselect
  1894.         self.menu_View_Refresh()
  1895.        
  1896.     def menu_File_Raster_Engrave(self):
  1897.         self.menu_File_save_EGV(operation_type="Raster_Eng")
  1898.        
  1899.     def menu_File_Vector_Engrave(self):
  1900.         self.menu_File_save_EGV(operation_type="Vector_Eng")
  1901.        
  1902.     def menu_File_Vector_Cut(self):
  1903.         self.menu_File_save_EGV(operation_type="Vector_Cut")
  1904.        
  1905.     def menu_File_G_Code(self):
  1906.         self.menu_File_save_EGV(operation_type="Gcode_Cut")
  1907.        
  1908.     def menu_File_Raster_Vector_Engrave(self):
  1909.         self.menu_File_save_EGV(operation_type="Raster_Eng-Vector_Eng")
  1910.  
  1911.     def menu_File_Vector_Engrave_Cut(self):
  1912.         self.menu_File_save_EGV(operation_type="Vector_Eng-Vector_Cut")
  1913.  
  1914.     def menu_File_Raster_Vector_Cut(self):
  1915.         self.menu_File_save_EGV(operation_type="Raster_Eng-Vector_Eng-Vector_Cut")
  1916.  
  1917.     def menu_File_save_EGV(self,operation_type=None,default_name="out.EGV"):
  1918.         self.stop[0]=False
  1919.         if DEBUG:
  1920.             start=time()
  1921.         fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
  1922.         init_file=os.path.basename(fileName)
  1923.         default_name = init_file+"_"+operation_type
  1924.        
  1925.         if self.EGV_FILE != None:
  1926.             init_dir = os.path.dirname(self.EGV_FILE)
  1927.         else:
  1928.             init_dir = os.path.dirname(self.DESIGN_FILE)
  1929.            
  1930.         if ( not os.path.isdir(init_dir) ):
  1931.             init_dir = self.HOME_DIR
  1932.            
  1933.         fileName, fileExtension = os.path.splitext(default_name)
  1934.         init_file=os.path.basename(fileName)
  1935.  
  1936.         filename = asksaveasfilename(defaultextension='.EGV', \
  1937.                                      filetypes=[("EGV File","*.EGV")],\
  1938.                                      initialdir=init_dir,\
  1939.                                      initialfile= init_file )
  1940.        
  1941.         if filename != '' and filename != ():
  1942.  
  1943.             if operation_type.find("Raster_Eng") > -1:
  1944.                 self.make_raster_coords()
  1945.             else:
  1946.                 self.statusbar.configure( bg = 'yellow' )
  1947.                 self.statusMessage.set("No raster data to engrave")
  1948.                
  1949.             self.send_data(operation_type=operation_type, output_filename=filename)
  1950.             self.EGV_FILE = filename
  1951.         if DEBUG:
  1952.             print("time = %d seconds" %(int(time()-start)))
  1953.         self.stop[0]=True
  1954.        
  1955.  
  1956.  
  1957.     def menu_File_Open_EGV(self):
  1958.         init_dir = os.path.dirname(self.DESIGN_FILE)
  1959.         if ( not os.path.isdir(init_dir) ):
  1960.             init_dir = self.HOME_DIR
  1961.         fileselect = askopenfilename(filetypes=[("Engraver Files", ("*.egv","*.EGV")),\
  1962.                                                     ("All Files","*")],\
  1963.                                                      initialdir=init_dir)
  1964.         if fileselect != '' and fileselect != ():
  1965.             self.resetPath()
  1966.             self.DESIGN_FILE = fileselect
  1967.             self.EGV_Send_Window(fileselect)
  1968.        
  1969.     def Open_EGV(self,filemname,n_passes=1):
  1970.         self.stop[0]=False
  1971.         EGV_data=[]
  1972.         value1 = ""
  1973.         value2 = ""
  1974.         value3 = ""
  1975.         value4 = ""
  1976.         data=""
  1977.         #value1 and value2 are the absolute y and x starting positions
  1978.         #value3 and value4 are the absolute y and x end positions
  1979.         with open(filemname) as f:
  1980.             while True:
  1981.                 ## Skip header
  1982.                 c = f.read(1)
  1983.                 while c!="%" and c:
  1984.                     c = f.read(1)
  1985.                 ## Read 1st Value
  1986.                 c = f.read(1)
  1987.                 while c!="%" and c:
  1988.                     value1 = value1 + c
  1989.                     c = f.read(1)
  1990.                 y_start_mils = int(value1)
  1991.                 ## Read 2nd Value
  1992.                 c = f.read(1)
  1993.                 while c!="%" and c:
  1994.                     value2 = value2 + c
  1995.                     c = f.read(1)
  1996.                 x_start_mils = int(value2)  
  1997.                 ## Read 3rd Value
  1998.                 c = f.read(1)
  1999.                 while c!="%" and c:
  2000.                     value3 = value3 + c
  2001.                     c = f.read(1)
  2002.                 y_end_mils = int(value3)
  2003.                 ## Read 4th Value
  2004.                 c = f.read(1)
  2005.                 while c!="%" and c:
  2006.                     value4 = value4 + c
  2007.                     c = f.read(1)
  2008.                 x_end_mils = int(value4)
  2009.                 break
  2010.  
  2011.             ## Read Data
  2012.             while True:
  2013.                 c = f.read(1)
  2014.                 if not c:
  2015.                     break
  2016.                 if c=='\n' or c==' ' or c=='\r':
  2017.                     pass
  2018.                 else:
  2019.                     data=data+"%c" %c
  2020.                     EGV_data.append(ord(c))
  2021.                    
  2022.         if ( (x_end_mils != 0) or (y_end_mils != 0) ):
  2023.             n_passes=1
  2024.         else:
  2025.             x_start_mils = 0
  2026.             y_start_mils = 0
  2027.  
  2028.         try:
  2029.             self.send_egv_data(EGV_data,n_passes)
  2030.         except MemoryError as e:
  2031.             msg1 = "Memory Error:"
  2032.             msg2 = "Memory Error:  Out of Memory."
  2033.             self.statusMessage.set(msg2)
  2034.             self.statusbar.configure( bg = 'red' )
  2035.             message_box(msg1, msg2)
  2036.             debug_message(traceback.format_exc())
  2037.            
  2038.         except Exception as e:
  2039.             msg1 = "Sending Data Stopped: "
  2040.             msg2 = "%s" %(e)
  2041.             if msg2 == "":
  2042.                 formatted_lines = traceback.format_exc().splitlines()
  2043.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2044.             self.statusbar.configure( bg = 'red' )
  2045.             message_box(msg1, msg2)
  2046.             debug_message(traceback.format_exc())
  2047.  
  2048.         #rapid move back to starting position
  2049.         dxmils = -(x_end_mils - x_start_mils)
  2050.         dymils =   y_end_mils - y_start_mils
  2051.         self.Send_Rapid_Move(dxmils,dxmils)
  2052.         self.stop[0]=True
  2053.        
  2054.     def Open_SVG(self,filemname):
  2055.         self.resetPath()
  2056.         self.SVG_FILE = filemname
  2057.         if self.reduced_mem.get():
  2058.             self.input_dpi = 500.0
  2059.         else:
  2060.             self.input_dpi = 1000.0
  2061.         svg_reader =  SVG_READER()
  2062.         svg_reader.image_dpi = self.input_dpi
  2063.         svg_reader.set_inkscape_path(self.inkscape_path.get())
  2064.         svg_reader.timout = int(float( self.ink_timeout.get())*60.0)
  2065.         dialog_pxpi    = None
  2066.         dialog_viewbox = None
  2067.         try:
  2068.             try:
  2069.                 try:
  2070.                     svg_reader.parse_svg(self.SVG_FILE)
  2071.                     svg_reader.make_paths()
  2072.                 except SVG_PXPI_EXCEPTION as e:
  2073.                     pxpi_dialog = pxpiDialog(root,
  2074.                                            self.units.get(),
  2075.                                            svg_reader.SVG_Size,
  2076.                                            svg_reader.SVG_ViewBox,
  2077.                                            svg_reader.SVG_inkscape_version)
  2078.                    
  2079.                     svg_reader = SVG_READER()
  2080.                     svg_reader.image_dpi = self.input_dpi
  2081.                     svg_reader.set_inkscape_path(self.inkscape_path.get())
  2082.                     svg_reader.timout = int(float( self.ink_timeout.get())*60.0)
  2083.                     if pxpi_dialog.result == None:
  2084.                         return
  2085.                    
  2086.                     dialog_pxpi,dialog_viewbox = pxpi_dialog.result
  2087.                     svg_reader.parse_svg(self.SVG_FILE)
  2088.                     svg_reader.set_size(dialog_pxpi,dialog_viewbox)
  2089.                     svg_reader.make_paths()
  2090.                    
  2091.             except SVG_TEXT_EXCEPTION as e:
  2092.                 svg_reader = SVG_READER()
  2093.                 svg_reader.image_dpi = self.input_dpi
  2094.                 svg_reader.set_inkscape_path(self.inkscape_path.get())
  2095.                 svg_reader.timout = int(float( self.ink_timeout.get())*60.0)
  2096.                 self.statusMessage.set("Converting TEXT to PATHS.")
  2097.                 self.master.update()
  2098.                 svg_reader.parse_svg(self.SVG_FILE)
  2099.                 if dialog_pxpi != None and dialog_viewbox != None:
  2100.                     svg_reader.set_size(dialog_pxpi,dialog_viewbox)
  2101.                 svg_reader.make_paths(txt2paths=True)
  2102.                
  2103.         except Exception as e:
  2104.             msg1 = "SVG Error: "
  2105.             msg2 = "%s" %(e)
  2106.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2107.             self.statusbar.configure( bg = 'red' )
  2108.             message_box(msg1, msg2)
  2109.             debug_message(traceback.format_exc())
  2110.             return
  2111.         except:
  2112.             self.statusMessage.set("Unable To open SVG File: %s" %(filemname))
  2113.             debug_message(traceback.format_exc())
  2114.             return
  2115.         xmax = svg_reader.Xsize/25.4
  2116.         ymax = svg_reader.Ysize/25.4
  2117.         xmin = 0
  2118.         ymin = 0
  2119.  
  2120.         self.Design_bounds = (xmin,xmax,ymin,ymax)
  2121.            
  2122.         ##########################
  2123.         ###   Create ECOORDS   ###
  2124.         ##########################
  2125.         self.VcutData.make_ecoords(svg_reader.cut_lines,scale=1/25.4)
  2126.         self.VengData.make_ecoords(svg_reader.eng_lines,scale=1/25.4)
  2127.  
  2128.         ##########################
  2129.         ###   Load Image       ###
  2130.         ##########################
  2131.         self.RengData.set_image(svg_reader.raster_PIL)
  2132.        
  2133.         if (self.RengData.image != None):
  2134.             self.wim, self.him = self.RengData.image.size
  2135.             self.aspect_ratio =  float(self.wim-1) / float(self.him-1)
  2136.             #self.make_raster_coords()
  2137.         self.refreshTime()
  2138.         margin=0.0625 # A bit of margin to prevent the warningwindow for designs that are close to being within the bounds
  2139.         if self.Design_bounds[0] > self.VengData.bounds[0]+margin or\
  2140.            self.Design_bounds[0] > self.VcutData.bounds[0]+margin or\
  2141.            self.Design_bounds[1] < self.VengData.bounds[1]-margin or\
  2142.            self.Design_bounds[1] < self.VcutData.bounds[1]-margin or\
  2143.            self.Design_bounds[2] > self.VengData.bounds[2]+margin or\
  2144.            self.Design_bounds[2] > self.VcutData.bounds[2]+margin or\
  2145.            self.Design_bounds[3] < self.VengData.bounds[3]-margin or\
  2146.            self.Design_bounds[3] < self.VcutData.bounds[3]-margin:
  2147.             line1 = "Warning:\n"
  2148.             line2 = "There is vector cut or vector engrave data located outside of the SVG page bounds.\n\n"
  2149.             line3 = "K40 Whisperer will attempt to use all of the vector data.  "
  2150.             line4 = "Please verify that the vector data is not outside of your lasers working area before engraving."
  2151.             message_box("Warning", line1+line2+line3+line4)
  2152.  
  2153.  
  2154.     #####################################################################
  2155.     def make_raster_coords(self):
  2156.         if self.RengData.rpaths:
  2157.             return
  2158.         try:
  2159.             hcoords=[]
  2160.             if (self.RengData.image != None and self.RengData.ecoords==[]):
  2161.                 ecoords=[]
  2162.                 cutoff=128
  2163.                 image_temp = self.RengData.image.convert("L")
  2164. ##                if self.unsharp_flag.get():
  2165. ##                    from PIL import ImageFilter      
  2166. ##                    #image_temp = image_temp.filter(UnsharpMask(radius=self.unsharp_r, percent=self.unsharp_p, threshold=self.unsharp_t))
  2167. ##                    filter = ImageFilter.UnsharpMask()
  2168. ##                    filter.radius    = float(self.unsharp_r.get())      # radius 3-5 pixels
  2169. ##                    filter.percent   = int(float(self.unsharp_p.get())) # precent 500%
  2170. ##                    filter.threshold = int(float(self.unsharp_t.get())) # Threshold 0
  2171. ##                    image_temp = image_temp.filter(filter)
  2172.  
  2173.                 if self.negate.get():
  2174.                     image_temp = ImageOps.invert(image_temp)
  2175.                    
  2176.                 if self.mirror.get():
  2177.                     image_temp = ImageOps.mirror(image_temp)
  2178.  
  2179.                 if self.rotate.get():
  2180.                     #image_temp = image_temp.rotate(90,expand=True)
  2181.                     image_temp = self.rotate_raster(image_temp)
  2182.  
  2183.                 Xscale = float(self.LaserXscale.get())
  2184.                 Yscale = float(self.LaserYscale.get())    
  2185.                 if self.rotary.get():
  2186.                     Rscale = float(self.LaserRscale.get())
  2187.                     Yscale = Yscale*Rscale
  2188.  
  2189.                 if Xscale != 1.0 or Yscale != 1.0:
  2190.                     wim,him = image_temp.size
  2191.                     nw = int(wim*Xscale)
  2192.                     nh = int(him*Yscale)
  2193.                     image_temp = image_temp.resize((nw,nh))
  2194.  
  2195.                    
  2196.                 if self.halftone.get():
  2197.                     ht_size_mils =  round( self.input_dpi / float(self.ht_size.get()) ,1)
  2198.                     npixels = int( round(ht_size_mils,1) )
  2199.                     if npixels == 0:
  2200.                         return
  2201.                     wim,him = image_temp.size
  2202.                     # Convert to Halftoning and save
  2203.                     nw=int(wim / npixels)
  2204.                     nh=int(him / npixels)
  2205.                     image_temp = image_temp.resize((nw,nh))
  2206.                    
  2207.                     image_temp = self.convert_halftoning(image_temp)
  2208.                     image_temp = image_temp.resize((wim,him))
  2209.                 else:
  2210.                     image_temp = image_temp.point(lambda x: 0 if x<128 else 255, '1')
  2211.                    
  2212.                 if DEBUG:
  2213.                     image_name = os.path.expanduser("~")+"/IMAGE.png"
  2214.                     image_temp.save(image_name,"PNG")
  2215.  
  2216.                 Reng_np = image_temp.load()
  2217.                 wim,him = image_temp.size
  2218.                 del image_temp
  2219.                 #######################################
  2220.                 x=0
  2221.                 y=0
  2222.                 loop=1
  2223.                 LENGTH=0
  2224.                 n_scanlines = 0
  2225.                
  2226.                 my_hull = hull2D()
  2227.                 bignumber = 9999999;
  2228.                 Raster_step = int(self.get_raster_step_1000in())
  2229.                 timestamp=0
  2230.                 im_height_mils = int(him/self.input_dpi*1000.0)
  2231.                 for i_step in range(0,im_height_mils,Raster_step):
  2232.                     i=floor(i_step*self.input_dpi/1000.0)
  2233.                     #print(i_step,i)
  2234.                     stamp=int(3*time()) #update every 1/3 of a second
  2235.                     if (stamp != timestamp):
  2236.                         timestamp=stamp #interlock
  2237.                         self.statusMessage.set("Creating Scan Lines: %.1f %%" %( (100.0*i)/him ) )
  2238.                         self.master.update()
  2239.                     #lovejoy    
  2240.                     if self.stop[0]==True:
  2241.                         raise Exception("Action stopped by User.")
  2242.                     line = []
  2243.                     cnt=1
  2244.                     LEFT  = bignumber;
  2245.                     RIGHT =-bignumber;
  2246.                     for j in range(1,wim):
  2247.                         if (Reng_np[j,i] == Reng_np[j-1,i]):
  2248.                             cnt = cnt+1
  2249.                         else:
  2250.                             if Reng_np[j-1,i]:
  2251.                                 laser = "U"
  2252.                             else:
  2253.                                 laser = "D"
  2254.                                 LEFT  = min(j-cnt,LEFT)
  2255.                                 RIGHT = max(j,RIGHT)
  2256.                                
  2257.                             line.append((cnt,laser))
  2258.                             cnt=1
  2259.                     if Reng_np[j-1,i] > cutoff:
  2260.                         laser = "U"
  2261.                     else:
  2262.                         laser = "D"
  2263.                         LEFT  = min(j-cnt,LEFT)
  2264.                         RIGHT = max(j,RIGHT)
  2265.                        
  2266.                     line.append((cnt,laser))
  2267.                     if LEFT != bignumber and RIGHT != -bignumber:
  2268.                         LENGTH = LENGTH + (RIGHT - LEFT)/self.input_dpi
  2269.                         n_scanlines = n_scanlines + 1
  2270.                    
  2271.                     y=(im_height_mils-i_step)/1000.0
  2272.                     x=0
  2273.                     if LEFT != bignumber:
  2274.                         hcoords.append([LEFT/self.input_dpi,y])
  2275.                     if RIGHT != -bignumber:
  2276.                         hcoords.append([RIGHT/self.input_dpi,y])
  2277.                     if hcoords!=[]:
  2278.                         hcoords = my_hull.convexHullecoords(hcoords)
  2279.                        
  2280.                     rng = list(range(0,len(line),1))
  2281.                        
  2282.                     for i in rng:
  2283.                         seg = line[i]
  2284.                         delta = seg[0]/self.input_dpi
  2285.                         if seg[1]=="D":
  2286.                             loop=loop+1
  2287.                             ecoords.append([x      ,y,loop])
  2288.                             ecoords.append([x+delta,y,loop])
  2289.                         x = x + delta
  2290.                 self.RengData.set_ecoords(ecoords,data_sorted=True)
  2291.                 self.RengData.len=LENGTH
  2292.                 self.RengData.n_scanlines = n_scanlines
  2293.             #Set Flag indicating raster paths have been calculated    
  2294.             self.RengData.rpaths = True
  2295.             self.RengData.hull_coords = hcoords
  2296.        
  2297.         except MemoryError as e:
  2298.             msg1 = "Memory Error:"
  2299.             msg2 = "Memory Error:  Out of Memory."
  2300.             self.statusMessage.set(msg2)
  2301.             self.statusbar.configure( bg = 'red' )
  2302.             message_box(msg1, msg2)
  2303.             debug_message(traceback.format_exc())
  2304.            
  2305.         except Exception as e:
  2306.             msg1 = "Making Raster Coords Stopped: "
  2307.             msg2 = "%s" %(e)
  2308.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2309.             self.statusbar.configure( bg = 'red' )
  2310.             message_box(msg1, msg2)
  2311.             debug_message(traceback.format_exc())
  2312.     #######################################################################
  2313.  
  2314.  
  2315.     def rotate_raster(self,image_in):
  2316.         wim,him = image_in.size
  2317.         im_rotated = Image.new("L", (him, wim), "white")
  2318.  
  2319.         image_in_np   = image_in.load()
  2320.         im_rotated_np = im_rotated.load()
  2321.        
  2322.         for i in range(1,him):
  2323.             for j in range(1,wim):
  2324.                 im_rotated_np[i,wim-j] = image_in_np[j,i]
  2325.         return im_rotated
  2326.    
  2327.     def get_raster_step_1000in(self):
  2328.         val_in = float(self.rast_step.get())
  2329.         value = int(round(val_in*1000.0,1))
  2330.         return value
  2331.  
  2332.  
  2333.     def generate_bezier(self,M1,M2,w,n=100):
  2334.         if (M1==M2):
  2335.             x1=0
  2336.             y1=0
  2337.         else:
  2338.             x1 = 255*(1-M2)/(M1-M2)
  2339.             y1 = M1*x1
  2340.         x=[]
  2341.         y=[]
  2342.         # Calculate Bezier Curve
  2343.         for step in range(0,n+1):
  2344.             t    = float(step)/float(n)
  2345.             Ct   = 1 / ( pow(1-t,2)+2*(1-t)*t*w+pow(t,2) )
  2346.             x.append( Ct*( 2*(1-t)*t*w*x1+pow(t,2)*255) )
  2347.             y.append( Ct*( 2*(1-t)*t*w*y1+pow(t,2)*255) )
  2348.         return x,y
  2349.  
  2350.     '''This Example opens an Image and transform the image into halftone.  -Isai B. Cicourel'''
  2351.     # Create a Half-tone version of the image
  2352.     def convert_halftoning(self,image):
  2353.         image = image.convert('L')
  2354.         x_lim, y_lim = image.size
  2355.         pixel = image.load()
  2356.        
  2357.         M1 = float(self.bezier_M1.get())
  2358.         M2 = float(self.bezier_M2.get())
  2359.         w  = float(self.bezier_weight.get())
  2360.        
  2361.         if w > 0:
  2362.             x,y = self.generate_bezier(M1,M2,w)
  2363.            
  2364.             interp = interpolate(x, y) # Set up interpolate class
  2365.             val_map=[]
  2366.             # Map Bezier Curve to values between 0 and 255
  2367.             for val in range(0,256):
  2368.                 val_out = int(round(interp[val])) # Get the interpolated value at each value
  2369.                 val_map.append(val_out)
  2370.             # Adjust image
  2371.             timestamp=0
  2372.             for y in range(1, y_lim):
  2373.                 stamp=int(3*time()) #update every 1/3 of a second
  2374.                 if (stamp != timestamp):
  2375.                     timestamp=stamp #interlock
  2376.                     self.statusMessage.set("Adjusting Image Darkness: %.1f %%" %( (100.0*y)/y_lim ) )
  2377.                     self.master.update()
  2378.                 for x in range(1, x_lim):
  2379.                     pixel[x, y] = val_map[ pixel[x, y] ]
  2380.  
  2381.         self.statusMessage.set("Creating Halftone Image." )
  2382.         self.master.update()
  2383.         image = image.convert('1')
  2384.         return image
  2385.  
  2386.     #######################################################################
  2387.  
  2388.     def gcode_error_message(self,message):
  2389.         error_report = Toplevel(width=525,height=60)
  2390.         error_report.title("G-Code Reading Errors/Warnings")
  2391.         error_report.iconname("G-Code Errors")
  2392.         error_report.grab_set()
  2393.         return_value =  StringVar()
  2394.         return_value.set("none")
  2395.  
  2396.  
  2397.         def Close_Click(event):
  2398.             return_value.set("close")
  2399.             error_report.destroy()
  2400.            
  2401.         #Text Box
  2402.         Error_Frame = Frame(error_report)
  2403.         scrollbar = Scrollbar(Error_Frame, orient=VERTICAL)
  2404.         Error_Text = Text(Error_Frame, width="80", height="20",yscrollcommand=scrollbar.set,bg='white')
  2405.         for line in message:
  2406.             Error_Text.insert(END,line+"\n")
  2407.         scrollbar.config(command=Error_Text.yview)
  2408.         scrollbar.pack(side=RIGHT,fill=Y)
  2409.         #End Text Box
  2410.  
  2411.         Button_Frame = Frame(error_report)
  2412.         close_button = Button(Button_Frame,text=" Close ")
  2413.         close_button.bind("<ButtonRelease-1>", Close_Click)
  2414.         close_button.pack(side=RIGHT,fill=X)
  2415.        
  2416.         Error_Text.pack(side=LEFT,fill=BOTH,expand=1)
  2417.         Button_Frame.pack(side=BOTTOM)
  2418.         Error_Frame.pack(side=LEFT,fill=BOTH,expand=1)
  2419.        
  2420.         root.wait_window(error_report)
  2421.         return return_value.get()
  2422.  
  2423.     def Open_G_Code(self,filename):
  2424.         self.resetPath()
  2425.        
  2426.         g_rip = G_Code_Rip()
  2427.         try:
  2428.             MSG = g_rip.Read_G_Code(filename, XYarc2line = True, arc_angle=2, units="in", Accuracy="")
  2429.             Error_Text = ""
  2430.             if MSG!=[]:
  2431.                 self.gcode_error_message(MSG)
  2432.  
  2433.         #except StandardError as e:
  2434.         except Exception as e:
  2435.             msg1 = "G-Code Load Failed:  "
  2436.             msg2 = "Filename: %s" %(filename)
  2437.             msg3 = "%s" %(e)
  2438.             self.statusMessage.set((msg1+msg3).split("\n")[0] )
  2439.             self.statusbar.configure( bg = 'red' )
  2440.             message_box(msg1, "%s\n%s" %(msg2,msg3))
  2441.             debug_message(traceback.format_exc())
  2442.  
  2443.            
  2444.         ecoords= g_rip.generate_laser_paths(g_rip.g_code_data)
  2445.         self.GcodeData.set_ecoords(ecoords,data_sorted=True)
  2446.         self.Design_bounds = self.GcodeData.bounds
  2447.  
  2448.        
  2449.     def Open_DXF(self,filemname):
  2450.         self.resetPath()
  2451.        
  2452.         self.DXF_FILE = filemname
  2453.         dxf_import=DXF_CLASS()
  2454.         tolerance = .0005
  2455.         try:
  2456.             fd = open(self.DXF_FILE)
  2457.             dxf_import.GET_DXF_DATA(fd,lin_tol = tolerance,get_units=True,units=None)
  2458.             fd.seek(0)
  2459.            
  2460.             dxf_units = dxf_import.units
  2461.             if dxf_units=="Unitless":
  2462.                 d = UnitsDialog(root)
  2463.                 dxf_units = d.result
  2464.             if dxf_units=="Inches":
  2465.                 dxf_scale = 1.0
  2466.             elif dxf_units=="Feet":
  2467.                 dxf_scale = 12.0
  2468.             elif dxf_units=="Miles":
  2469.                 dxf_scale = 5280.0*12.0
  2470.             elif dxf_units=="Millimeters":
  2471.                 dxf_scale = 1.0/25.4
  2472.             elif dxf_units=="Centimeters":
  2473.                 dxf_scale = 1.0/2.54
  2474.             elif dxf_units=="Meters":
  2475.                 dxf_scale = 1.0/254.0
  2476.             elif dxf_units=="Kilometers":
  2477.                 dxf_scale = 1.0/254000.0
  2478.             elif dxf_units=="Microinches":
  2479.                 dxf_scale = 1.0/1000000.0
  2480.             elif dxf_units=="Mils":
  2481.                 dxf_scale = 1.0/1000.0
  2482.             else:
  2483.                 return    
  2484.  
  2485.             lin_tol = tolerance / dxf_scale
  2486.             dxf_import.GET_DXF_DATA(fd,lin_tol=lin_tol,get_units=False,units=None)
  2487.             fd.close()
  2488.         #except StandardError as e:
  2489.         except Exception as e:
  2490.             msg1 = "DXF Load Failed:"
  2491.             msg2 = "%s" %(e)
  2492.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2493.             self.statusbar.configure( bg = 'red' )
  2494.             message_box(msg1, msg2)
  2495.             debug_message(traceback.format_exc())
  2496.         except:
  2497.             fmessage("Unable To open Drawing Exchange File (DXF) file.")
  2498.             debug_message(traceback.format_exc())
  2499.             return
  2500.        
  2501.         new_origin=False
  2502.         dxf_engrave_coords = dxf_import.DXF_COORDS_GET_TYPE(engrave=True, new_origin=False)
  2503.         dxf_cut_coords     = dxf_import.DXF_COORDS_GET_TYPE(engrave=False,new_origin=False)
  2504. ##        if DEBUG:
  2505. ##            dxf_code = dxf_import.WriteDXF(close_loops=False)
  2506. ##            fout = open('Z:\\out.dxf','w')
  2507. ##            for line in dxf_code:
  2508. ##                fout.write(line+'\n')
  2509. ##            fout.close
  2510.        
  2511.         if dxf_import.dxf_messages != "":
  2512.             msg_split=dxf_import.dxf_messages.split("\n")
  2513.             msg_split.sort()
  2514.             msg_split.append("")
  2515.             mcnt=1
  2516.             msg_out = ""
  2517.             for i in range(1,len(msg_split)):
  2518.                 if msg_split[i-1]==msg_split[i]:
  2519.                     mcnt=mcnt+1
  2520.                 else:
  2521.                     if msg_split[i-1]!="":
  2522.                         msg_line = "%s (%d places)\n" %(msg_split[i-1],mcnt)
  2523.                         msg_out = msg_out + msg_line
  2524.                     mcnt=1
  2525.             message_box("DXF Import:",msg_out)
  2526.                    
  2527.         ##########################
  2528.         ###   Create ECOORDS   ###
  2529.         ##########################
  2530.         self.VcutData.make_ecoords(dxf_cut_coords    ,scale=dxf_scale)
  2531.         self.VengData.make_ecoords(dxf_engrave_coords,scale=dxf_scale)
  2532.  
  2533.         xmin = min(self.VcutData.bounds[0],self.VengData.bounds[0])
  2534.         xmax = max(self.VcutData.bounds[1],self.VengData.bounds[1])
  2535.         ymin = min(self.VcutData.bounds[2],self.VengData.bounds[2])
  2536.         ymax = max(self.VcutData.bounds[3],self.VengData.bounds[3])
  2537.         self.Design_bounds = (xmin,xmax,ymin,ymax)
  2538.  
  2539.  
  2540.     def Open_Settings_File(self,filename):
  2541.         try:
  2542.             fin = open(filename,'r')
  2543.         except:
  2544.             fmessage("Unable to open file: %s" %(filename))
  2545.             return
  2546.        
  2547.         text_codes=[]
  2548.         ident = "k40_whisperer_set"
  2549.         for line in fin:
  2550.             try:
  2551.                 if ident in line:
  2552.                     # BOOL
  2553.                     if "include_Reng"  in line:
  2554.                         self.include_Reng.set(line[line.find("include_Reng"):].split()[1])
  2555.                     elif "include_Veng"  in line:
  2556.                         self.include_Veng.set(line[line.find("include_Veng"):].split()[1])
  2557.                     elif "include_Vcut"  in line:
  2558.                         self.include_Vcut.set(line[line.find("include_Vcut"):].split()[1])
  2559.                     elif "include_Gcde"  in line:
  2560.                         self.include_Gcde.set(line[line.find("include_Gcde"):].split()[1])
  2561.                     elif "include_Time"  in line:
  2562.                         self.include_Time.set(line[line.find("include_Time"):].split()[1])
  2563.                     elif "halftone"  in line:
  2564.                         self.halftone.set(line[line.find("halftone"):].split()[1])
  2565.                     elif "negate"  in line:
  2566.                         self.negate.set(line[line.find("negate"):].split()[1])
  2567.                     elif "HomeUR"  in line:
  2568.                         self.HomeUR.set(line[line.find("HomeUR"):].split()[1])                    
  2569.                     elif "inputCSYS"  in line:
  2570.                         self.inputCSYS.set(line[line.find("inputCSYS"):].split()[1])
  2571.                     elif "advanced"  in line:
  2572.                         self.advanced.set(line[line.find("advanced"):].split()[1])
  2573.                     elif "mirror"  in line:
  2574.                         self.mirror.set(line[line.find("mirror"):].split()[1])
  2575.                     elif "rotate"  in line:
  2576.                         self.rotate.set(line[line.find("rotate"):].split()[1])
  2577.                     elif "engraveUP"  in line:
  2578.                         self.engraveUP.set(line[line.find("engraveUP"):].split()[1])
  2579.                     elif "init_home"  in line:
  2580.                         self.init_home.set(line[line.find("init_home"):].split()[1])
  2581.                     elif "post_home"  in line:
  2582.                         self.post_home.set(line[line.find("post_home"):].split()[1])
  2583.                     elif "post_beep"  in line:
  2584.                         self.post_beep.set(line[line.find("post_beep"):].split()[1])
  2585.                     elif "post_disp"  in line:
  2586.                         self.post_disp.set(line[line.find("post_disp"):].split()[1])
  2587.                     elif "post_exec"  in line:
  2588.                         self.post_exec.set(line[line.find("post_exec"):].split()[1])
  2589.                        
  2590.                     elif "pre_pr_crc"  in line:
  2591.                         self.pre_pr_crc.set(line[line.find("pre_pr_crc"):].split()[1])
  2592.                     elif "inside_first"  in line:
  2593.                         self.inside_first.set(line[line.find("inside_first"):].split()[1])
  2594.                     elif "comb_engrave"  in line:
  2595.                         self.comb_engrave.set(line[line.find("comb_engrave"):].split()[1])
  2596.                     elif "comb_vector"  in line:
  2597.                         self.comb_vector.set(line[line.find("comb_vector"):].split()[1])
  2598.                     elif "zoom2image"  in line:
  2599.                         self.zoom2image.set(line[line.find("zoom2image"):].split()[1])
  2600.  
  2601.                     elif "rotary"  in line:
  2602.                          self.rotary.set(line[line.find("rotary"):].split()[1])
  2603.                     elif "reduced_mem"  in line:
  2604.                          self.reduced_mem.set(line[line.find("reduced_mem"):].split()[1])
  2605.                     elif "wait"  in line:
  2606.                          self.wait.set(line[line.find("wait"):].split()[1])
  2607.  
  2608.                     elif "trace_w_laser"  in line:
  2609.                          self.trace_w_laser.set(line[line.find("trace_w_laser"):].split()[1])
  2610.            
  2611.                     # STRING.set()
  2612.                     elif "board_name" in line:
  2613.                         self.board_name.set(line[line.find("board_name"):].split()[1])
  2614.                     elif "units"    in line:
  2615.                         self.units.set(line[line.find("units"):].split()[1])
  2616.                     elif "Reng_feed"    in line:
  2617.                          self.Reng_feed .set(line[line.find("Reng_feed"):].split()[1])
  2618.                     elif "Veng_feed"    in line:
  2619.                          self.Veng_feed .set(line[line.find("Veng_feed"):].split()[1])  
  2620.                     elif "Vcut_feed"    in line:
  2621.                          self.Vcut_feed.set(line[line.find("Vcut_feed"):].split()[1])
  2622.                     elif "jog_step"    in line:
  2623.                          self.jog_step.set(line[line.find("jog_step"):].split()[1])
  2624.                          
  2625.                     elif "Reng_passes"    in line:
  2626.                          self.Reng_passes.set(line[line.find("Reng_passes"):].split()[1])
  2627.                     elif "Veng_passes"    in line:
  2628.                          self.Veng_passes.set(line[line.find("Veng_passes"):].split()[1])
  2629.                     elif "Vcut_passes"    in line:
  2630.                          self.Vcut_passes.set(line[line.find("Vcut_passes"):].split()[1])
  2631.                     elif "Gcde_passes"    in line:
  2632.                          self.Gcde_passes.set(line[line.find("Gcde_passes"):].split()[1])
  2633.  
  2634.                     elif "rast_step"    in line:
  2635.                          self.rast_step.set(line[line.find("rast_step"):].split()[1])
  2636.                     elif "ht_size"    in line:
  2637.                          self.ht_size.set(line[line.find("ht_size"):].split()[1])
  2638.  
  2639.                     elif "LaserXsize"    in line:
  2640.                          self.LaserXsize.set(line[line.find("LaserXsize"):].split()[1])
  2641.                     elif "LaserYsize"    in line:
  2642.                          self.LaserYsize.set(line[line.find("LaserYsize"):].split()[1])
  2643.  
  2644.                     elif "LaserXscale"    in line:
  2645.                          self.LaserXscale.set(line[line.find("LaserXscale"):].split()[1])
  2646.                     elif "LaserYscale"    in line:
  2647.                          self.LaserYscale.set(line[line.find("LaserYscale"):].split()[1])
  2648.                     elif "LaserRscale"    in line:
  2649.                          self.LaserRscale.set(line[line.find("LaserRscale"):].split()[1])
  2650.  
  2651.                     elif "rapid_feed"    in line:
  2652.                          self.rapid_feed.set(line[line.find("rapid_feed"):].split()[1])
  2653.                          
  2654.                     elif "gotoX"    in line:
  2655.                          self.gotoX.set(line[line.find("gotoX"):].split()[1])
  2656.                     elif "gotoY"    in line:
  2657.                          self.gotoY.set(line[line.find("gotoY"):].split()[1])
  2658.  
  2659.                     elif "bezier_M1"    in line:
  2660.                          self.bezier_M1.set(line[line.find("bezier_M1"):].split()[1])
  2661.                     elif "bezier_M2"    in line:
  2662.                          self.bezier_M2.set(line[line.find("bezier_M2"):].split()[1])
  2663.                     elif "bezier_weight"    in line:
  2664.                          self.bezier_weight.set(line[line.find("bezier_weight"):].split()[1])
  2665.                     elif "trace_gap"    in line:
  2666.                          self.trace_gap.set(line[line.find("trace_gap"):].split()[1])
  2667.                     elif "trace_speed"    in line:
  2668.                          self.trace_speed.set(line[line.find("trace_speed"):].split()[1])
  2669.  
  2670.     ##                elif "unsharp_flag"    in line:
  2671.     ##                     self.unsharp_flag.set(line[line.find("unsharp_flag"):].split()[1])
  2672.     ##                elif "unsharp_r"    in line:
  2673.     ##                     self.unsharp_r.set(line[line.find("unsharp_r"):].split()[1])
  2674.     ##                elif "unsharp_p"    in line:
  2675.     ##                     self.unsharp_p.set(line[line.find("unsharp_p"):].split()[1])
  2676.     ##                elif "unsharp_t"    in line:
  2677.     ##                     self.unsharp_t.set(line[line.find("unsharp_t"):].split()[1])
  2678.            
  2679.                     elif "t_timeout"    in line:
  2680.                          self.t_timeout.set(line[line.find("t_timeout"):].split()[1])
  2681.                     elif "n_timeouts"    in line:
  2682.                          self.n_timeouts.set(line[line.find("n_timeouts"):].split()[1])
  2683.  
  2684.                     elif "ink_timeout"    in line:
  2685.                          self.ink_timeout.set(line[line.find("ink_timeout"):].split()[1])
  2686.  
  2687.                     elif "designfile"    in line:
  2688.                            self.DESIGN_FILE=(line[line.find("designfile"):].split("\042")[1])
  2689.                     elif "inkscape_path"    in line:
  2690.                          self.inkscape_path.set(line[line.find("inkscape_path"):].split("\042")[1])
  2691.                     elif "batch_path"    in line:
  2692.                          self.batch_path.set(line[line.find("batch_path"):].split("\042")[1])
  2693.  
  2694.                          
  2695.             except:
  2696.                 #Ignoring exeptions during reading data from line
  2697.                 pass
  2698.                      
  2699.         fin.close()
  2700.  
  2701.         fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
  2702.         init_file=os.path.basename(fileName)
  2703.        
  2704.         if init_file != "None":
  2705.             if ( os.path.isfile(self.DESIGN_FILE) ):
  2706.                 pass
  2707.             else:
  2708.                 self.statusMessage.set("Image file not found: %s " %(self.DESIGN_FILE))
  2709.  
  2710.         if self.units.get() == 'in':
  2711.             self.funits.set('in/min')
  2712.             self.units_scale = 1.0
  2713.         else:
  2714.             self.units.set('mm')
  2715.             self.funits.set('mm/s')
  2716.             self.units_scale = 25.4
  2717.  
  2718.         temp_name, fileExtension = os.path.splitext(filename)
  2719.         file_base=os.path.basename(temp_name)
  2720.            
  2721.         if self.initComplete == 1:
  2722.             self.menu_Mode_Change()
  2723.             self.DESIGN_FILE = filename
  2724.            
  2725.     ##########################################################################
  2726.     ##########################################################################
  2727.     def menu_File_Save(self):
  2728.         settings_data = self.WriteConfig()
  2729.         init_dir = os.path.dirname(self.DESIGN_FILE)
  2730.         if ( not os.path.isdir(init_dir) ):
  2731.             init_dir = self.HOME_DIR
  2732.            
  2733.         fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
  2734.         init_file=os.path.basename(fileName)
  2735.  
  2736.         filename = asksaveasfilename(defaultextension='.txt', \
  2737.                                      filetypes=[("Text File","*.txt")],\
  2738.                                      initialdir=init_dir,\
  2739.                                      initialfile= init_file )
  2740.  
  2741.         if filename != '' and filename != ():
  2742.             try:
  2743.                 fout = open(filename,'w')
  2744.             except:
  2745.                 self.statusMessage.set("Unable to open file for writing: %s" %(filename))
  2746.                 self.statusbar.configure( bg = 'red' )
  2747.                 return
  2748.  
  2749.             for line in settings_data:
  2750.                 try:
  2751.                     fout.write(line+'\n')
  2752.                 except:
  2753.                     fout.write('(skipping line)\n')
  2754.                     debug_message(traceback.format_exc())
  2755.             fout.close
  2756.             self.statusMessage.set("File Saved: %s" %(filename))
  2757.             self.statusbar.configure( bg = 'white' )
  2758.        
  2759.     def Get_Design_Bounds(self):
  2760.         if self.rotate.get():
  2761.             ymin =  self.Design_bounds[0]
  2762.             ymax =  self.Design_bounds[1]
  2763.             xmin = -self.Design_bounds[3]
  2764.             xmax = -self.Design_bounds[2]
  2765.         else:
  2766.             xmin,xmax,ymin,ymax = self.Design_bounds
  2767.         return (xmin,xmax,ymin,ymax)
  2768.    
  2769.     def Move_UL(self,dummy=None):
  2770.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2771.         if self.HomeUR.get():
  2772.             Xnew = self.laserX + (xmax-xmin)
  2773.             DX = round((xmax-xmin)*1000.0)
  2774.         else:
  2775.             Xnew = self.laserX
  2776.             DX = 0
  2777.            
  2778.         (Xsize,Ysize)=self.LASER_Size()
  2779.         if Xnew <= Xsize+.001:
  2780.             self.move_head_window_temporary([DX,0.0])
  2781.         else:
  2782.             pass
  2783.  
  2784.     def Move_UR(self,dummy=None):
  2785.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2786.         if self.HomeUR.get():
  2787.             Xnew = self.laserX
  2788.             DX = 0
  2789.         else:
  2790.             Xnew = self.laserX + (xmax-xmin)
  2791.             DX = round((xmax-xmin)*1000.0)
  2792.  
  2793.         (Xsize,Ysize)=self.LASER_Size()
  2794.         if Xnew <= Xsize+.001:
  2795.             self.move_head_window_temporary([DX,0.0])
  2796.         else:
  2797.             pass
  2798.    
  2799.     def Move_LR(self,dummy=None):
  2800.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2801.         if self.HomeUR.get():
  2802.             Xnew = self.laserX
  2803.             DX = 0
  2804.         else:
  2805.             Xnew = self.laserX + (xmax-xmin)
  2806.             DX = round((xmax-xmin)*1000.0)
  2807.            
  2808.         Ynew = self.laserY - (ymax-ymin)
  2809.         (Xsize,Ysize)=self.LASER_Size()
  2810.         if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
  2811.             DY = round((ymax-ymin)*1000.0)
  2812.             self.move_head_window_temporary([DX,-DY])
  2813.         else:
  2814.             pass
  2815.    
  2816.     def Move_LL(self,dummy=None):
  2817.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2818.         if self.HomeUR.get():
  2819.             Xnew = self.laserX + (xmax-xmin)
  2820.             DX = round((xmax-xmin)*1000.0)
  2821.         else:
  2822.             Xnew = self.laserX
  2823.             DX = 0
  2824.            
  2825.         Ynew = self.laserY - (ymax-ymin)
  2826.         (Xsize,Ysize)=self.LASER_Size()
  2827.         if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
  2828.             DY = round((ymax-ymin)*1000.0)
  2829.             self.move_head_window_temporary([DX,-DY])
  2830.         else:
  2831.             pass
  2832.  
  2833.     def Move_CC(self,dummy=None):
  2834.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2835.         if self.HomeUR.get():
  2836.             Xnew = self.laserX + (xmax-xmin)/2.0
  2837.             DX = round((xmax-xmin)/2.0*1000.0)
  2838.         else:
  2839.             Xnew = self.laserX + (xmax-xmin)/2.0
  2840.             DX = round((xmax-xmin)/2.0*1000.0)
  2841.  
  2842.            
  2843.         Ynew = self.laserY - (ymax-ymin)/2.0
  2844.         (Xsize,Ysize)=self.LASER_Size()
  2845.         if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
  2846.             DY = round((ymax-ymin)/2.0*1000.0)
  2847.             self.move_head_window_temporary([DX,-DY])
  2848.         else:
  2849.             pass
  2850.  
  2851.     def Move_Arbitrary(self,MoveX,MoveY,dummy=None):
  2852.         if self.GUI_Disabled:
  2853.             return
  2854.         if self.HomeUR.get():
  2855.             DX = -MoveX
  2856.         else:
  2857.             DX = MoveX
  2858.         DY = MoveY
  2859.         NewXpos = self.pos_offset[0]+DX
  2860.         NewYpos = self.pos_offset[1]+DY
  2861.         self.move_head_window_temporary([NewXpos,NewYpos])
  2862.  
  2863.     def Move_Arb_Step(self,dx,dy):
  2864.         if self.GUI_Disabled:
  2865.             return
  2866.         if self.units.get()=="in":
  2867.             dx_inches = round(dx*1000)
  2868.             dy_inches = round(dy*1000)
  2869.         else:
  2870.             dx_inches = round(dx/25.4*1000)
  2871.             dy_inches = round(dy/25.4*1000)
  2872.         self.Move_Arbitrary( dx_inches,dy_inches )
  2873.  
  2874.     def Move_Arb_Right(self,dummy=None):
  2875.         JOG_STEP = float( self.jog_step.get() )
  2876.         self.Move_Arb_Step( JOG_STEP,0 )
  2877.  
  2878.     def Move_Arb_Left(self,dummy=None):
  2879.         JOG_STEP = float( self.jog_step.get() )
  2880.         self.Move_Arb_Step( -JOG_STEP,0 )
  2881.  
  2882.     def Move_Arb_Up(self,dummy=None):
  2883.         JOG_STEP = float( self.jog_step.get() )
  2884.         self.Move_Arb_Step( 0,JOG_STEP )
  2885.  
  2886.     def Move_Arb_Down(self,dummy=None):
  2887.         JOG_STEP = float( self.jog_step.get() )
  2888.         self.Move_Arb_Step( 0,-JOG_STEP )
  2889.  
  2890.     ####################################################
  2891.  
  2892.     def Move_Right(self,dummy=None):
  2893.         JOG_STEP = float( self.jog_step.get() )
  2894.         self.Rapid_Move( JOG_STEP,0 )
  2895.  
  2896.     def Move_Left(self,dummy=None):
  2897.         JOG_STEP = float( self.jog_step.get() )
  2898.         self.Rapid_Move( -JOG_STEP,0 )
  2899.  
  2900.     def Move_Up(self,dummy=None):
  2901.         JOG_STEP = float( self.jog_step.get() )
  2902.         self.Rapid_Move( 0,JOG_STEP )
  2903.  
  2904.     def Move_Down(self,dummy=None):
  2905.         JOG_STEP = float( self.jog_step.get() )
  2906.         self.Rapid_Move( 0,-JOG_STEP )
  2907.  
  2908.     def Rapid_Move(self,dx,dy):
  2909.         if self.GUI_Disabled:
  2910.             return
  2911.         if self.units.get()=="in":
  2912.             dx_inches = round(dx,3)
  2913.             dy_inches = round(dy,3)
  2914.         else:
  2915.             dx_inches = round(dx/25.4,3)
  2916.             dy_inches = round(dy/25.4,3)
  2917.  
  2918.         if (self.HomeUR.get()):
  2919.             dx_inches = -dx_inches
  2920.  
  2921.         Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches)
  2922.         dxmils = (Xnew - self.laserX)*1000.0
  2923.         dymils = (Ynew - self.laserY)*1000.0
  2924.  
  2925.         if self.k40 == None:
  2926.             self.laserX  = Xnew
  2927.             self.laserY  = Ynew
  2928.             self.menu_View_Refresh()
  2929.         elif self.Send_Rapid_Move(dxmils,dymils):
  2930.             self.laserX  = Xnew
  2931.             self.laserY  = Ynew
  2932.             self.menu_View_Refresh()
  2933.        
  2934.  
  2935.     def Send_Rapid_Move(self,dxmils,dymils):
  2936.         try:
  2937.             if self.k40 != None:
  2938.                 Xscale = float(self.LaserXscale.get())
  2939.                 Yscale = float(self.LaserYscale.get())
  2940.                 if self.rotary.get():
  2941.                     Rscale = float(self.LaserRscale.get())
  2942.                     Yscale = Yscale*Rscale
  2943.                    
  2944.                 if Xscale != 1.0 or Yscale != 1.0:    
  2945.                     dxmils = int(round(dxmils *Xscale))
  2946.                     dymils = int(round(dymils *Yscale))
  2947.                 self.k40.n_timeouts = 10
  2948.                
  2949.                 if self.rotary.get() and float(self.rapid_feed.get()):
  2950.                     self.slow_jog(int(dxmils),int(dymils))
  2951.                 else:
  2952.                     self.k40.rapid_move(int(dxmils),int(dymils))
  2953.  
  2954.  
  2955.                 return True
  2956.             else:
  2957.                 return True
  2958.         #except StandardError as e:
  2959.         except Exception as e:
  2960.             msg1 = "Rapid Move Failed: "
  2961.             msg2 = "%s" %(e)
  2962.             if msg2 == "":
  2963.                 formatted_lines = traceback.format_exc().splitlines()
  2964.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2965.             self.statusbar.configure( bg = 'red' )
  2966.             debug_message(traceback.format_exc())
  2967.             return False
  2968.  
  2969.  
  2970.     def slow_jog(self,dxmils,dymils):
  2971.         if int(dxmils)==0 and int(dymils)==0:
  2972.             return
  2973.         self.stop[0]=False
  2974.         Rapid_data=[]
  2975.         Rapid_inst = egv(target=lambda s:Rapid_data.append(s))
  2976.         Rapid_feed = float(self.rapid_feed.get())*self.feed_factor()
  2977.         Rapid_inst.make_egv_rapid(dxmils,dymils,Feed=Rapid_feed,board_name=self.board_name.get())
  2978.         self.send_egv_data(Rapid_data, 1, None)
  2979.         self.stop[0]=True
  2980.  
  2981.     def update_gui(self, message=None, bgcolor='white'):
  2982.         if message!=None:
  2983.             self.statusMessage.set(message)
  2984.             self.statusbar.configure( bg = bgcolor )
  2985.         self.master.update()
  2986.         return True
  2987.  
  2988.     def set_gui(self,new_state="normal"):
  2989.         if new_state=="normal":
  2990.             self.GUI_Disabled=False
  2991.         else:
  2992.             self.GUI_Disabled=True
  2993.  
  2994.         try:
  2995.             self.menuBar.entryconfigure("File"    , state=new_state)
  2996.             self.menuBar.entryconfigure("View"    , state=new_state)
  2997.             self.menuBar.entryconfigure("Tools"     , state=new_state)
  2998.             self.menuBar.entryconfigure("Settings", state=new_state)
  2999.             self.menuBar.entryconfigure("Help"    , state=new_state)
  3000.             self.PreviewCanvas.configure(state=new_state)
  3001.            
  3002.             for w in self.master.winfo_children():
  3003.                 try:
  3004.                     w.configure(state=new_state)
  3005.                 except:
  3006.                     pass
  3007.             self.Stop_Button.configure(state="normal")
  3008.             self.statusbar.configure(state="normal")
  3009.             self.master.update()
  3010.         except:
  3011.             if DEBUG:
  3012.                 debug_message(traceback.format_exc())
  3013.  
  3014.     def Vector_Cut(self, output_filename=None):
  3015.         self.Prepare_for_laser_run("Vector Cut: Processing Vector Data.")
  3016.         if self.VcutData.ecoords!=[]:
  3017.             self.send_data("Vector_Cut", output_filename)
  3018.         else:
  3019.             self.statusbar.configure( bg = 'yellow' )
  3020.             self.statusMessage.set("No vector data to cut")
  3021.         self.Finish_Job()
  3022.        
  3023.     def Vector_Eng(self, output_filename=None):
  3024.         self.Prepare_for_laser_run("Vector Engrave: Processing Vector Data.")
  3025.         if self.VengData.ecoords!=[]:
  3026.             self.send_data("Vector_Eng", output_filename)
  3027.         else:
  3028.             self.statusbar.configure( bg = 'yellow' )
  3029.             self.statusMessage.set("No vector data to engrave")
  3030.         self.Finish_Job()
  3031.  
  3032.     def Trace_Eng(self, output_filename=None):
  3033.         self.Prepare_for_laser_run("Boundary Trace: Processing Data.")
  3034.         self.trace_coords = self.make_trace_path()
  3035.  
  3036.         if self.trace_coords!=[]:
  3037.             self.send_data("Trace_Eng", output_filename)
  3038.         else:
  3039.             self.statusbar.configure( bg = 'yellow' )
  3040.             self.statusMessage.set("No trace data to follow")
  3041.         self.Finish_Job()
  3042.  
  3043.     def Raster_Eng(self, output_filename=None):
  3044.         self.Prepare_for_laser_run("Raster Engraving: Processing Image Data.")
  3045.         try:
  3046.             self.make_raster_coords()
  3047.             if self.RengData.ecoords!=[]:
  3048.                 self.send_data("Raster_Eng", output_filename)
  3049.             else:
  3050.                 self.statusbar.configure( bg = 'yellow' )
  3051.                 self.statusMessage.set("No raster data to engrave")
  3052.  
  3053.         except MemoryError as e:
  3054.             msg1 = "Memory Error:"
  3055.             msg2 = "Memory Error:  Out of Memory."
  3056.             self.statusMessage.set(msg2)
  3057.             self.statusbar.configure( bg = 'red' )
  3058.             message_box(msg1, msg2)
  3059.             debug_message(traceback.format_exc())
  3060.            
  3061.         except Exception as e:
  3062.             msg1 = "Making Raster Data Stopped: "
  3063.             msg2 = "%s" %(e)
  3064.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  3065.             self.statusbar.configure( bg = 'red' )
  3066.             message_box(msg1, msg2)
  3067.             debug_message(traceback.format_exc())
  3068.         self.Finish_Job()
  3069.  
  3070.     def Raster_Vector_Eng(self, output_filename=None):
  3071.         self.Prepare_for_laser_run("Raster Engraving: Processing Image and Vector Data.")
  3072.         try:
  3073.             self.make_raster_coords()
  3074.             if self.RengData.ecoords!=[] or self.VengData.ecoords!=[]:
  3075.                 self.send_data("Raster_Eng+Vector_Eng", output_filename)
  3076.             else:
  3077.                 self.statusbar.configure( bg = 'yellow' )
  3078.                 self.statusMessage.set("No data to engrave")
  3079.         except Exception as e:
  3080.             msg1 = "Preparing Data Stopped: "
  3081.             msg2 = "%s" %(e)
  3082.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  3083.             self.statusbar.configure( bg = 'red' )
  3084.             message_box(msg1, msg2)
  3085.             debug_message(traceback.format_exc())
  3086.         self.Finish_Job()
  3087.  
  3088.     def Vector_Eng_Cut(self, output_filename=None):
  3089.         self.Prepare_for_laser_run("Vector Cut: Processing Vector Data.")
  3090.         if self.VcutData.ecoords!=[] or self.VengData.ecoords!=[]:
  3091.             self.send_data("Vector_Eng+Vector_Cut", output_filename)
  3092.         else:
  3093.             self.statusbar.configure( bg = 'yellow' )
  3094.             self.statusMessage.set("No vector data.")
  3095.         self.Finish_Job()
  3096.        
  3097.     def Raster_Vector_Cut(self, output_filename=None):
  3098.         self.Prepare_for_laser_run("Raster Engraving: Processing Image and Vector Data.")
  3099.         try:
  3100.             self.make_raster_coords()
  3101.             if self.RengData.ecoords!=[] or self.VengData.ecoords!=[] or self.VcutData.ecoords!=[]:
  3102.                 self.send_data("Raster_Eng+Vector_Eng+Vector_Cut", output_filename)
  3103.             else:
  3104.                 self.statusbar.configure( bg = 'yellow' )
  3105.                 self.statusMessage.set("No data to engrave/cut")
  3106.         except Exception as e:
  3107.             msg1 = "Preparing Data Stopped: "
  3108.             msg2 = "%s" %(e)
  3109.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  3110.             self.statusbar.configure( bg = 'red' )
  3111.             message_box(msg1, msg2)
  3112.             debug_message(traceback.format_exc())
  3113.         self.Finish_Job()
  3114.        
  3115.     def Gcode_Cut(self, output_filename=None):
  3116.         self.Prepare_for_laser_run("G Code Cutting.")
  3117.         if self.GcodeData.ecoords!=[]:
  3118.             self.send_data("Gcode_Cut", output_filename)
  3119.         else:
  3120.             self.statusbar.configure( bg = 'yellow' )
  3121.             self.statusMessage.set("No g-code data to cut")
  3122.         self.Finish_Job()
  3123.  
  3124.     def Prepare_for_laser_run(self,msg):
  3125.         self.stop[0]=False
  3126.         self.move_head_window_temporary([0,0])
  3127.         self.set_gui("disabled")
  3128.         self.statusbar.configure( bg = 'green' )
  3129.         self.statusMessage.set(msg)
  3130.         self.master.update()
  3131.  
  3132.     def Finish_Job(self, event=None):
  3133.         self.set_gui("normal")
  3134.         self.stop[0]=True
  3135.         if self.post_home.get():
  3136.             self.Unlock()
  3137.  
  3138.         if self.post_beep.get():
  3139.             self.master.bell()
  3140.  
  3141.         stderr = ''
  3142.         stdout = ''
  3143.         if self.post_exec.get():
  3144.             cmd = [self.batch_path.get()]
  3145.             from subprocess import Popen, PIPE
  3146.             startupinfo=None
  3147.             proc = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE, startupinfo=startupinfo)
  3148.             stdout,stderr = proc.communicate()
  3149.  
  3150.         if self.post_disp.get() or stderr != '':
  3151.             msg1 = ''
  3152.             minutes = floor(self.run_time / 60)
  3153.             seconds = self.run_time - minutes*60
  3154.             msg2 = "Job Ended.\nRun Time = %02d:%02d" %(minutes,seconds)
  3155.             if stdout != '':
  3156.                 msg2=msg2+'\n\nBatch File Output:\n'+stdout
  3157.             if stderr != '':
  3158.                 msg2=msg2+'\n\nBatch File Errors:\n'+stderr
  3159.             self.run_time = 0
  3160.             message_box(msg1, msg2)
  3161.  
  3162.  
  3163.     def make_trace_path(self):
  3164.         my_hull = hull2D()
  3165.         if self.inputCSYS.get() and self.RengData.image == None:
  3166.             xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  3167.         else:
  3168.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  3169.            
  3170.         startx = xmin
  3171.         starty = ymax
  3172.  
  3173.         #######################################
  3174.         Vcut_coords = self.VcutData.ecoords
  3175.         Veng_coords = self.VengData.ecoords
  3176.         Gcode_coords= self.GcodeData.ecoords
  3177.         if self.mirror.get() or self.rotate.get():
  3178.             Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords)
  3179.             Veng_coords = self.mirror_rotate_vector_coords(Veng_coords)
  3180.             Gcode_coords= self.mirror_rotate_vector_coords(Gcode_coords)
  3181.  
  3182.         #######################################
  3183.         if self.RengData.ecoords==[]:
  3184.             if self.stop[0] == True:
  3185.                 self.stop[0]=False
  3186.                 self.make_raster_coords()
  3187.                 self.stop[0]=True
  3188.             else:
  3189.                 self.make_raster_coords()
  3190.  
  3191.         RengHullCoords = []
  3192.         Xscale = 1/float(self.LaserXscale.get())
  3193.         Yscale = 1/float(self.LaserYscale.get())
  3194.         if self.rotary.get():
  3195.             Rscale = 1/float(self.LaserRscale.get())
  3196.             Yscale = Yscale*Rscale
  3197.            
  3198.         for point in self.RengData.hull_coords:
  3199.             RengHullCoords.append([point[0]*Xscale+xmin, point[1]*Yscale, point[2]])
  3200.            
  3201.         all_coords = []
  3202.         all_coords.extend(Vcut_coords)
  3203.         all_coords.extend(Veng_coords)
  3204.         all_coords.extend(Gcode_coords)
  3205.         all_coords.extend(RengHullCoords)
  3206.  
  3207.         trace_coords=[]
  3208.         if all_coords != []:
  3209.             trace_coords = my_hull.convexHullecoords(all_coords)
  3210.             gap = float(self.trace_gap.get())/self.units_scale
  3211.             trace_coords = self.offset_eccords(trace_coords,gap)
  3212.  
  3213.         trace_coords,startx,starty = self.scale_vector_coords(trace_coords,startx,starty)
  3214.         return trace_coords
  3215.  
  3216.            
  3217.     ################################################################################
  3218.     def Sort_Paths(self,ecoords,i_loop=2):
  3219.         ##########################
  3220.         ###   find loop ends   ###
  3221.         ##########################
  3222.         Lbeg=[]
  3223.         Lend=[]
  3224.         if len(ecoords)>0:
  3225.             Lbeg.append(0)
  3226.             loop_old=ecoords[0][i_loop]
  3227.             for i in range(1,len(ecoords)):
  3228.                 loop = ecoords[i][i_loop]
  3229.                 if loop != loop_old:
  3230.                     Lbeg.append(i)
  3231.                     Lend.append(i-1)
  3232.                 loop_old=loop
  3233.             Lend.append(i)
  3234.  
  3235.         #######################################################
  3236.         # Find new order based on distance to next beg or end #
  3237.         #######################################################
  3238.         order_out = []
  3239.         use_beg=0
  3240.         if len(ecoords)>0:
  3241.             order_out.append([Lbeg[0],Lend[0]])
  3242.         inext = 0
  3243.         total=len(Lbeg)
  3244.         for i in range(total-1):
  3245.             if use_beg==1:
  3246.                 ii=Lbeg.pop(inext)
  3247.                 Lend.pop(inext)
  3248.             else:
  3249.                 ii=Lend.pop(inext)
  3250.                 Lbeg.pop(inext)
  3251.  
  3252.             Xcur = ecoords[ii][0]
  3253.             Ycur = ecoords[ii][1]
  3254.  
  3255.             dx = Xcur - ecoords[ Lbeg[0] ][0]
  3256.             dy = Ycur - ecoords[ Lbeg[0] ][1]
  3257.             min_dist = dx*dx + dy*dy
  3258.  
  3259.             dxe = Xcur - ecoords[ Lend[0] ][0]
  3260.             dye = Ycur - ecoords[ Lend[0] ][1]
  3261.             min_diste = dxe*dxe + dye*dye
  3262.  
  3263.             inext=0
  3264.             inexte=0
  3265.             for j in range(1,len(Lbeg)):
  3266.                 dx = Xcur - ecoords[ Lbeg[j] ][0]
  3267.                 dy = Ycur - ecoords[ Lbeg[j] ][1]
  3268.                 dist = dx*dx + dy*dy
  3269.                 if dist < min_dist:
  3270.                     min_dist=dist
  3271.                     inext=j
  3272.                 ###
  3273.                 dxe = Xcur - ecoords[ Lend[j] ][0]
  3274.                 dye = Ycur - ecoords[ Lend[j] ][1]
  3275.                 diste = dxe*dxe + dye*dye
  3276.                 if diste < min_diste:
  3277.                     min_diste=diste
  3278.                     inexte=j
  3279.                 ###
  3280.             if min_diste < min_dist:
  3281.                 inext=inexte
  3282.                 order_out.append([Lend[inexte],Lbeg[inexte]])
  3283.                 use_beg=1
  3284.             else:
  3285.                 order_out.append([Lbeg[inext],Lend[inext]])
  3286.                 use_beg=0
  3287.         ###########################################################
  3288.         return order_out
  3289.    
  3290.     #####################################################
  3291.     # determine if a point is inside a given polygon or not
  3292.     # Polygon is a list of (x,y) pairs.
  3293.     # http://www.ariel.com.au/a/python-point-int-poly.html
  3294.     #####################################################
  3295.     def point_inside_polygon(self,x,y,poly):
  3296.         n = len(poly)
  3297.         inside = -1
  3298.         p1x = poly[0][0]
  3299.         p1y = poly[0][1]
  3300.         for i in range(n+1):
  3301.             p2x = poly[i%n][0]
  3302.             p2y = poly[i%n][1]
  3303.             if y > min(p1y,p2y):
  3304.                 if y <= max(p1y,p2y):
  3305.                     if x <= max(p1x,p2x):
  3306.                         if p1y != p2y:
  3307.                             xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
  3308.                         if p1x == p2x or x <= xinters:
  3309.                             inside = inside * -1
  3310.             p1x,p1y = p2x,p2y
  3311.  
  3312.         return inside
  3313.  
  3314.     def optimize_paths(self,ecoords,inside_check=True):
  3315.         order_out = self.Sort_Paths(ecoords)    
  3316.         lastx=-999
  3317.         lasty=-999
  3318.         Acc=0.004
  3319.         cuts=[]
  3320.  
  3321.         for line in order_out:
  3322.             temp=line
  3323.             if temp[0] > temp[1]:
  3324.                 step = -1
  3325.             else:
  3326.                 step = 1
  3327.  
  3328.             loop_old = -1
  3329.            
  3330.             for i in range(temp[0],temp[1]+step,step):
  3331.                 x1   = ecoords[i][0]
  3332.                 y1   = ecoords[i][1]
  3333.                 loop = ecoords[i][2]
  3334.                 # check and see if we need to move to a new discontinuous start point
  3335.                 if (loop != loop_old):
  3336.                     dx = x1-lastx
  3337.                     dy = y1-lasty
  3338.                     dist = sqrt(dx*dx + dy*dy)
  3339.                     if dist > Acc:
  3340.                         cuts.append([[x1,y1]])
  3341.                     else:
  3342.                         cuts[-1].append([x1,y1])
  3343.                 else:
  3344.                     cuts[-1].append([x1,y1])
  3345.                 lastx = x1
  3346.                 lasty = y1
  3347.                 loop_old = loop
  3348.  
  3349.         if inside_check:
  3350.             #####################################################
  3351.             # For each loop determine if other loops are inside #
  3352.             #####################################################
  3353.             Nloops=len(cuts)
  3354.             self.LoopTree=[]
  3355.             for iloop in range(Nloops):
  3356.                 self.LoopTree.append([])
  3357.     ##            CUR_PCT=float(iloop)/Nloops*100.0
  3358.     ##            if (not self.batch.get()):
  3359.     ##                self.statusMessage.set('Determining Which Side of Loop to Cut: %d of %d' %(iloop+1,Nloops))
  3360.     ##                self.master.update()
  3361.                 ipoly = cuts[iloop]
  3362.                 ## Check points in other loops (could just check one) ##
  3363.                 if ipoly != []:
  3364.                     for jloop in range(Nloops):
  3365.                         if jloop != iloop:
  3366.                             inside = 0
  3367.                             inside = inside + self.point_inside_polygon(cuts[jloop][0][0],cuts[jloop][0][1],ipoly)
  3368.                             if inside > 0:
  3369.                                 self.LoopTree[iloop].append(jloop)
  3370.             #####################################################
  3371.             for i in range(Nloops):
  3372.                 lns=[]
  3373.                 lns.append(i)
  3374.                 self.remove_self_references(lns,self.LoopTree[i])
  3375.  
  3376.             self.order=[]
  3377.             self.loops = list(range(Nloops))
  3378.             for i in range(Nloops):
  3379.                 if self.LoopTree[i]!=[]:
  3380.                     self.addlist(self.LoopTree[i])
  3381.                     self.LoopTree[i]=[]
  3382.                 if self.loops[i]!=[]:
  3383.                     self.order.append(self.loops[i])
  3384.                     self.loops[i]=[]
  3385.         #END inside_check
  3386.             ecoords_out = []
  3387.             for i in self.order:
  3388.                 line = cuts[i]
  3389.                 for coord in line:
  3390.                     ecoords_out.append([coord[0],coord[1],i])
  3391.         #END inside_check
  3392.         else:
  3393.             ecoords_out = []
  3394.             for i in range(len(cuts)):
  3395.                 line = cuts[i]
  3396.                 for coord in line:
  3397.                     ecoords_out.append([coord[0],coord[1],i])
  3398.                    
  3399.         return ecoords_out
  3400.            
  3401.     def remove_self_references(self,loop_numbers,loops):
  3402.         for i in range(0,len(loops)):
  3403.             for j in range(0,len(loop_numbers)):
  3404.                 if loops[i]==loop_numbers[j]:
  3405.                     loops.pop(i)
  3406.                     return
  3407.             if self.LoopTree[loops[i]]!=[]:
  3408.                 loop_numbers.append(loops[i])
  3409.                 self.remove_self_references(loop_numbers,self.LoopTree[loops[i]])
  3410.  
  3411.     def addlist(self,list):
  3412.         for i in list:
  3413.             try: #this try/except is a bad hack fix to a recursion error. It should be fixed properly later.
  3414.                 if self.LoopTree[i]!=[]:
  3415.                     self.addlist(self.LoopTree[i]) #too many recursions here causes cmp error
  3416.                     self.LoopTree[i]=[]
  3417.             except:
  3418.                 pass
  3419.             if self.loops[i]!=[]:
  3420.                 self.order.append(self.loops[i])
  3421.                 self.loops[i]=[]
  3422.  
  3423.  
  3424.     def mirror_rotate_vector_coords(self,coords):
  3425.         xmin = self.Design_bounds[0]
  3426.         xmax = self.Design_bounds[1]
  3427.         coords_rotate_mirror=[]
  3428.        
  3429.         for i in range(len(coords)):
  3430.             coords_rotate_mirror.append(coords[i][:])
  3431.             if self.mirror.get():
  3432.                 if self.inputCSYS.get() and self.RengData.image == None:
  3433.                     coords_rotate_mirror[i][0]=-coords_rotate_mirror[i][0]
  3434.                 else:
  3435.                     coords_rotate_mirror[i][0]=xmin+xmax-coords_rotate_mirror[i][0]
  3436.                
  3437.                
  3438.             if self.rotate.get():
  3439.                 x = coords_rotate_mirror[i][0]
  3440.                 y = coords_rotate_mirror[i][1]
  3441.                 coords_rotate_mirror[i][0] = -y
  3442.                 coords_rotate_mirror[i][1] =  x
  3443.                
  3444.         return coords_rotate_mirror
  3445.  
  3446.     def scale_vector_coords(self,coords,startx,starty):
  3447.        
  3448.         Xscale = float(self.LaserXscale.get())
  3449.         Yscale = float(self.LaserYscale.get())
  3450.         if self.rotary.get():
  3451.             Rscale = float(self.LaserRscale.get())
  3452.             Yscale = Yscale*Rscale
  3453.  
  3454.         coords_scale=[]
  3455.         if Xscale != 1.0 or Yscale != 1.0:
  3456.             for i in range(len(coords)):
  3457.                 coords_scale.append(coords[i][:])
  3458.                 x = coords_scale[i][0]
  3459.                 y = coords_scale[i][1]
  3460.                 coords_scale[i][0] = x*Xscale
  3461.                 coords_scale[i][1] = y*Yscale
  3462.             scaled_startx = startx*Xscale
  3463.             scaled_starty = starty*Yscale
  3464.         else:
  3465.             coords_scale = coords
  3466.             scaled_startx = startx
  3467.             scaled_starty = starty
  3468.  
  3469.         return coords_scale,scaled_startx,scaled_starty
  3470.  
  3471.  
  3472.     def feed_factor(self):
  3473.         if self.units.get()=='in':
  3474.             feed_factor = 25.4/60.0
  3475.         else:
  3476.             feed_factor = 1.0
  3477.         return feed_factor
  3478.  
  3479.     def send_data(self,operation_type=None, output_filename=None):
  3480.         num_passes=0
  3481.         if self.k40 == None and output_filename == None:
  3482.             self.statusMessage.set("Laser Cutter is not Initialized...")
  3483.             self.statusbar.configure( bg = 'red' )
  3484.             return
  3485.         try:
  3486.             feed_factor=self.feed_factor()
  3487.            
  3488.             if self.inputCSYS.get() and self.RengData.image == None:
  3489.                 xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  3490.             else:
  3491.                 xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  3492.                        
  3493.             startx = xmin
  3494.             starty = ymax
  3495.  
  3496.             if self.HomeUR.get():
  3497.                 Xscale = float(self.LaserXscale.get())
  3498.                 FlipXoffset = Xscale*xmin + Xscale*xmax
  3499.                 if self.rotate.get():
  3500.                     startx = -xmin
  3501.             else:
  3502.                 FlipXoffset = None
  3503.  
  3504.             if self.rotary.get():
  3505.                 Rapid_Feed = float(self.rapid_feed.get())*feed_factor
  3506.             else:
  3507.                 Rapid_Feed = 0.0
  3508.                
  3509.             Raster_Eng_data=[]
  3510.             Vector_Eng_data=[]
  3511.             Trace_Eng_data=[]
  3512.             Vector_Cut_data=[]
  3513.             G_code_Cut_data=[]
  3514.                        
  3515.             if (operation_type.find("Vector_Cut") > -1) and  (self.VcutData.ecoords!=[]):
  3516.                 Feed_Rate = float(self.Vcut_feed.get())*feed_factor
  3517.                 self.statusMessage.set("Vector Cut: Determining Cut Order....")
  3518.                 self.master.update()
  3519.                 if not self.VcutData.sorted and self.inside_first.get():
  3520.                     self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True)
  3521.  
  3522.  
  3523. ##                DEBUG_PLOT=False
  3524. ##                test_ecoords=self.VcutData.ecoords
  3525. ##                if DEBUG_PLOT:
  3526. ##                    import matplotlib.pyplot as plt
  3527. ##                    plt.ion()
  3528. ##                    plt.clf()        
  3529. ##                    X=[]
  3530. ##                    Y=[]
  3531. ##                    LOOP_OLD = test_ecoords[0][2]
  3532. ##                    for i in range(len(test_ecoords)):
  3533. ##                        LOOP = test_ecoords[i][2]
  3534. ##                        if LOOP != LOOP_OLD:
  3535. ##                            plt.plot(X,Y)
  3536. ##                            plt.pause(.5)
  3537. ##                            X=[]
  3538. ##                            Y=[]
  3539. ##                            LOOP_OLD=LOOP
  3540. ##                        X.append(test_ecoords[i][0])
  3541. ##                        Y.append(test_ecoords[i][1])
  3542. ##                    plt.plot(X,Y)
  3543.  
  3544.  
  3545.                 self.statusMessage.set("Generating EGV data...")
  3546.                 self.master.update()
  3547.  
  3548.                 Vcut_coords = self.VcutData.ecoords
  3549.                 if self.mirror.get() or self.rotate.get():
  3550.                     Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords)
  3551.  
  3552.                 Vcut_coords,startx,starty = self.scale_vector_coords(Vcut_coords,startx,starty)
  3553.                 Vector_Cut_egv_inst = egv(target=lambda s:Vector_Cut_data.append(s))  
  3554.                 Vector_Cut_egv_inst.make_egv_data(
  3555.                                                 Vcut_coords,                      \
  3556.                                                 startX=startx,                    \
  3557.                                                 startY=starty,                    \
  3558.                                                 Feed = Feed_Rate,                 \
  3559.                                                 board_name=self.board_name.get(), \
  3560.                                                 Raster_step = 0,                  \
  3561.                                                 update_gui=self.update_gui,       \
  3562.                                                 stop_calc=self.stop,              \
  3563.                                                 FlipXoffset=FlipXoffset,          \
  3564.                                                 Rapid_Feed_Rate = Rapid_Feed,     \
  3565.                                                 use_laser=True
  3566.                                                 )
  3567.  
  3568.             if (operation_type.find("Vector_Eng") > -1) and  (self.VengData.ecoords!=[]):
  3569.                 Feed_Rate = float(self.Veng_feed.get())*feed_factor
  3570.                 self.statusMessage.set("Vector Engrave: Determining Cut Order....")
  3571.                 self.master.update()
  3572.                 if not self.VengData.sorted and self.inside_first.get():
  3573.                     self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords,inside_check=False),data_sorted=True)
  3574.                 self.statusMessage.set("Generating EGV data...")
  3575.                 self.master.update()
  3576.  
  3577.                 Veng_coords = self.VengData.ecoords
  3578.                 if self.mirror.get() or self.rotate.get():
  3579.                     Veng_coords = self.mirror_rotate_vector_coords(Veng_coords)
  3580.  
  3581.                 Veng_coords,startx,starty = self.scale_vector_coords(Veng_coords,startx,starty)
  3582.                 Vector_Eng_egv_inst = egv(target=lambda s:Vector_Eng_data.append(s))
  3583.                 Vector_Eng_egv_inst.make_egv_data(
  3584.                                                 Veng_coords,                      \
  3585.                                                 startX=startx,                    \
  3586.                                                 startY=starty,                    \
  3587.                                                 Feed = Feed_Rate,                 \
  3588.                                                 board_name=self.board_name.get(), \
  3589.                                                 Raster_step = 0,                  \
  3590.                                                 update_gui=self.update_gui,       \
  3591.                                                 stop_calc=self.stop,              \
  3592.                                                 FlipXoffset=FlipXoffset,          \
  3593.                                                 Rapid_Feed_Rate = Rapid_Feed,     \
  3594.                                                 use_laser=True
  3595.                                                 )
  3596.  
  3597.  
  3598.             if (operation_type.find("Trace_Eng") > -1) and (self.trace_coords!=[]):
  3599.                 Feed_Rate = float(self.trace_speed.get())*feed_factor
  3600.                 laser_on = self.trace_w_laser.get()
  3601.                 self.statusMessage.set("Generating EGV data...")
  3602.                 self.master.update()
  3603.                 Trace_Eng_egv_inst = egv(target=lambda s:Trace_Eng_data.append(s))
  3604.                 Trace_Eng_egv_inst.make_egv_data(
  3605.                                                 self.trace_coords,                \
  3606.                                                 startX=startx,                    \
  3607.                                                 startY=starty,                    \
  3608.                                                 Feed = Feed_Rate,                 \
  3609.                                                 board_name=self.board_name.get(), \
  3610.                                                 Raster_step = 0,                  \
  3611.                                                 update_gui=self.update_gui,       \
  3612.                                                 stop_calc=self.stop,              \
  3613.                                                 FlipXoffset=FlipXoffset,          \
  3614.                                                 Rapid_Feed_Rate = Rapid_Feed,     \
  3615.                                                 use_laser=laser_on
  3616.                                                 )
  3617.                
  3618.                
  3619.             if (operation_type.find("Raster_Eng") > -1) and  (self.RengData.ecoords!=[]):
  3620.                 Feed_Rate = float(self.Reng_feed.get())*feed_factor
  3621.                 Raster_step = self.get_raster_step_1000in()
  3622.                 if not self.engraveUP.get():
  3623.                     Raster_step = -Raster_step
  3624.                    
  3625.                 raster_startx = 0
  3626.  
  3627.                 Yscale = float(self.LaserYscale.get())
  3628.                 if self.rotary.get():
  3629.                     Rscale = float(self.LaserRscale.get())
  3630.                     Yscale = Yscale*Rscale
  3631.                 raster_starty = Yscale*starty
  3632.  
  3633.                 self.statusMessage.set("Generating EGV data...")
  3634.                 self.master.update()
  3635.                 Raster_Eng_egv_inst = egv(target=lambda s:Raster_Eng_data.append(s))
  3636.                 Raster_Eng_egv_inst.make_egv_data(
  3637.                                                 self.RengData.ecoords,            \
  3638.                                                 startX=raster_startx,             \
  3639.                                                 startY=raster_starty,             \
  3640.                                                 Feed = Feed_Rate,                 \
  3641.                                                 board_name=self.board_name.get(), \
  3642.                                                 Raster_step = Raster_step,        \
  3643.                                                 update_gui=self.update_gui,       \
  3644.                                                 stop_calc=self.stop,              \
  3645.                                                 FlipXoffset=FlipXoffset,          \
  3646.                                                 Rapid_Feed_Rate = Rapid_Feed,     \
  3647.                                                 use_laser=True
  3648.                                                 )
  3649.                 #print(len(Raster_Eng_data))
  3650.                 Raster_Eng_data=Raster_Eng_egv_inst.strip_redundant_codes(Raster_Eng_data)
  3651.                 #print(len(Raster_Eng_data))
  3652.  
  3653.             if (operation_type.find("Gcode_Cut") > -1) and (self.GcodeData.ecoords!=[]):
  3654.                 self.statusMessage.set("Generating EGV data...")
  3655.                 self.master.update()
  3656.                 Gcode_coords = self.GcodeData.ecoords
  3657.                 if self.mirror.get() or self.rotate.get():
  3658.                     Gcode_coords = self.mirror_rotate_vector_coords(Gcode_coords)
  3659.  
  3660.                 Gcode_coords,startx,starty = self.scale_vector_coords(Gcode_coords,startx,starty)
  3661.                 G_code_Cut_egv_inst = egv(target=lambda s:G_code_Cut_data.append(s))
  3662.                 G_code_Cut_egv_inst.make_egv_data(
  3663.                                                 Gcode_coords,                     \
  3664.                                                 startX=startx,                    \
  3665.                                                 startY=starty,                    \
  3666.                                                 Feed = None,                      \
  3667.                                                 board_name=self.board_name.get(), \
  3668.                                                 Raster_step = 0,                  \
  3669.                                                 update_gui=self.update_gui,       \
  3670.                                                 stop_calc=self.stop,              \
  3671.                                                 FlipXoffset=FlipXoffset,          \
  3672.                                                 Rapid_Feed_Rate = Rapid_Feed,     \
  3673.                                                 use_laser=True
  3674.                                                 )
  3675.                
  3676.             ### Join Resulting Data together ###
  3677.             data=[]
  3678.             data.append(ord("I"))
  3679.             if Trace_Eng_data!=[]:
  3680.                 trace_passes=1
  3681.                 for k in range(trace_passes):
  3682.                     if len(data)> 4:
  3683.                         data[-4]=ord("@")
  3684.                     data.extend(Trace_Eng_data)
  3685.             if Raster_Eng_data!=[]:
  3686.                 num_passes = int(float(self.Reng_passes.get()))
  3687.                 for k in range(num_passes):
  3688.                     if len(data)> 4:
  3689.                         data[-4]=ord("@")
  3690.                     data.extend(Raster_Eng_data)
  3691.             if Vector_Eng_data!=[]:
  3692.                 num_passes = int(float(self.Veng_passes.get()))
  3693.                 for k in range(num_passes):
  3694.                     if len(data)> 4:
  3695.                         data[-4]=ord("@")
  3696.                     data.extend(Vector_Eng_data)
  3697.             if Vector_Cut_data!=[]:
  3698.                 num_passes = int(float(self.Vcut_passes.get()))
  3699.                 for k in range(num_passes):
  3700.                     if len(data)> 4:
  3701.                         data[-4]=ord("@")
  3702.                     data.extend(Vector_Cut_data)
  3703.             if G_code_Cut_data!=[]:
  3704.                 num_passes = int(float(self.Gcde_passes.get()))
  3705.                 for k in range(num_passes):
  3706.                     if len(data)> 4:
  3707.                         data[-4]=ord("@")
  3708.                     data.extend(G_code_Cut_data)
  3709.             if len(data)< 4:
  3710.                 raise Exception("No laser data was generated.")    
  3711.                
  3712.             self.master.update()
  3713.             if output_filename != None:
  3714.                 self.write_egv_to_file(data,output_filename)
  3715.             else:
  3716.                 self.send_egv_data(data, 1, output_filename)
  3717.                 self.menu_View_Refresh()
  3718.                
  3719.         except MemoryError as e:
  3720.             msg1 = "Memory Error:"
  3721.             msg2 = "Memory Error:  Out of Memory."
  3722.             self.statusMessage.set(msg2)
  3723.             self.statusbar.configure( bg = 'red' )
  3724.             message_box(msg1, msg2)
  3725.             debug_message(traceback.format_exc())
  3726.        
  3727.         except Exception as e:
  3728.             msg1 = "Sending Data Stopped: "
  3729.             msg2 = "%s" %(e)
  3730.             if msg2 == "":
  3731.                 formatted_lines = traceback.format_exc().splitlines()
  3732.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  3733.             self.statusbar.configure( bg = 'red' )
  3734.             message_box(msg1, msg2)
  3735.             debug_message(traceback.format_exc())
  3736.  
  3737.     def send_egv_data(self,data,num_passes=1,output_filename=None):        
  3738.         pre_process_CRC        = self.pre_pr_crc.get()
  3739.         if self.k40 != None:
  3740.             self.k40.timeout       = int(float( self.t_timeout.get()  ))
  3741.             self.k40.n_timeouts    = int(float( self.n_timeouts.get() ))
  3742.             time_start = time()
  3743.             self.k40.send_data(data,self.update_gui,self.stop,num_passes,pre_process_CRC, wait_for_laser=self.wait.get())
  3744.             self.run_time = time()-time_start
  3745.             if DEBUG:
  3746.                 print(("Elapsed Time: %.6f" %(time()-time_start)))
  3747.            
  3748.         else:
  3749.             self.statusMessage.set("Laser is not initialized.")
  3750.             self.statusbar.configure( bg = 'yellow' )
  3751.             return
  3752.         self.menu_View_Refresh()
  3753.        
  3754.     ##########################################################################
  3755.     ##########################################################################
  3756.     def write_egv_to_file(self,data,fname):
  3757.         if len(data) == 0:
  3758.             raise Exception("No data available to write to file.")
  3759.         try:
  3760.             fout = open(fname,'w')
  3761.         except:
  3762.             raise Exception("Unable to open file ( %s ) for writing." %(fname))
  3763.         fout.write("Document type : LHYMICRO-GL file\n")
  3764.         fout.write("Creator-Software: K40 Whisperer\n")
  3765.        
  3766.         fout.write("\n")
  3767.         fout.write("%0%0%0%0%")
  3768.         for char_val in data:
  3769.             char = chr(char_val)
  3770.             fout.write("%s" %(char))
  3771.            
  3772.         #fout.write("\n")
  3773.         fout.close
  3774.         self.menu_View_Refresh()
  3775.         self.statusMessage.set("Data saved to: %s" %(fname))
  3776.        
  3777.     def Home(self, event=None):
  3778.         if self.GUI_Disabled:
  3779.             return
  3780.         if self.k40 != None:
  3781.             self.k40.home_position()
  3782.         self.laserX  = 0.0
  3783.         self.laserY  = 0.0
  3784.         self.pos_offset = [0.0,0.0]
  3785.         self.menu_View_Refresh()
  3786.  
  3787.     def GoTo(self):
  3788.         xpos = float(self.gotoX.get())
  3789.         ypos = float(self.gotoY.get())
  3790.         if self.k40 != None:
  3791.             self.k40.home_position()
  3792.         self.laserX  = 0.0
  3793.         self.laserY  = 0.0
  3794.         self.Rapid_Move(xpos,ypos)
  3795.         self.menu_View_Refresh()  
  3796.        
  3797.     def Reset(self):
  3798.         if self.k40 != None:
  3799.             try:
  3800.                 self.k40.reset_usb()
  3801.                 self.statusMessage.set("USB Reset Succeeded")
  3802.             except:
  3803.                 debug_message(traceback.format_exc())
  3804.                 pass
  3805.            
  3806.     def Stop(self,event=None):
  3807.         if self.stop[0]==True:
  3808.             return
  3809.         line1 = "Sending data to the laser from K40 Whisperer is currently Paused."
  3810.         line2 = "Press \"OK\" to abort any jobs currently running."
  3811.         line3 = "Press \"Cancel\" to resume."
  3812.         if self.k40 != None:
  3813.             try:
  3814.                 self.k40.pause_un_pause()
  3815.             except:
  3816.                 if message_ask_ok_cancel("Stop Laser Job.", "\n%s\n%s" %(line2,line3)):
  3817.                     self.stop[0]=True
  3818.                
  3819.         if message_ask_ok_cancel("Stop Laser Job.", "%s\n\n%s\n%s" %(line1,line2,line3)):
  3820.             self.stop[0]=True
  3821.         else:
  3822.             if self.k40 != None:
  3823.                 self.k40.pause_un_pause()
  3824.  
  3825.     def Hide_Advanced(self,event=None):
  3826.         self.advanced.set(0)
  3827.         self.menu_View_Refresh()
  3828.  
  3829.     def Release_USB(self):
  3830.         if self.k40 != None:
  3831.             try:
  3832.                 self.k40.release_usb()
  3833.                 self.statusMessage.set("USB Release Succeeded")
  3834.             except:
  3835.                 debug_message(traceback.format_exc())
  3836.                 pass
  3837.             self.k40=None
  3838.        
  3839.     def Initialize_Laser(self,event=None):
  3840.         if self.GUI_Disabled:
  3841.             return
  3842.         #lovejoy
  3843.         #self.stop[0]=True
  3844.         self.stop[0]=False
  3845.         self.Release_USB()
  3846.         self.k40=None
  3847.         self.move_head_window_temporary([0.0,0.0])      
  3848.         self.k40=K40_CLASS()
  3849.         try:
  3850.             self.k40.initialize_device()
  3851.             self.k40.say_hello()
  3852.             if self.init_home.get():
  3853.                 self.Home()
  3854.             else:
  3855.                 self.Unlock()
  3856.  
  3857.         except Exception as e:
  3858.             error_text = "%s" %(e)
  3859.             if "BACKEND" in error_text.upper():
  3860.                 error_text = error_text + " (libUSB driver not installed)"
  3861.             self.statusMessage.set("USB Error: %s" %(error_text))
  3862.             self.statusbar.configure( bg = 'red' )
  3863.             self.k40=None
  3864.             debug_message(traceback.format_exc())
  3865.  
  3866.         except:
  3867.             self.statusMessage.set("Unknown USB Error")
  3868.             self.statusbar.configure( bg = 'red' )
  3869.             self.k40=None
  3870.             debug_message(traceback.format_exc())
  3871.  
  3872.     def Unfreeze_Laser(self,event=None):
  3873.         if self.GUI_Disabled:
  3874.             return
  3875.         if self.k40 != None:
  3876.             try:
  3877.                 self.k40.unfreeze()
  3878.                 self.statusMessage.set("Unfreeze Complete")
  3879.                 self.statusbar.configure( bg = 'white' )
  3880.             except:
  3881.                 pass
  3882.            
  3883.     def Unlock(self,event=None):
  3884.         if self.GUI_Disabled:
  3885.             return
  3886.         if self.k40 != None:
  3887.             try:
  3888.                 self.k40.unlock_rail()
  3889.                 self.statusMessage.set("Rail Unlock Succeeded")
  3890.                 self.statusbar.configure( bg = 'white' )
  3891.             except:
  3892.                 self.statusMessage.set("Rail Unlock Failed.")
  3893.                 self.statusbar.configure( bg = 'red' )
  3894.                 debug_message(traceback.format_exc())
  3895.                 pass
  3896.    
  3897.     ##########################################################################
  3898.     ##########################################################################
  3899.            
  3900.     def menu_File_Quit(self):
  3901.         if message_ask_ok_cancel("Exit", "Exiting...."):
  3902.             self.Quit_Click(None)
  3903.  
  3904.     def Reset_RasterPath_and_Update_Time(self, varName=0, index=0, mode=0):
  3905.         self.RengData.reset_path()
  3906.         self.refreshTime()
  3907.  
  3908.     def View_Refresh_and_Reset_RasterPath(self, varName=0, index=0, mode=0):
  3909.         self.RengData.reset_path()
  3910.         self.SCALE = 0
  3911.         self.menu_View_Refresh()
  3912.  
  3913.     def menu_View_inputCSYS_Refresh_Callback(self, varName, index, mode):
  3914.         self.move_head_window_temporary([0.0,0.0])
  3915.         self.SCALE = 0
  3916.         self.menu_View_Refresh()
  3917.  
  3918.     def menu_View_Refresh_Callback(self, varName=0, index=0, mode=0):
  3919.         self.SCALE = 0
  3920.         self.menu_View_Refresh()
  3921.  
  3922.         if DEBUG:
  3923.             curframe = inspect.currentframe()
  3924.             calframe = inspect.getouterframes(curframe, 2)
  3925.             print('menu_View_Refresh_Callback called by: %s' %(calframe[1][3]))
  3926.  
  3927.     def menu_View_Refresh(self):
  3928.         if DEBUG:
  3929.             curframe = inspect.currentframe()
  3930.             calframe = inspect.getouterframes(curframe, 2)
  3931.             print('menu_View_Refresh called by: %s' %(calframe[1][3]))
  3932.  
  3933.         try:
  3934.             app.master.title(title_text+"   "+ self.DESIGN_FILE)
  3935.         except:
  3936.             pass
  3937.         dummy_event = Event()
  3938.         dummy_event.widget=self.master
  3939.         self.Master_Configure(dummy_event,1)
  3940.         self.Plot_Data()
  3941.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  3942.         W = xmax-xmin
  3943.         H = ymax-ymin
  3944.  
  3945.         if self.units.get()=="in":
  3946.             X_display = self.laserX + self.pos_offset[0]/1000.0
  3947.             Y_display = self.laserY + self.pos_offset[1]/1000.0
  3948.             W_display = W
  3949.             H_display = H
  3950.             U_display = self.units.get()
  3951.         else:
  3952.             X_display = (self.laserX + self.pos_offset[0]/1000.0)*self.units_scale
  3953.             Y_display = (self.laserY + self.pos_offset[1]/1000.0)*self.units_scale
  3954.             W_display = W*self.units_scale
  3955.             H_display = H*self.units_scale
  3956.             U_display = self.units.get()
  3957.         if self.HomeUR.get():
  3958.             X_display = -X_display
  3959.  
  3960.         self.statusMessage.set(" Current Position: X=%.3f Y=%.3f    ( W X H )=( %.3f%s X %.3f%s ) "
  3961.                                 %(X_display,
  3962.                                   Y_display,
  3963.                                   W_display,
  3964.                                   U_display,
  3965.                                   H_display,
  3966.                                   U_display))
  3967.  
  3968.         self.statusbar.configure( bg = 'white' )
  3969.        
  3970.     def menu_Inside_First_Callback(self, varName, index, mode):
  3971.         if self.GcodeData.ecoords != []:
  3972.             if self.VcutData.sorted == True:
  3973.                 self.menu_Reload_Design()
  3974.             elif self.VengData.sorted == True:
  3975.                 self.menu_Reload_Design()
  3976.  
  3977.     def menu_Mode_Change(self):
  3978.         dummy_event = Event()
  3979.         dummy_event.widget=self.master
  3980.         self.Master_Configure(dummy_event,1)
  3981.  
  3982.     def menu_Calc_Raster_Time(self,event=None):
  3983.         self.set_gui("disabled")
  3984.         self.stop[0]=False
  3985.         self.make_raster_coords()
  3986.         self.stop[0]=True
  3987.         self.refreshTime()
  3988.         self.set_gui("normal")
  3989.         self.menu_View_Refresh()
  3990.        
  3991.  
  3992.     def menu_Help_About(self):
  3993.         application="K40 Whisperer"
  3994.         about = "%s Version %s\n\n" %(application,version)
  3995.         about = about + "By Scorch.\n"
  3996.         about = about + "\163\143\157\162\143\150\100\163\143\157\162"
  3997.         about = about + "\143\150\167\157\162\153\163\056\143\157\155\n"
  3998.         about = about + "https://www.scorchworks.com/\n\n"
  3999.         try:
  4000.             python_version = "%d.%d.%d" %(sys.version_info.major,sys.version_info.minor,sys.version_info.micro)
  4001.         except:
  4002.             python_version = ""
  4003.         about = about + "Python "+python_version+" (%d bit)" %(struct.calcsize("P") * 8)
  4004.         message_box("About %s" %(application),about)
  4005.  
  4006.     def menu_Help_Web(self):
  4007.         webbrowser.open_new(r"https://www.scorchworks.com/K40whisperer/k40whisperer.html")
  4008.  
  4009.     def menu_Help_Manual(self):
  4010.         webbrowser.open_new(r"https://www.scorchworks.com/K40whisperer/k40w_manual.html")
  4011.  
  4012.     def KEY_F1(self, event):
  4013.         if self.GUI_Disabled:
  4014.             return
  4015.         self.menu_Help_About()
  4016.  
  4017.     def KEY_F2(self, event):
  4018.         if self.GUI_Disabled:
  4019.             return
  4020.         self.GEN_Settings_Window()
  4021.  
  4022.     def KEY_F3(self, event):
  4023.         if self.GUI_Disabled:
  4024.             return
  4025.         self.RASTER_Settings_Window()
  4026.  
  4027.     def KEY_F4(self, event):
  4028.         if self.GUI_Disabled:
  4029.             return
  4030.         self.ROTARY_Settings_Window()
  4031.         self.menu_View_Refresh()
  4032.  
  4033.     def KEY_F5(self, event):
  4034.         if self.GUI_Disabled:
  4035.             return
  4036.         self.menu_View_Refresh()
  4037.  
  4038.     def KEY_F6(self, event):
  4039.         if self.GUI_Disabled:
  4040.             return
  4041.         self.advanced.set(not self.advanced.get())
  4042.         self.menu_View_Refresh()
  4043.  
  4044.     def bindConfigure(self, event):
  4045.         if not self.initComplete:
  4046.             self.initComplete = 1
  4047.             self.menu_Mode_Change()
  4048.  
  4049.     def Master_Configure(self, event, update=0):
  4050.         if event.widget != self.master:
  4051.             return
  4052.         x = int(self.master.winfo_x())
  4053.         y = int(self.master.winfo_y())
  4054.         w = int(self.master.winfo_width())
  4055.         h = int(self.master.winfo_height())
  4056.         if (self.x, self.y) == (-1,-1):
  4057.             self.x, self.y = x,y
  4058.         if abs(self.w-w)>10 or abs(self.h-h)>10 or update==1:
  4059.             ###################################################
  4060.             #  Form changed Size (resized) adjust as required #
  4061.             ###################################################
  4062.             self.w=w
  4063.             self.h=h
  4064.  
  4065.             if True:                
  4066.                 # Left Column #
  4067.                 w_label=90
  4068.                 w_entry=48
  4069.                 w_units=52
  4070.  
  4071.                 x_label_L=10
  4072.                 x_entry_L=x_label_L+w_label+20-5
  4073.                 x_units_L=x_entry_L+w_entry+2
  4074.  
  4075.                 Yloc=10
  4076.                 self.Initialize_Button.place (x=12, y=Yloc, width=100*2, height=23)
  4077.                 Yloc=Yloc+33
  4078.  
  4079.                 self.Open_Button.place (x=12, y=Yloc, width=100, height=40)
  4080.                 self.Reload_Button.place(x=12+100, y=Yloc, width=100, height=40)                
  4081.                 if h>=560:
  4082.                     Yloc=Yloc+50
  4083.                     self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2)
  4084.                     Yloc=Yloc+6
  4085.                     self.Label_Position_Control.place(x=x_label_L, y=Yloc, width=w_label*2, height=21)
  4086.  
  4087.                     Yloc=Yloc+25
  4088.                     self.Home_Button.place (x=12, y=Yloc, width=100, height=23)
  4089.                     self.UnLock_Button.place(x=12+100, y=Yloc, width=100, height=23)
  4090.  
  4091.                     Yloc=Yloc+33
  4092.                     self.Label_Step.place(x=x_label_L, y=Yloc, width=w_label, height=21)
  4093.                     self.Label_Step_u.place(x=x_units_L, y=Yloc, width=w_units, height=21)
  4094.                     self.Entry_Step.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
  4095.  
  4096.                     ###########################################################################
  4097.                     Yloc=Yloc+30
  4098.                     bsz=40
  4099.                     xoffst=35
  4100.                     self.UL_Button.place    (x=xoffst+12      ,  y=Yloc, width=bsz, height=bsz)
  4101.                     self.Up_Button.place    (x=xoffst+12+bsz  ,  y=Yloc, width=bsz, height=bsz)
  4102.                     self.UR_Button.place    (x=xoffst+12+bsz*2,  y=Yloc, width=bsz, height=bsz)
  4103.                     Yloc=Yloc+bsz
  4104.                     self.Left_Button.place  (x=xoffst+12      ,y=Yloc, width=bsz, height=bsz)
  4105.                     self.CC_Button.place    (x=xoffst+12+bsz  ,y=Yloc, width=bsz, height=bsz)
  4106.                     self.Right_Button.place (x=xoffst+12+bsz*2,y=Yloc, width=bsz, height=bsz)
  4107.                     Yloc=Yloc+bsz
  4108.                     self.LL_Button.place    (x=xoffst+12      ,  y=Yloc, width=bsz, height=bsz)
  4109.                     self.Down_Button.place  (x=xoffst+12+bsz  ,  y=Yloc, width=bsz, height=bsz)
  4110.                     self.LR_Button.place    (x=xoffst+12+bsz*2,  y=Yloc, width=bsz, height=bsz)
  4111.            
  4112.                
  4113.                     Yloc=Yloc+bsz
  4114.                     ###########################################################################
  4115.                     self.Label_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
  4116.                     self.Label_GoToY.place(x=x_units_L, y=Yloc, width=w_entry, height=23)
  4117.                     Yloc=Yloc+25
  4118.                     self.GoTo_Button.place (x=12, y=Yloc, width=100, height=23)
  4119.                     self.Entry_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
  4120.                     self.Entry_GoToY.place(x=x_units_L, y=Yloc, width=w_entry, height=23)
  4121.                     ###########################################################################
  4122.                 else:
  4123.                     ###########################################################################
  4124.                     self.separator1.place_forget()
  4125.                     self.Label_Position_Control.place_forget()
  4126.                     ##    
  4127.                     Yloc=Yloc+50
  4128.                     self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2)
  4129.                     Yloc=Yloc+6
  4130.                     self.Home_Button.place (x=12, y=Yloc, width=100, height=23)
  4131.                     self.UnLock_Button.place(x=12+100, y=Yloc, width=100, height=23)
  4132.                     ##
  4133.                     self.Label_Step.place_forget()
  4134.                     self.Label_Step_u.place_forget()
  4135.                     self.Entry_Step.place_forget()
  4136.                     self.UL_Button.place_forget()
  4137.                     self.Up_Button.place_forget()
  4138.                     self.UR_Button.place_forget()
  4139.                     self.Left_Button.place_forget()
  4140.                     self.CC_Button.place_forget()
  4141.                     self.Right_Button.place_forget()
  4142.                     self.LL_Button.place_forget()
  4143.                     self.Down_Button.place_forget()
  4144.                     self.LR_Button.place_forget()
  4145.                     self.Label_GoToX.place_forget()
  4146.                     self.Label_GoToY.place_forget()
  4147.                     self.GoTo_Button.place_forget()
  4148.                     self.Entry_GoToX.place_forget()
  4149.                     self.Entry_GoToY.place_forget()
  4150.                     ###########################################################################
  4151.  
  4152.                 #From Bottom up
  4153.                 BUinit = self.h-70
  4154.                 Yloc = BUinit
  4155.                 self.Stop_Button.place (x=12, y=Yloc, width=100*2, height=30)
  4156.                
  4157.                 self.Stop_Button.configure(bg='light coral')
  4158.                 Yloc=Yloc-10+10
  4159.  
  4160.                 wadv       = 220 #200
  4161.                 wadv_use   = wadv-20
  4162.                 Xvert_sep  = 220
  4163.                 Xadvanced  = Xvert_sep+10
  4164.                 w_label_adv= wadv-80 #  110 w_entry
  4165.  
  4166.                 if self.GcodeData.ecoords == []:
  4167.                     self.Grun_Button.place_forget()
  4168.                     self.Reng_Veng_Vcut_Button.place_forget()
  4169.                     self.Reng_Veng_Button.place_forget()
  4170.                     self.Veng_Vcut_Button.place_forget()
  4171.  
  4172.                     Yloc=Yloc-30
  4173.                     self.Vcut_Button.place      (x=12, y=Yloc, width=100, height=23)
  4174.                     self.Entry_Vcut_feed.place  (x=x_entry_L, y=Yloc, width=w_entry, height=23)
  4175.                     self.Label_Vcut_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
  4176.                     Y_Vcut=Yloc
  4177.  
  4178.                     Yloc=Yloc-30
  4179.                     self.Veng_Button.place  (x=12, y=Yloc, width=100, height=23)
  4180.                     self.Entry_Veng_feed.place(  x=x_entry_L, y=Yloc, width=w_entry, height=23)
  4181.                     self.Label_Veng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
  4182.                     Y_Veng=Yloc
  4183.                    
  4184.                     Yloc=Yloc-30
  4185.                     self.Reng_Button.place  (x=12, y=Yloc, width=100, height=23)
  4186.                     self.Entry_Reng_feed.place(  x=x_entry_L, y=Yloc, width=w_entry, height=23)
  4187.                     self.Label_Reng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
  4188.                     Y_Reng=Yloc
  4189.                    
  4190.                     if self.comb_vector.get() or self.comb_engrave.get():
  4191.                         if self.comb_engrave.get():
  4192.                             self.Veng_Button.place_forget()                    
  4193.                             self.Reng_Button.place_forget()
  4194.                         if self.comb_vector.get():
  4195.                             self.Vcut_Button.place_forget()
  4196.                             self.Veng_Button.place_forget()
  4197.                            
  4198.                         if self.comb_engrave.get():
  4199.                             if self.comb_vector.get():
  4200.                                 self.Reng_Veng_Vcut_Button.place(x=12, y=Y_Reng, width=100, height=23*3+14)
  4201.                             else:
  4202.                                 self.Reng_Veng_Button.place(x=12, y=Y_Reng, width=100, height=23*2+7)
  4203.                         elif self.comb_vector.get():
  4204.                             self.Veng_Vcut_Button.place(x=12, y=Y_Veng, width=100, height=23*2+7)
  4205.                    
  4206.                    
  4207.                 else:
  4208.                     self.Vcut_Button.place_forget()
  4209.                     self.Entry_Vcut_feed.place_forget()
  4210.                     self.Label_Vcut_feed_u.place_forget()
  4211.                    
  4212.                     self.Veng_Button.place_forget()
  4213.                     self.Entry_Veng_feed.place_forget()
  4214.                     self.Label_Veng_feed_u.place_forget()
  4215.                    
  4216.                     self.Reng_Button.place_forget()
  4217.                     self.Entry_Reng_feed.place_forget()
  4218.                     self.Label_Reng_feed_u.place_forget()
  4219.  
  4220.                     self.Reng_Veng_Vcut_Button.place_forget()
  4221.                     self.Reng_Veng_Button.place_forget()
  4222.                     self.Veng_Vcut_Button.place_forget()
  4223.                    
  4224.                     Yloc=Yloc-30
  4225.                     self.Grun_Button.place  (x=12, y=Yloc, width=100*2, height=23)
  4226.                    
  4227.                 if h>=560:
  4228.                     Yloc=Yloc-15
  4229.                     self.separator2.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2)
  4230.                 else:
  4231.                     self.separator2.place_forget()
  4232.                    
  4233.                 # End Left Column #
  4234.  
  4235.                 if self.advanced.get():
  4236.                    
  4237.                     self.PreviewCanvas.configure( width = self.w-240-wadv, height = self.h-50 )
  4238.                     self.PreviewCanvas_frame.place(x=220+wadv, y=10)
  4239.                     self.separator_vert.place(x=220, y=10,width=2, height=self.h-50)
  4240.  
  4241.                     adv_Yloc=25-10 #15
  4242.                     self.Label_Advanced_column.place(x=Xadvanced, y=adv_Yloc, width=wadv_use, height=21)
  4243.                     adv_Yloc=adv_Yloc+25
  4244.                     self.separator_adv.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
  4245.  
  4246.                     if h>=560:
  4247.                         adv_Yloc=adv_Yloc+25-20 #15
  4248.                         self.Label_Halftone_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4249.                         self.Checkbutton_Halftone_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4250.                    
  4251.                         adv_Yloc=adv_Yloc+25
  4252.                         self.Label_Negate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4253.                         self.Checkbutton_Negate_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4254.  
  4255.                         adv_Yloc=adv_Yloc+25
  4256.                         self.separator_adv2.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
  4257.                    
  4258.                         adv_Yloc=adv_Yloc+25-20
  4259.                         self.Label_Mirror_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4260.                         self.Checkbutton_Mirror_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4261.  
  4262.                         adv_Yloc=adv_Yloc+25
  4263.                         self.Label_Rotate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4264.                         self.Checkbutton_Rotate_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4265.  
  4266.                         adv_Yloc=adv_Yloc+25
  4267.                         self.Label_inputCSYS_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4268.                         self.Checkbutton_inputCSYS_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4269.                    
  4270.                         adv_Yloc=adv_Yloc+25
  4271.                         self.separator_adv3.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
  4272.  
  4273.                         adv_Yloc=adv_Yloc+25-20
  4274.                         self.Label_Inside_First_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4275.                         self.Checkbutton_Inside_First_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4276.                    
  4277.                         adv_Yloc=adv_Yloc+25
  4278.                         self.Label_Rotary_Enable_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4279.                         self.Checkbutton_Rotary_Enable_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4280.                     else:
  4281.                         #self.Label_Advanced_column.place_forget()
  4282.                         #self.separator_adv.place_forget()
  4283.                         self.Label_Halftone_adv.place_forget()
  4284.                         self.Checkbutton_Halftone_adv.place_forget()
  4285.                         self.Label_Negate_adv.place_forget()
  4286.                         self.Checkbutton_Negate_adv.place_forget()
  4287.                         self.separator_adv2.place_forget()
  4288.                         self.Label_Mirror_adv.place_forget()
  4289.                         self.Checkbutton_Mirror_adv.place_forget()
  4290.                         self.Label_Rotate_adv.place_forget()
  4291.                         self.Checkbutton_Rotate_adv.place_forget()
  4292.                         self.Label_inputCSYS_adv.place_forget()
  4293.                         self.Checkbutton_inputCSYS_adv.place_forget()
  4294.                         self.separator_adv3.place_forget()
  4295.                         self.Label_Inside_First_adv.place_forget()
  4296.                         self.Checkbutton_Inside_First_adv.place_forget()
  4297.                         self.Label_Rotary_Enable_adv.place_forget()
  4298.                         self.Checkbutton_Rotary_Enable_adv.place_forget()
  4299.  
  4300.                     adv_Yloc = BUinit
  4301.                     self.Hide_Adv_Button.place (x=Xadvanced, y=adv_Yloc, width=wadv_use, height=30)
  4302.  
  4303.                     if self.RengData.image != None:
  4304.                         self.Label_inputCSYS_adv.configure(state="disabled")
  4305.                         self.Checkbutton_inputCSYS_adv.place_forget()              
  4306.                     else:
  4307.                         self.Label_inputCSYS_adv.configure(state="normal")
  4308.                        
  4309.                     if self.GcodeData.ecoords == []:
  4310.                         #adv_Yloc = adv_Yloc-40
  4311.                         self.Label_Vcut_passes.place(x=Xadvanced, y=Y_Vcut, width=w_label_adv, height=21)
  4312.                         self.Entry_Vcut_passes.place(x=Xadvanced+w_label_adv+2, y=Y_Vcut, width=w_entry, height=23)
  4313.  
  4314.                         #adv_Yloc=adv_Yloc-30
  4315.                         self.Label_Veng_passes.place(x=Xadvanced, y=Y_Veng, width=w_label_adv, height=21)
  4316.                         self.Entry_Veng_passes.place(x=Xadvanced+w_label_adv+2, y=Y_Veng, width=w_entry, height=23)
  4317.  
  4318.                         #adv_Yloc=adv_Yloc-30
  4319.                         self.Label_Reng_passes.place(x=Xadvanced, y=Y_Reng, width=w_label_adv, height=21)
  4320.                         self.Entry_Reng_passes.place(x=Xadvanced+w_label_adv+2, y=Y_Reng, width=w_entry, height=23)
  4321.                         self.Label_Gcde_passes.place_forget()
  4322.                         self.Entry_Gcde_passes.place_forget()
  4323.                         adv_Yloc = Y_Reng
  4324.  
  4325.                        ####
  4326.                         adv_Yloc=adv_Yloc-15
  4327.                         self.separator_comb.place(x=Xadvanced-1, y=adv_Yloc, width=wadv_use, height=2)
  4328.  
  4329.                         adv_Yloc=adv_Yloc-25
  4330.                         self.Label_Comb_Vector_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4331.                         self.Checkbutton_Comb_Vector_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4332.                        
  4333.                         adv_Yloc=adv_Yloc-25
  4334.                         self.Label_Comb_Engrave_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4335.                         self.Checkbutton_Comb_Engrave_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  4336.                         ####
  4337.                        
  4338.                     else:
  4339.                         adv_Yloc=adv_Yloc-40
  4340.                         self.Label_Gcde_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  4341.                         self.Entry_Gcde_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23)
  4342.                         self.Label_Vcut_passes.place_forget()
  4343.                         self.Entry_Vcut_passes.place_forget()
  4344.                         self.Label_Veng_passes.place_forget()
  4345.                         self.Entry_Veng_passes.place_forget()
  4346.                         self.Label_Reng_passes.place_forget()
  4347.                         self.Entry_Reng_passes.place_forget()
  4348.  
  4349.                 else:
  4350.                     self.PreviewCanvas_frame.place_forget()
  4351.                     self.separator_vert.place_forget()
  4352.                     self.Label_Advanced_column.place_forget()
  4353.                     self.separator_adv.place_forget()
  4354.                     self.Label_Halftone_adv.place_forget()
  4355.                     self.Checkbutton_Halftone_adv.place_forget()
  4356.                     self.Label_Negate_adv.place_forget()
  4357.                     self.Checkbutton_Negate_adv.place_forget()
  4358.                     self.separator_adv2.place_forget()
  4359.                     self.Label_Mirror_adv.place_forget()
  4360.                     self.Checkbutton_Mirror_adv.place_forget()
  4361.                     self.Label_Rotate_adv.place_forget()
  4362.                     self.Checkbutton_Rotate_adv.place_forget()
  4363.                     self.Label_inputCSYS_adv.place_forget()
  4364.                     self.Checkbutton_inputCSYS_adv.place_forget()
  4365.                     self.separator_adv3.place_forget()
  4366.                     self.Label_Inside_First_adv.place_forget()
  4367.                     self.Checkbutton_Inside_First_adv.place_forget()
  4368.  
  4369.                     self.Label_Rotary_Enable_adv.place_forget()
  4370.                     self.Checkbutton_Rotary_Enable_adv.place_forget()
  4371.  
  4372.                     self.separator_comb.place_forget()
  4373.                     self.Label_Comb_Engrave_adv.place_forget()
  4374.                     self.Checkbutton_Comb_Engrave_adv.place_forget()
  4375.                     self.Label_Comb_Vector_adv.place_forget()
  4376.                     self.Checkbutton_Comb_Vector_adv.place_forget()
  4377.  
  4378.  
  4379.                     self.Entry_Vcut_passes.place_forget()
  4380.                     self.Label_Vcut_passes.place_forget()
  4381.                     self.Entry_Veng_passes.place_forget()
  4382.                     self.Label_Veng_passes.place_forget()
  4383.                     self.Entry_Reng_passes.place_forget()
  4384.                     self.Label_Reng_passes.place_forget()
  4385.                     self.Label_Gcde_passes.place_forget()
  4386.                     self.Entry_Gcde_passes.place_forget()
  4387.                     self.Hide_Adv_Button.place_forget()
  4388.                    
  4389.                     self.PreviewCanvas.configure( width = self.w-240, height = self.h-50 )
  4390.                     self.PreviewCanvas_frame.place(x=Xvert_sep, y=10)
  4391.                     self.separator_vert.place_forget()
  4392.  
  4393.                 self.Set_Input_States()
  4394.                
  4395.             self.Plot_Data()
  4396.            
  4397.     def Recalculate_RQD_Click(self, event):
  4398.         self.menu_View_Refresh()
  4399.  
  4400.     def Set_Input_States(self):
  4401.         pass
  4402.            
  4403.     def Set_Input_States_Event(self,event):
  4404.         self.Set_Input_States()
  4405.  
  4406.     def Set_Input_States_RASTER(self,event=None):
  4407.         if self.halftone.get():
  4408.             self.Label_Halftone_DPI.configure(state="normal")
  4409.             self.Halftone_DPI_OptionMenu.configure(state="normal")
  4410.             self.Label_Halftone_u.configure(state="normal")
  4411.             self.Label_bezier_M1.configure(state="normal")
  4412.             self.bezier_M1_Slider.configure(state="normal")
  4413.             self.Label_bezier_M2.configure(state="normal")
  4414.             self.bezier_M2_Slider.configure(state="normal")
  4415.             self.Label_bezier_weight.configure(state="normal")
  4416.             self.bezier_weight_Slider.configure(state="normal")
  4417.         else:
  4418.             self.Label_Halftone_DPI.configure(state="disabled")
  4419.             self.Halftone_DPI_OptionMenu.configure(state="disabled")
  4420.             self.Label_Halftone_u.configure(state="disabled")
  4421.             self.Label_bezier_M1.configure(state="disabled")
  4422.             self.bezier_M1_Slider.configure(state="disabled")
  4423.             self.Label_bezier_M2.configure(state="disabled")
  4424.             self.bezier_M2_Slider.configure(state="disabled")
  4425.             self.Label_bezier_weight.configure(state="disabled")
  4426.             self.bezier_weight_Slider.configure(state="disabled")
  4427.  
  4428.     def Set_Input_States_BATCH(self):
  4429.         if self.post_exec.get():
  4430.             self.Entry_Batch_Path.configure(state="normal")
  4431.         else:
  4432.             self.Entry_Batch_Path.configure(state="disabled")
  4433. ##    def Set_Input_States_Unsharp(self,event=None):        
  4434. ##        if self.unsharp_flag.get():
  4435. ##            self.Label_Unsharp_Radius.configure(state="normal")
  4436. ##            self.Label_Unsharp_Radius_u.configure(state="normal")
  4437. ##            self.Entry_Unsharp_Radius.configure(state="normal")
  4438. ##            self.Label_Unsharp_Percent.configure(state="normal")
  4439. ##            self.Label_Unsharp_Percent_u.configure(state="normal")
  4440. ##            self.Entry_Unsharp_Percent.configure(state="normal")
  4441. ##            self.Label_Unsharp_Threshold.configure(state="normal")
  4442. ##            self.Entry_Unsharp_Threshold.configure(state="normal")
  4443. ##
  4444. ##        else:
  4445. ##            self.Label_Unsharp_Radius.configure(state="disabled")
  4446. ##            self.Label_Unsharp_Radius_u.configure(state="disabled")
  4447. ##            self.Entry_Unsharp_Radius.configure(state="disabled")
  4448. ##            self.Label_Unsharp_Percent.configure(state="disabled")
  4449. ##            self.Label_Unsharp_Percent_u.configure(state="disabled")
  4450. ##            self.Entry_Unsharp_Percent.configure(state="disabled")
  4451. ##            self.Label_Unsharp_Threshold.configure(state="disabled")
  4452. ##            self.Entry_Unsharp_Threshold.configure(state="disabled")
  4453.  
  4454.     def Set_Input_States_Rotary(self,event=None):
  4455.         if self.rotary.get():
  4456.             self.Label_Laser_R_Scale.configure(state="normal")
  4457.             self.Entry_Laser_R_Scale.configure(state="normal")
  4458.             self.Label_Laser_Rapid_Feed.configure(state="normal")
  4459.             self.Label_Laser_Rapid_Feed_u.configure(state="normal")
  4460.             self.Entry_Laser_Rapid_Feed.configure(state="normal")
  4461.         else:
  4462.             self.Label_Laser_R_Scale.configure(state="disabled")
  4463.             self.Entry_Laser_R_Scale.configure(state="disabled")
  4464.             self.Label_Laser_Rapid_Feed.configure(state="disabled")
  4465.             self.Label_Laser_Rapid_Feed_u.configure(state="disabled")
  4466.             self.Entry_Laser_Rapid_Feed.configure(state="disabled")
  4467.            
  4468. #    def Set_Input_States_RASTER_Event(self,event):
  4469. #        self.Set_Input_States_RASTER()
  4470.  
  4471.     def Imaging_Free(self,image_in,bg="#ffffff"):
  4472.         image_in = image_in.convert('L')
  4473.         wim,him = image_in.size
  4474.         image_out=PhotoImage(width=wim,height=him)
  4475.         pixel=image_in.load()
  4476.         if bg!=None:
  4477.             image_out.put(bg, to=(0,0,wim,him))
  4478.         for y in range(0,him):
  4479.             for x in range(0,wim):
  4480.                 val=pixel[x,y]
  4481.                 if val!=255:
  4482.                     image_out.put("#%02x%02x%02x" %(val,val,val),(x,y))
  4483.         return image_out
  4484.  
  4485.     ##########################################
  4486.     #        CANVAS PLOTTING STUFF           #
  4487.     ##########################################
  4488.     def Plot_Data(self):
  4489.         self.PreviewCanvas.delete(ALL)
  4490.         self.calc_button.place_forget()
  4491.  
  4492.         for seg in self.segID:
  4493.             self.PreviewCanvas.delete(seg)
  4494.         self.segID = []
  4495.        
  4496.         cszw = int(self.PreviewCanvas.cget("width"))
  4497.         cszh = int(self.PreviewCanvas.cget("height"))
  4498.         buff=10
  4499.         wc = float(cszw/2)
  4500.         hc = float(cszh/2)        
  4501.        
  4502.         maxx = float(self.LaserXsize.get()) / self.units_scale
  4503.         minx = 0.0
  4504.         maxy = 0.0
  4505.         miny = -float(self.LaserYsize.get()) / self.units_scale
  4506.         midx=(maxx+minx)/2
  4507.         midy=(maxy+miny)/2
  4508.        
  4509.                
  4510.         if self.inputCSYS.get() and self.RengData.image == None:
  4511.             xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  4512.         else:
  4513.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()          
  4514.                
  4515.         if (self.HomeUR.get()):
  4516.             XlineShift = maxx - self.laserX - (xmax-xmin)
  4517.         else:
  4518.             XlineShift = self.laserX
  4519.         YlineShift = self.laserY    
  4520.         if min((xmax-xmin),(ymax-ymin)) > 0 and self.zoom2image.get():
  4521.             self.PlotScale = max((xmax-xmin)/(cszw-buff), (ymax-ymin)/(cszh-buff))
  4522.             if self.HomeUR.get():
  4523.                 x_rgt =  (xmax-minx) / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2
  4524.                 x_lft =  (xmax-maxx) / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2
  4525.             else:
  4526.                 x_lft =  minx / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2
  4527.                 x_rgt =  maxx / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2
  4528.             y_bot = -miny / self.PlotScale + self.laserY / self.PlotScale + (cszh-(ymax-ymin)/self.PlotScale)/2
  4529.             y_top = -maxy / self.PlotScale + self.laserY / self.PlotScale + (cszh-(ymax-ymin)/self.PlotScale)/2
  4530.             self.segID.append( self.PreviewCanvas.create_rectangle(
  4531.                             x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) )
  4532.         else:
  4533.             self.PlotScale = max((maxx-minx)/(cszw-buff), (maxy-miny)/(cszh-buff))
  4534.             x_lft = cszw/2 + (minx-midx) / self.PlotScale
  4535.             x_rgt = cszw/2 + (maxx-midx) / self.PlotScale
  4536.             y_bot = cszh/2 + (maxy-midy) / self.PlotScale
  4537.             y_top = cszh/2 + (miny-midy) / self.PlotScale
  4538.             self.segID.append( self.PreviewCanvas.create_rectangle(
  4539.                             x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) )
  4540.  
  4541.  
  4542.         ######################################
  4543.         ###       Plot Raster Image        ###
  4544.         ######################################
  4545.         if self.RengData.image != None:
  4546.             if self.include_Reng.get():  
  4547.                 try:
  4548.                     new_SCALE = (1.0/self.PlotScale)/self.input_dpi
  4549.                     if new_SCALE != self.SCALE:
  4550.                         self.SCALE = new_SCALE
  4551.                         nw=int(self.SCALE*self.wim)
  4552.                         nh=int(self.SCALE*self.him)
  4553.  
  4554.                         plot_im = self.RengData.image.convert("L")                        
  4555. ##                        if self.unsharp_flag.get():
  4556. ##                            from PIL import ImageFilter
  4557. ##                            filter = ImageFilter.UnsharpMask()
  4558. ##                            filter.radius    = float(self.unsharp_r.get())
  4559. ##                            filter.percent   = int(float(self.unsharp_p.get()))
  4560. ##                            filter.threshold = int(float(self.unsharp_t.get()))
  4561. ##                            plot_im = plot_im.filter(filter)
  4562.                        
  4563.                         if self.negate.get():
  4564.                             plot_im = ImageOps.invert(plot_im)
  4565.  
  4566.                         if self.halftone.get() == False:
  4567.                             plot_im = plot_im.point(lambda x: 0 if x<128 else 255, '1')
  4568.                             plot_im = plot_im.convert("L")
  4569.  
  4570.                         if self.mirror.get():
  4571.                             plot_im = ImageOps.mirror(plot_im)
  4572.  
  4573.                         if self.rotate.get():
  4574.                             plot_im = plot_im.rotate(90,expand=True)
  4575.                             nh=int(self.SCALE*self.wim)
  4576.                             nw=int(self.SCALE*self.him)
  4577.                            
  4578.                         try:
  4579.                             self.UI_image = ImageTk.PhotoImage(plot_im.resize((nw,nh), Image.LANCZOS))
  4580.                         except:
  4581.                             debug_message("Imaging_Free Used.")
  4582.                             self.UI_image = self.Imaging_Free(plot_im.resize((nw,nh), Image.LANCZOS))
  4583.                 except:
  4584.                     self.SCALE = 1
  4585.                     debug_message(traceback.format_exc())
  4586.                    
  4587.                 self.Plot_Raster(self.laserX+.001, self.laserY-.001, x_lft,y_top,self.PlotScale,im=self.UI_image)
  4588.         else:
  4589.             self.UI_image = None
  4590.  
  4591.  
  4592.         ######################################
  4593.         ###       Plot Reng Coords         ###
  4594.         ######################################
  4595.         if self.include_Rpth.get() and self.RengData.ecoords!=[]:
  4596.             loop_old = -1
  4597.  
  4598.             #####
  4599.             Xscale = 1/float(self.LaserXscale.get())
  4600.             Yscale = 1/float(self.LaserYscale.get())
  4601.             if self.rotary.get():
  4602.                 Rscale = 1/float(self.LaserRscale.get())
  4603.                 Yscale = Yscale*Rscale
  4604.             ######
  4605.  
  4606.             for line in self.RengData.ecoords:
  4607.                 XY    = line
  4608.                 x1    = XY[0]*Xscale
  4609.                 y1    = XY[1]*Yscale-ymax
  4610.                 loop  = XY[2]
  4611.                 color = "black"
  4612.                 # check and see if we need to move to a new discontinuous start point
  4613.                 if (loop == loop_old):
  4614.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, color)
  4615.                 loop_old = loop
  4616.                 xold=x1
  4617.                 yold=y1
  4618.  
  4619.            
  4620.         ######################################
  4621.         ###       Plot Veng Coords         ###
  4622.         ######################################
  4623.         if self.include_Veng.get():
  4624.             loop_old = -1
  4625.            
  4626.  
  4627.             plot_coords = self.VengData.ecoords
  4628.             if self.mirror.get() or self.rotate.get():
  4629.                 plot_coords = self.mirror_rotate_vector_coords(plot_coords)
  4630.  
  4631.             for line in plot_coords:
  4632.                 XY    = line
  4633.                 x1    = (XY[0]-xmin)
  4634.                 y1    = (XY[1]-ymax)
  4635.                 loop  = XY[2]
  4636.                 # check and see if we need to move to a new discontinuous start point
  4637.                 if (loop == loop_old):
  4638.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "blue")
  4639.                 loop_old = loop
  4640.                 xold=x1
  4641.                 yold=y1
  4642.  
  4643.         ######################################
  4644.         ###       Plot Vcut Coords         ###
  4645.         ######################################
  4646.         if self.include_Vcut.get():
  4647.             loop_old = -1
  4648.  
  4649.             plot_coords = self.VcutData.ecoords
  4650.             if self.mirror.get() or self.rotate.get():
  4651.                     plot_coords = self.mirror_rotate_vector_coords(plot_coords)
  4652.                
  4653.             for line in plot_coords:
  4654.                 XY    = line
  4655.                 x1    = (XY[0]-xmin)
  4656.                 y1    = (XY[1]-ymax)
  4657.                 loop  = XY[2]
  4658.                 # check and see if we need to move to a new discontinuous start point
  4659.                 if (loop == loop_old):
  4660.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "red")
  4661.                 loop_old = loop
  4662.                 xold=x1
  4663.                 yold=y1
  4664.  
  4665.         ######################################
  4666.         ###       Plot Gcode Coords        ###
  4667.         ######################################
  4668.         if self.include_Gcde.get():  
  4669.             loop_old = -1
  4670.             scale=1
  4671.  
  4672.             plot_coords = self.GcodeData.ecoords
  4673.             if self.mirror.get() or self.rotate.get():
  4674.                     plot_coords = self.mirror_rotate_vector_coords(plot_coords)
  4675.                
  4676.             for line in plot_coords:
  4677.                 XY    = line
  4678.                 x1    = (XY[0]-xmin)*scale
  4679.                 y1    = (XY[1]-ymax)*scale
  4680.  
  4681.                 loop  = XY[2]
  4682.                 # check and see if we need to move to a new discontinuous start point
  4683.                 if (loop == loop_old):
  4684.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "white")
  4685.                 loop_old = loop
  4686.                 xold=x1
  4687.                 yold=y1
  4688.  
  4689.  
  4690.         ######################################
  4691.         ###       Plot Trace Coords        ###
  4692.         ######################################
  4693.         if self.trace_window.winfo_exists():  # or DEBUG:
  4694.             #####
  4695.             Xscale = 1/float(self.LaserXscale.get())
  4696.             Yscale = 1/float(self.LaserYscale.get())
  4697.             if self.rotary.get():
  4698.                 Rscale = 1/float(self.LaserRscale.get())
  4699.                 Yscale = Yscale*Rscale
  4700.             ######
  4701.             trace_coords = self.make_trace_path()
  4702.             for i in range(len(trace_coords)):
  4703.                 trace_coords[i]=[trace_coords[i][0]*Xscale,trace_coords[i][1]*Yscale,trace_coords[i][2]]
  4704.  
  4705.             for line in trace_coords:
  4706.                 XY    = line
  4707.                 x1    = (XY[0]-xmin)*scale
  4708.                 y1    = (XY[1]-ymax)*scale
  4709.                 loop  = XY[2]
  4710.                 # check and see if we need to move to a new discontinuous start point
  4711.                 if (loop == loop_old):
  4712.                     green = "#%02x%02x%02x" % (0, 200, 0)
  4713.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift,
  4714.                                    self.PlotScale, green, thick=2,tag_value=('LaserTag', 'trace'))
  4715.                 loop_old = loop
  4716.                 xold=x1
  4717.                 yold=y1
  4718.  
  4719.  
  4720.         ######################################            
  4721.         self.refreshTime()
  4722.         dot_col = "grey50"
  4723.         xoff = self.pos_offset[0]/1000.0
  4724.         yoff = self.pos_offset[1]/1000.0
  4725.  
  4726.         if abs(self.pos_offset[0])+abs(self.pos_offset[1]) > 0:
  4727.             head_offset=True
  4728.         else:
  4729.             head_offset=False
  4730.        
  4731.         self.Plot_circle(self.laserX+xoff,self.laserY+yoff,x_lft,y_top,self.PlotScale,dot_col,radius=5,cross_hair=head_offset)
  4732.        
  4733.     def Plot_Raster(self, XX, YY, Xleft, Ytop, PlotScale, im):
  4734.         if (self.HomeUR.get()):
  4735.             maxx = float(self.LaserXsize.get()) / self.units_scale
  4736.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  4737.             xplt = Xleft + ( maxx-XX-(xmax-xmin) )/PlotScale
  4738.         else:
  4739.             xplt = Xleft +  XX/PlotScale
  4740.            
  4741.         yplt = Ytop  - YY/PlotScale
  4742.         self.segID.append(
  4743.             self.PreviewCanvas.create_image(xplt, yplt, anchor=NW, image=self.UI_image,tags='LaserTag')
  4744.             )
  4745.  
  4746.  
  4747.     def offset_eccords(self,ecoords_in,offset_val):
  4748.         if not PYCLIPPER:
  4749.             return ecoords_in
  4750.        
  4751.         loop_num = ecoords_in[0][2]
  4752.         pco = pyclipper.PyclipperOffset()
  4753.         ecoords_out=[]
  4754.         pyclip_path = []
  4755.         for i in range(0,len(ecoords_in)):
  4756.             pyclip_path.append([ecoords_in[i][0]*1000,ecoords_in[i][1]*1000])
  4757.  
  4758.         pco.AddPath(pyclip_path, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
  4759.         try:
  4760.             plot_coords = pco.Execute(offset_val*1000.0)[0]
  4761.             plot_coords.append(plot_coords[0])
  4762.         except:
  4763.             plot_coords=[]
  4764.            
  4765.         for i in range(0,len(plot_coords)):
  4766.             ecoords_out.append([plot_coords[i][0]/1000.0,plot_coords[i][1]/1000.0,loop_num])
  4767.         return ecoords_out
  4768.    
  4769.        
  4770.     def Plot_circle(self, XX, YY, Xleft, Ytop, PlotScale, col, radius=0, cross_hair=False):
  4771.         circle_tags = ('LaserTag','LaserDot')
  4772.         if (self.HomeUR.get()):
  4773.             maxx = float(self.LaserXsize.get()) / self.units_scale
  4774.             xplt = Xleft + maxx/PlotScale - XX/PlotScale
  4775.         else:
  4776.             xplt = Xleft + XX/PlotScale
  4777.         yplt = Ytop  - YY/PlotScale
  4778.  
  4779.  
  4780.         if cross_hair:
  4781.             radius=radius*2
  4782.             leg = int(radius*.707)
  4783.             self.segID.append(
  4784.                 self.PreviewCanvas.create_polygon(
  4785.                                                 xplt-radius,
  4786.                                                 yplt,
  4787.                                                 xplt-leg,
  4788.                                                 yplt+leg,
  4789.                                                 xplt,
  4790.                                                 yplt+radius,
  4791.                                                 xplt+leg,
  4792.                                                 yplt+leg,
  4793.                                                 xplt+radius,
  4794.                                                 yplt,
  4795.                                                 xplt+leg,
  4796.                                                 yplt-leg,
  4797.                                                 xplt,
  4798.                                                 yplt-radius,
  4799.                                                 xplt-leg,
  4800.                                                 yplt-leg,
  4801.                                                 fill=col,  outline=col, width = 1, stipple='gray12',tags=circle_tags ))
  4802.            
  4803.             self.segID.append(
  4804.                 self.PreviewCanvas.create_line( xplt-radius,
  4805.                                                 yplt,
  4806.                                                 xplt+radius,
  4807.                                                 yplt,
  4808.                                                 fill=col, capstyle="round", width = 1, tags=circle_tags ))
  4809.             self.segID.append(
  4810.                 self.PreviewCanvas.create_line( xplt,
  4811.                                                 yplt-radius,
  4812.                                                 xplt,
  4813.                                                 yplt+radius,
  4814.                                                 fill=col, capstyle="round", width = 1, tags=circle_tags ))
  4815.         else:
  4816.             self.segID.append(
  4817.                 self.PreviewCanvas.create_oval(
  4818.                                                 xplt-radius,
  4819.                                                 yplt-radius,
  4820.                                                 xplt+radius,
  4821.                                                 yplt+radius,
  4822.                                                 fill=col,  outline=col, width = 0, stipple='gray50',tags=circle_tags ))
  4823.  
  4824.  
  4825.     def Plot_Line(self, XX1, YY1, XX2, YY2, Xleft, Ytop, XlineShift, YlineShift, PlotScale, col, thick=0, tag_value='LaserTag'):
  4826.         xplt1 = Xleft + (XX1 + XlineShift )/PlotScale
  4827.         xplt2 = Xleft + (XX2 + XlineShift )/PlotScale
  4828.         yplt1 = Ytop  - (YY1 + YlineShift )/PlotScale
  4829.         yplt2 = Ytop  - (YY2 + YlineShift )/PlotScale
  4830.        
  4831.         self.segID.append(
  4832.             self.PreviewCanvas.create_line( xplt1,
  4833.                                             yplt1,
  4834.                                             xplt2,
  4835.                                             yplt2,
  4836.                                             fill=col, capstyle="round", width = thick, tags=tag_value) )
  4837.        
  4838.     ################################################################################
  4839.     #                         Temporary Move Window                                #
  4840.     ################################################################################
  4841.     def move_head_window_temporary(self,new_pos_offset):
  4842.         if self.GUI_Disabled:
  4843.             return
  4844.         dx_inches = round(new_pos_offset[0]/1000.0,3)
  4845.         dy_inches = round(new_pos_offset[1]/1000.0,3)
  4846.         Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches,no_size=True)
  4847.  
  4848.         pos_offset_X = round((Xnew-self.laserX)*1000.0)
  4849.         pos_offset_Y = round((Ynew-self.laserY)*1000.0)
  4850.         new_pos_offset = [pos_offset_X,pos_offset_Y]        
  4851.        
  4852.         if self.inputCSYS.get() and self.RengData.image == None:
  4853.             new_pos_offset = [0,0]
  4854.             xdist = -self.pos_offset[0]
  4855.             ydist = -self.pos_offset[1]
  4856.         else:
  4857.             xdist = -self.pos_offset[0] + new_pos_offset[0]
  4858.             ydist = -self.pos_offset[1] + new_pos_offset[1]
  4859.            
  4860.         if self.k40 != None:
  4861.             if self.Send_Rapid_Move( xdist,ydist ):
  4862.                 self.pos_offset = new_pos_offset
  4863.                 self.menu_View_Refresh()
  4864.         else:      
  4865.             self.pos_offset = new_pos_offset
  4866.             self.menu_View_Refresh()
  4867.    
  4868.     ################################################################################
  4869.     #                         General Settings Window                              #
  4870.     ################################################################################
  4871.     def GEN_Settings_Window(self):
  4872.         gen_width = 560
  4873.         gen_settings = Toplevel(width=gen_width, height=575) #460+75)
  4874.         gen_settings.grab_set() # Use grab_set to prevent user input in the main window
  4875.         gen_settings.focus_set()
  4876.         gen_settings.resizable(0,0)
  4877.         gen_settings.title('General Settings')
  4878.         gen_settings.iconname("General Settings")
  4879.  
  4880.         D_Yloc  = 6
  4881.         D_dY = 26
  4882.         xd_label_L = 12
  4883.  
  4884.         w_label=150
  4885.         w_entry=40
  4886.         w_units=45
  4887.         xd_entry_L=xd_label_L+w_label+10
  4888.         xd_units_L=xd_entry_L+w_entry+5
  4889.         sep_border=10
  4890.  
  4891.         #Radio Button
  4892.         D_Yloc=D_Yloc+D_dY
  4893.         self.Label_Units = Label(gen_settings,text="Units")
  4894.         self.Label_Units.place(x=xd_label_L, y=D_Yloc, width=113, height=21)
  4895.         self.Radio_Units_IN = Radiobutton(gen_settings,text="inch", value="in",
  4896.                                          width="100", anchor=W)
  4897.         self.Radio_Units_IN.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  4898.         self.Radio_Units_IN.configure(variable=self.units, command=self.Entry_units_var_Callback )
  4899.         self.Radio_Units_MM = Radiobutton(gen_settings,text="mm", value="mm",
  4900.                                          width="100", anchor=W)
  4901.         self.Radio_Units_MM.place(x=w_label+110, y=D_Yloc, width=75, height=23)
  4902.         self.Radio_Units_MM.configure(variable=self.units, command=self.Entry_units_var_Callback )
  4903.  
  4904.         D_Yloc=D_Yloc+D_dY
  4905.         self.Label_init_home = Label(gen_settings,text="Home Upon Initialize")
  4906.         self.Label_init_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4907.         self.Checkbutton_init_home = Checkbutton(gen_settings,text="", anchor=W)
  4908.         self.Checkbutton_init_home.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  4909.         self.Checkbutton_init_home.configure(variable=self.init_home)
  4910.  
  4911.        
  4912.         D_Yloc=D_Yloc+D_dY
  4913.         self.Label_post_home = Label(gen_settings,text="After Job Finishes:")
  4914.         self.Label_post_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4915.  
  4916.         Xoption_width = 120
  4917.         Xoption_col1  = xd_entry_L
  4918.         Xoption_col2  = xd_entry_L+Xoption_width
  4919.         Xoption_col3  = xd_entry_L+Xoption_width*2
  4920.        
  4921.         self.Checkbutton_post_home = Checkbutton(gen_settings,text="Unlock Rail", anchor=W)
  4922.         self.Checkbutton_post_home.place(x=Xoption_col1, y=D_Yloc, width=Xoption_width, height=23)
  4923.         self.Checkbutton_post_home.configure(variable=self.post_home)
  4924.  
  4925.         self.Checkbutton_post_beep = Checkbutton(gen_settings,text="Beep", anchor=W)
  4926.         self.Checkbutton_post_beep.place(x=Xoption_col2, y=D_Yloc, width=Xoption_width, height=23)
  4927.         self.Checkbutton_post_beep.configure(variable=self.post_beep)
  4928.  
  4929.         D_Yloc=D_Yloc+D_dY
  4930.         self.Checkbutton_post_disp = Checkbutton(gen_settings,text="Popup Report", anchor=W)
  4931.         self.Checkbutton_post_disp.place(x=Xoption_col1, y=D_Yloc, width=Xoption_width, height=23)
  4932.         self.Checkbutton_post_disp.configure(variable=self.post_disp)
  4933.  
  4934.         self.Checkbutton_post_exec = Checkbutton(gen_settings,text="Run Batch File:", anchor=W, command=self.Set_Input_States_BATCH)
  4935.         self.Checkbutton_post_exec.place(x=Xoption_col2, y=D_Yloc, width=Xoption_width, height=23)
  4936.         self.Checkbutton_post_exec.configure(variable=self.post_exec)
  4937.  
  4938.  
  4939.         self.Entry_Batch_Path = Entry(gen_settings)
  4940.         self.Entry_Batch_Path.place(x=Xoption_col3, y=D_Yloc, width=Xoption_width, height=23)
  4941.         self.Entry_Batch_Path.configure(textvariable=self.batch_path)
  4942.        
  4943.  
  4944.         D_Yloc=D_Yloc+D_dY
  4945.         self.Label_Preprocess_CRC = Label(gen_settings,text="Preprocess CRC Data")
  4946.         self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4947.         self.Checkbutton_Preprocess_CRC = Checkbutton(gen_settings,text="", anchor=W)
  4948.         self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  4949.         self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc)
  4950.  
  4951.         D_Yloc=D_Yloc+D_dY
  4952.         self.Label_Reduce_Memory = Label(gen_settings,text="Reduce Memory Use")
  4953.         self.Label_Reduce_Memory.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4954.         self.Checkbutton_Reduce_Memory = Checkbutton(gen_settings,text="(needed for large designs or low memory computers)", anchor=W)
  4955.         self.Checkbutton_Reduce_Memory.place(x=xd_entry_L, y=D_Yloc, width=350, height=23)
  4956.         self.Checkbutton_Reduce_Memory.configure(variable=self.reduced_mem)
  4957.         self.reduced_mem.trace_variable("w", self.Reduced_Memory_Callback)
  4958.  
  4959.         D_Yloc=D_Yloc+D_dY
  4960.         self.Label_Wait = Label(gen_settings,text="Wait for Laser to Finish")
  4961.         self.Label_Wait.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4962.         self.Checkbutton_Wait = Checkbutton(gen_settings,text="(after all data has been sent over USB)", anchor=W)
  4963.         self.Checkbutton_Wait.place(x=xd_entry_L, y=D_Yloc, width=350, height=23)
  4964.         self.Checkbutton_Wait.configure(variable=self.wait)
  4965.         #self.wait.trace_variable("w", self.Wait_Callback)
  4966.        
  4967.         #D_Yloc=D_Yloc+D_dY
  4968.         #self.Label_Timeout = Label(gen_settings,text="USB Timeout")
  4969.         #self.Label_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4970.         #self.Label_Timeout_u = Label(gen_settings,text="ms", anchor=W)
  4971.         #self.Label_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  4972.         #self.Entry_Timeout = Entry(gen_settings,width="15")
  4973.         #self.Entry_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  4974.         #self.Entry_Timeout.configure(textvariable=self.t_timeout)
  4975.         #self.t_timeout.trace_variable("w", self.Entry_Timeout_Callback)
  4976.         #self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(),2)
  4977.  
  4978.         #D_Yloc=D_Yloc+D_dY
  4979.         #self.Label_N_Timeouts = Label(gen_settings,text="Number of Timeouts")
  4980.         #self.Label_N_Timeouts.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4981.         #self.Entry_N_Timeouts = Entry(gen_settings,width="15")
  4982.         #self.Entry_N_Timeouts.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  4983.         #self.Entry_N_Timeouts.configure(textvariable=self.n_timeouts)
  4984.         #self.n_timeouts.trace_variable("w", self.Entry_N_Timeouts_Callback)
  4985.         #self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(),2)
  4986.  
  4987.         D_Yloc=D_Yloc+D_dY*1.25
  4988.         self.gen_separator1 = Frame(gen_settings, height=2, bd=1, relief=SUNKEN)
  4989.         self.gen_separator1.place(x=xd_label_L, y=D_Yloc,width=gen_width-40, height=2)
  4990.  
  4991.         D_Yloc=D_Yloc+D_dY*.25
  4992.         self.Label_Inkscape_title = Label(gen_settings,text="Inkscape Options")
  4993.         self.Label_Inkscape_title.place(x=xd_label_L, y=D_Yloc, width=gen_width-40, height=21)
  4994.        
  4995.         D_Yloc=D_Yloc+D_dY
  4996.         font_entry_width=215
  4997.         self.Label_Inkscape_Path = Label(gen_settings,text="Inkscape Executable")
  4998.         self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  4999.         self.Entry_Inkscape_Path = Entry(gen_settings,width="15")
  5000.         self.Entry_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=font_entry_width, height=23)
  5001.         self.Entry_Inkscape_Path.configure(textvariable=self.inkscape_path)
  5002.         self.Entry_Inkscape_Path.bind('<FocusIn>', self.Inkscape_Path_Message)
  5003.         self.Inkscape_Path = Button(gen_settings,text="Find Inkscape")
  5004.         self.Inkscape_Path.place(x=xd_entry_L+font_entry_width+10, y=D_Yloc, width=110, height=23)
  5005.         self.Inkscape_Path.bind("<ButtonRelease-1>", self.Inkscape_Path_Click)
  5006.  
  5007.         D_Yloc=D_Yloc+D_dY
  5008.         self.Label_Ink_Timeout = Label(gen_settings,text="Inkscape Timeout")
  5009.         self.Label_Ink_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5010.         self.Label_Ink_Timeout_u = Label(gen_settings,text="minutes", anchor=W)
  5011.         self.Label_Ink_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units*2, height=21)
  5012.         self.Entry_Ink_Timeout = Entry(gen_settings,width="15")
  5013.         self.Entry_Ink_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5014.         self.Entry_Ink_Timeout.configure(textvariable=self.ink_timeout)
  5015.         self.ink_timeout.trace_variable("w", self.Entry_Ink_Timeout_Callback)
  5016.         self.entry_set(self.Entry_Ink_Timeout,self.Entry_Ink_Timeout_Check(),2)
  5017.  
  5018.         D_Yloc=D_Yloc+D_dY*1.25
  5019.         self.gen_separator2 = Frame(gen_settings, height=2, bd=1, relief=SUNKEN)
  5020.         self.gen_separator2.place(x=xd_label_L, y=D_Yloc,width=gen_width-40, height=2)
  5021.  
  5022.         D_Yloc=D_Yloc+D_dY*.5
  5023.         self.Label_no_com = Label(gen_settings,text="Home in Upper Right")
  5024.         self.Label_no_com.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5025.         self.Checkbutton_no_com = Checkbutton(gen_settings,text="", anchor=W)
  5026.         self.Checkbutton_no_com.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  5027.         self.Checkbutton_no_com.configure(variable=self.HomeUR)
  5028.         self.HomeUR.trace_variable("w",self.menu_View_Refresh_Callback)        
  5029.  
  5030.         D_Yloc=D_Yloc+D_dY
  5031.         self.Label_Board_Name      = Label(gen_settings,text="Board Name", anchor=CENTER )
  5032.         self.Board_Name_OptionMenu = OptionMenu(gen_settings, self.board_name,
  5033.                                             "LASER-M2",
  5034.                                             "LASER-M1",
  5035.                                             "LASER-M",
  5036.                                             "LASER-B2",
  5037.                                             "LASER-B1",
  5038.                                             "LASER-B",
  5039.                                             "LASER-A")
  5040.         self.Label_Board_Name.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5041.         self.Board_Name_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry*3, height=23)
  5042.  
  5043.         D_Yloc=D_Yloc+D_dY
  5044.         self.Label_Laser_Area_Width = Label(gen_settings,text="Laser Area Width")
  5045.         self.Label_Laser_Area_Width.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5046.         self.Label_Laser_Area_Width_u = Label(gen_settings,textvariable=self.units, anchor=W)
  5047.         self.Label_Laser_Area_Width_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5048.         self.Entry_Laser_Area_Width = Entry(gen_settings,width="15")
  5049.         self.Entry_Laser_Area_Width.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5050.         self.Entry_Laser_Area_Width.configure(textvariable=self.LaserXsize)
  5051.         self.LaserXsize.trace_variable("w", self.Entry_Laser_Area_Width_Callback)
  5052.         self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(),2)
  5053.  
  5054.         D_Yloc=D_Yloc+D_dY
  5055.         self.Label_Laser_Area_Height = Label(gen_settings,text="Laser Area Height")
  5056.         self.Label_Laser_Area_Height.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5057.         self.Label_Laser_Area_Height_u = Label(gen_settings,textvariable=self.units, anchor=W)
  5058.         self.Label_Laser_Area_Height_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5059.         self.Entry_Laser_Area_Height = Entry(gen_settings,width="15")
  5060.         self.Entry_Laser_Area_Height.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5061.         self.Entry_Laser_Area_Height.configure(textvariable=self.LaserYsize)
  5062.         self.LaserYsize.trace_variable("w", self.Entry_Laser_Area_Height_Callback)
  5063.         self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(),2)
  5064.  
  5065.         D_Yloc=D_Yloc+D_dY
  5066.         self.Label_Laser_X_Scale = Label(gen_settings,text="X Scale Factor")
  5067.         self.Label_Laser_X_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5068.         self.Entry_Laser_X_Scale = Entry(gen_settings,width="15")
  5069.         self.Entry_Laser_X_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5070.         self.Entry_Laser_X_Scale.configure(textvariable=self.LaserXscale)
  5071.         self.LaserXscale.trace_variable("w", self.Entry_Laser_X_Scale_Callback)
  5072.         self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(),2)
  5073.  
  5074.         D_Yloc=D_Yloc+D_dY
  5075.         self.Label_Laser_Y_Scale = Label(gen_settings,text="Y Scale Factor")
  5076.         self.Label_Laser_Y_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5077.         self.Entry_Laser_Y_Scale = Entry(gen_settings,width="15")
  5078.         self.Entry_Laser_Y_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5079.         self.Entry_Laser_Y_Scale.configure(textvariable=self.LaserYscale)
  5080.         self.LaserYscale.trace_variable("w", self.Entry_Laser_Y_Scale_Callback)
  5081.         self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(),2)
  5082.                
  5083.         D_Yloc=D_Yloc+D_dY+10
  5084.         self.Label_SaveConfig = Label(gen_settings,text="Configuration File")
  5085.         self.Label_SaveConfig.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5086.  
  5087.         self.GEN_SaveConfig = Button(gen_settings,text="Save")
  5088.         self.GEN_SaveConfig.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=21, anchor="nw")
  5089.         self.GEN_SaveConfig.bind("<ButtonRelease-1>", self.Write_Config_File)
  5090.        
  5091.         ## Buttons ##
  5092.         gen_settings.update_idletasks()
  5093.         Ybut=int(gen_settings.winfo_height())-30
  5094.         Xbut=int(gen_settings.winfo_width()/2)
  5095.  
  5096.         self.GEN_Close = Button(gen_settings,text="Close")
  5097.         self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
  5098.         self.GEN_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
  5099.  
  5100.         self.Set_Input_States_BATCH()
  5101.  
  5102.     ################################################################################
  5103.     #                          Raster Settings Window                              #
  5104.     ################################################################################
  5105.     def RASTER_Settings_Window(self):
  5106.         Wset=425+280
  5107.         Hset=330 #260
  5108.         raster_settings = Toplevel(width=Wset, height=Hset)
  5109.         raster_settings.grab_set() # Use grab_set to prevent user input in the main window
  5110.         raster_settings.focus_set()
  5111.         raster_settings.resizable(0,0)
  5112.         raster_settings.title('Raster Settings')
  5113.         raster_settings.iconname("Raster Settings")
  5114.  
  5115.         D_Yloc  = 6
  5116.         D_dY = 24
  5117.         xd_label_L = 12
  5118.  
  5119.         w_label=155
  5120.         w_entry=60
  5121.         w_units=35
  5122.         xd_entry_L=xd_label_L+w_label+10
  5123.         xd_units_L=xd_entry_L+w_entry+5
  5124.  
  5125.         D_Yloc=D_Yloc+D_dY
  5126.         self.Label_Rstep   = Label(raster_settings,text="Scanline Step", anchor=CENTER )
  5127.         self.Label_Rstep.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5128.         self.Label_Rstep_u = Label(raster_settings,text="in", anchor=W)
  5129.         self.Label_Rstep_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5130.         self.Entry_Rstep   = Entry(raster_settings,width="15")
  5131.         self.Entry_Rstep.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5132.         self.Entry_Rstep.configure(textvariable=self.rast_step)
  5133.         self.rast_step.trace_variable("w", self.Entry_Rstep_Callback)
  5134.  
  5135.         D_Yloc=D_Yloc+D_dY
  5136.         self.Label_EngraveUP = Label(raster_settings,text="Engrave Bottom Up")
  5137.         self.Checkbutton_EngraveUP = Checkbutton(raster_settings,text=" ", anchor=W)
  5138.         self.Checkbutton_EngraveUP.configure(variable=self.engraveUP)
  5139.         self.Label_EngraveUP.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5140.         self.Checkbutton_EngraveUP.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  5141.        
  5142.         D_Yloc=D_Yloc+D_dY
  5143.         self.Label_Halftone = Label(raster_settings,text="Halftone (Dither)")
  5144.         self.Label_Halftone.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5145.         self.Checkbutton_Halftone = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_RASTER)
  5146.         self.Checkbutton_Halftone.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  5147.         self.Checkbutton_Halftone.configure(variable=self.halftone)
  5148.         self.halftone.trace_variable("w", self.menu_View_Refresh_Callback)
  5149.  
  5150.         ############
  5151.         D_Yloc=D_Yloc+D_dY
  5152.         self.Label_Halftone_DPI      = Label(raster_settings,text="Halftone Resolution", anchor=CENTER )
  5153.  
  5154.         if self.reduced_mem.get():
  5155.             if self.ht_size == "1000": self.ht_size = "500"
  5156.             if self.ht_size == "333":  self.ht_size = "500"
  5157.             if self.ht_size == "200":  self.ht_size = "250"
  5158.             if self.ht_size == "143":  self.ht_size = "167"
  5159.             self.Halftone_DPI_OptionMenu = OptionMenu(raster_settings, self.ht_size,
  5160.                                                 "500",
  5161.                                                 "250",
  5162.                                                 "167",
  5163.                                                 "125")
  5164.         else:
  5165.             self.Halftone_DPI_OptionMenu = OptionMenu(raster_settings, self.ht_size,
  5166.                                                 "1000",
  5167.                                                 "500",
  5168.                                                 "333",
  5169.                                                 "250",
  5170.                                                 "200",
  5171.                                                 "167",
  5172.                                                 "143",
  5173.                                                 "125")
  5174.  
  5175.         self.Label_Halftone_DPI.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5176.         self.Halftone_DPI_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry+30, height=23)
  5177.  
  5178.         self.Label_Halftone_u = Label(raster_settings,text="dpi", anchor=W)
  5179.         self.Label_Halftone_u.place(x=xd_units_L+30, y=D_Yloc, width=w_units, height=21)
  5180.  
  5181.         ############
  5182.         D_Yloc=D_Yloc+D_dY+5
  5183.         self.Label_bezier_M1  = Label(raster_settings,
  5184.                                 text="Slope, Black (%.1f)"%(self.bezier_M1_default),
  5185.                                 anchor=CENTER )
  5186.         self.bezier_M1_Slider = Scale(raster_settings, from_=1, to=50, resolution=0.1, \
  5187.                                 orient=HORIZONTAL, variable=self.bezier_M1)
  5188.         self.bezier_M1_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
  5189.         D_Yloc=D_Yloc+21
  5190.         self.Label_bezier_M1.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5191.         self.bezier_M1.trace_variable("w", self.bezier_M1_Callback)
  5192.        
  5193.         D_Yloc=D_Yloc+D_dY-8
  5194.         self.Label_bezier_M2  = Label(raster_settings,
  5195.                                 text="Slope, White (%.2f)"%(self.bezier_M2_default),
  5196.                                 anchor=CENTER )
  5197.         self.bezier_M2_Slider = Scale(raster_settings, from_=0.0, to=1, \
  5198.                                 orient=HORIZONTAL,resolution=0.01, variable=self.bezier_M2)
  5199.         self.bezier_M2_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
  5200.         D_Yloc=D_Yloc+21
  5201.         self.Label_bezier_M2.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5202.         self.bezier_M2.trace_variable("w", self.bezier_M2_Callback)
  5203.  
  5204.         D_Yloc=D_Yloc+D_dY-8
  5205.         self.Label_bezier_weight   = Label(raster_settings,
  5206.                                      text="Transition (%.1f)"%(self.bezier_M1_default),
  5207.                                      anchor=CENTER )
  5208.         self.bezier_weight_Slider = Scale(raster_settings, from_=0, to=10, resolution=0.1, \
  5209.                                     orient=HORIZONTAL, variable=self.bezier_weight)
  5210.         self.bezier_weight_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
  5211.         D_Yloc=D_Yloc+21
  5212.         self.Label_bezier_weight.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5213.         self.bezier_weight.trace_variable("w", self.bezier_weight_Callback)
  5214.  
  5215. ##        show_unsharp = False
  5216. ##        if DEBUG and show_unsharp:
  5217. ##            D_Yloc=D_Yloc+D_dY
  5218. ##            self.Label_UnsharpMask = Label(raster_settings,text="Unsharp Mask")
  5219. ##            self.Label_UnsharpMask.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5220. ##            self.Checkbutton_UnsharpMask = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_Unsharp)
  5221. ##            self.Checkbutton_UnsharpMask.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  5222. ##            self.Checkbutton_UnsharpMask.configure(variable=self.unsharp_flag)
  5223. ##            self.unsharp_flag.trace_variable("w", self.menu_View_Refresh_Callback)
  5224. ##
  5225. ##            D_Yloc=D_Yloc+D_dY
  5226. ##            self.Label_Unsharp_Radius   = Label(raster_settings,text="Unsharp Mask Radius", anchor=CENTER )
  5227. ##            self.Label_Unsharp_Radius.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5228. ##            self.Label_Unsharp_Radius_u = Label(raster_settings,text="Pixels", anchor=W)
  5229. ##            self.Label_Unsharp_Radius_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5230. ##            self.Entry_Unsharp_Radius   = Entry(raster_settings,width="15")
  5231. ##            self.Entry_Unsharp_Radius.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5232. ##            self.Entry_Unsharp_Radius.configure(textvariable=self.unsharp_r)
  5233. ##            self.unsharp_r.trace_variable("w", self.Entry_Unsharp_Radius_Callback)
  5234. ##
  5235. ##            D_Yloc=D_Yloc+D_dY
  5236. ##            self.Label_Unsharp_Percent   = Label(raster_settings,text="Unsharp Mask Percent", anchor=CENTER )
  5237. ##            self.Label_Unsharp_Percent.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5238. ##            self.Label_Unsharp_Percent_u = Label(raster_settings,text="%", anchor=W)
  5239. ##            self.Label_Unsharp_Percent_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5240. ##            self.Entry_Unsharp_Percent   = Entry(raster_settings,width="15")
  5241. ##            self.Entry_Unsharp_Percent.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5242. ##            self.Entry_Unsharp_Percent.configure(textvariable=self.unsharp_p)
  5243. ##            self.unsharp_p.trace_variable("w", self.Entry_Unsharp_Percent_Callback)
  5244. ##
  5245. ##            D_Yloc=D_Yloc+D_dY
  5246. ##            self.Label_Unsharp_Threshold   = Label(raster_settings,text="Unsharp Mask Threshold", anchor=CENTER )
  5247. ##            self.Label_Unsharp_Threshold.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5248. ##            #self.Label_Unsharp_Threshold_u = Label(raster_settings,text="Pixels", anchor=W)
  5249. ##            #self.Label_Unsharp_Threshold_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5250. ##            self.Entry_Unsharp_Threshold   = Entry(raster_settings,width="15")
  5251. ##            self.Entry_Unsharp_Threshold.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5252. ##            self.Entry_Unsharp_Threshold.configure(textvariable=self.unsharp_t)
  5253. ##            self.unsharp_t.trace_variable("w", self.Entry_Unsharp_Threshold_Callback)        
  5254.  
  5255.         # Bezier Canvas
  5256.         self.Bezier_frame = Frame(raster_settings, bd=1, relief=SUNKEN)
  5257.         self.Bezier_frame.place(x=Wset-280, y=10, height=265, width=265)
  5258.         self.BezierCanvas = Canvas(self.Bezier_frame, background="white")
  5259.         self.BezierCanvas.pack(side=LEFT, fill=BOTH, expand=1)
  5260.         self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="grey75", capstyle="round", width = 2, tags='perm')
  5261.  
  5262.  
  5263.         M1 = self.bezier_M1_default
  5264.         M2 = self.bezier_M2_default
  5265.         w  = self.bezier_weight_default
  5266.         num = 10
  5267.         x,y = self.generate_bezier(M1,M2,w,n=num)
  5268.         for i in range(0,num):
  5269.             self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="grey85", stipple='gray25',\
  5270.                                            capstyle="round", width = 2, tags='perm')
  5271.        
  5272.  
  5273.         ## Buttons ##
  5274.         raster_settings.update_idletasks()
  5275.         Ybut=int(raster_settings.winfo_height())-30
  5276.         Xbut=int(raster_settings.winfo_width()/2)
  5277.  
  5278.         self.RASTER_Close = Button(raster_settings,text="Close")
  5279.         self.RASTER_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
  5280.         self.RASTER_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
  5281.  
  5282.         self.bezier_M1_Callback()
  5283.         self.Set_Input_States_RASTER()
  5284.         #if DEBUG and show_unsharp:
  5285.         #    self.Set_Input_States_Unsharp()
  5286.  
  5287.  
  5288.     ################################################################################
  5289.     #                         Rotary Settings Window                               #
  5290.     ################################################################################
  5291.     def ROTARY_Settings_Window(self):
  5292.         rotary_settings = Toplevel(width=350, height=175)
  5293.         rotary_settings.grab_set() # Use grab_set to prevent user input in the main window
  5294.         rotary_settings.focus_set()
  5295.         rotary_settings.resizable(0,0)
  5296.         rotary_settings.title('Rotary Settings')
  5297.         rotary_settings.iconname("Rotary Settings")
  5298.  
  5299.         D_Yloc  = 6
  5300.         D_dY = 30
  5301.         xd_label_L = 12
  5302.  
  5303.         w_label=180
  5304.         w_entry=40
  5305.         w_units=45
  5306.         xd_entry_L=xd_label_L+w_label+10
  5307.         xd_units_L=xd_entry_L+w_entry+5
  5308.         sep_border=10
  5309.        
  5310.  
  5311.         D_Yloc=D_Yloc+D_dY-15
  5312.         self.Label_Rotary_Enable = Label(rotary_settings,text="Use Rotary Settings")
  5313.         self.Label_Rotary_Enable.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5314.         self.Checkbutton_Rotary_Enable = Checkbutton(rotary_settings,text="", anchor=W, command=self.Set_Input_States_Rotary)
  5315.         self.Checkbutton_Rotary_Enable.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  5316.         self.Checkbutton_Rotary_Enable.configure(variable=self.rotary)
  5317.  
  5318.         D_Yloc=D_Yloc+D_dY
  5319.         self.Label_Laser_R_Scale = Label(rotary_settings,text="Rotary Scale Factor (Y axis)")
  5320.         self.Label_Laser_R_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5321.         self.Entry_Laser_R_Scale = Entry(rotary_settings,width="15")
  5322.         self.Entry_Laser_R_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5323.         self.Entry_Laser_R_Scale.configure(textvariable=self.LaserRscale)
  5324.         self.LaserRscale.trace_variable("w", self.Entry_Laser_R_Scale_Callback)
  5325.         self.entry_set(self.Entry_Laser_R_Scale,self.Entry_Laser_R_Scale_Check(),2)
  5326.  
  5327.         D_Yloc=D_Yloc+D_dY
  5328.         self.Label_Laser_Rapid_Feed = Label(rotary_settings,text="Rapid Speed (default=0)")
  5329.         self.Label_Laser_Rapid_Feed.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5330.         self.Label_Laser_Rapid_Feed_u = Label(rotary_settings,textvariable=self.funits, anchor=W)
  5331.         self.Label_Laser_Rapid_Feed_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5332.         self.Entry_Laser_Rapid_Feed = Entry(rotary_settings,width="15")
  5333.         self.Entry_Laser_Rapid_Feed.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5334.         self.Entry_Laser_Rapid_Feed.configure(textvariable=self.rapid_feed)
  5335.         self.rapid_feed.trace_variable("w", self.Entry_Laser_Rapid_Feed_Callback)
  5336.         self.entry_set(self.Entry_Laser_Rapid_Feed,self.Entry_Laser_Rapid_Feed_Check(),2)
  5337.        
  5338.         ## Buttons ##
  5339.         rotary_settings.update_idletasks()
  5340.         Ybut=int(rotary_settings.winfo_height())-30
  5341.         Xbut=int(rotary_settings.winfo_width()/2)
  5342.  
  5343.         self.GEN_Close = Button(rotary_settings,text="Close")
  5344.         self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
  5345.         self.GEN_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
  5346.  
  5347.         self.Set_Input_States_Rotary()
  5348.  
  5349.     ################################################################################
  5350.     #                            Trace Send Window                                 #
  5351.     ################################################################################
  5352.  
  5353.     def TRACE_Settings_Window(self, dummy=None):
  5354.         if self.GUI_Disabled:
  5355.             return
  5356.         trace_window = Toplevel(width=350, height=180)
  5357.         self.trace_window=trace_window
  5358.         trace_window.grab_set() # Use grab_set to prevent user input in the main window during calculations
  5359.         trace_window.resizable(0,0)
  5360.         trace_window.title('Trace Boundary')
  5361.         trace_window.iconname("Trace Boundary")
  5362.  
  5363.         def Close_Click():
  5364.             win_id=self.grab_current()
  5365.             self.PreviewCanvas.delete('trace')
  5366.             win_id.destroy()
  5367.  
  5368.         def Close_and_Send_Click():
  5369.             win_id=self.grab_current()
  5370.             self.PreviewCanvas.delete('trace')
  5371.             win_id.destroy()
  5372.             self.Trace_Eng()
  5373.  
  5374.         D_Yloc  = 0
  5375.         D_dY = 28
  5376.         xd_label_L = 12
  5377.  
  5378.         w_label=225
  5379.         w_entry=40
  5380.         w_units=50
  5381.         xd_entry_L=xd_label_L+w_label+10
  5382.         xd_units_L=xd_entry_L+w_entry+5
  5383.  
  5384.         D_Yloc=D_Yloc+D_dY
  5385.         self.Label_Laser_Trace = Label(trace_window,text="Laser 'On' During Trace")
  5386.         self.Label_Laser_Trace.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5387.         self.Checkbutton_Laser_Trace = Checkbutton(trace_window,text="", anchor=W)
  5388.         self.Checkbutton_Laser_Trace.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  5389.         self.Checkbutton_Laser_Trace.configure(variable=self.trace_w_laser)
  5390.  
  5391.         D_Yloc=D_Yloc+D_dY
  5392.         self.Label_Trace_Gap = Label(trace_window,text="Gap Between Design and Trace")
  5393.         self.Label_Trace_Gap.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5394.         self.Entry_Trace_Gap = Entry(trace_window,width="15")
  5395.         self.Entry_Trace_Gap.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5396.         self.Label_Trace_Gap_u = Label(trace_window,textvariable=self.units, anchor=W)
  5397.         self.Label_Trace_Gap_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5398.         self.Entry_Trace_Gap.configure(textvariable=self.trace_gap,justify='center')
  5399.         self.trace_gap.trace_variable("w", self.Entry_Trace_Gap_Callback)
  5400.         self.entry_set(self.Entry_Trace_Gap,self.Entry_Trace_Gap_Check(),2)
  5401.         if not PYCLIPPER:
  5402.             self.Label_Trace_Gap.configure(state="disabled")
  5403.             self.Label_Trace_Gap_u.configure(state="disabled")
  5404.             self.Entry_Trace_Gap.configure(state="disabled")
  5405.            
  5406.         D_Yloc=D_Yloc+D_dY
  5407.         self.Trace_Button = Button(trace_window,text="Trace Boundary With Laser Head",command=Close_and_Send_Click)
  5408.         self.Trace_Button.place(x=xd_label_L, y=D_Yloc, width=w_label, height=23)
  5409.        
  5410.         self.Entry_Trace_Speed = Entry(trace_window,width="15")
  5411.         self.Entry_Trace_Speed.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5412.         green = "#%02x%02x%02x" % (0, 200, 0)
  5413.         self.Entry_Trace_Speed.configure(textvariable=self.trace_speed,justify='center',fg=green)
  5414.         self.trace_speed.trace_variable("w", self.Entry_Trace_Speed_Callback)
  5415.         self.entry_set(self.Entry_Trace_Speed,self.Entry_Trace_Speed_Check(),2)
  5416.         self.Label_Trace_Speed_u = Label(trace_window,textvariable=self.funits, anchor=W)
  5417.         self.Label_Trace_Speed_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  5418.        
  5419.        
  5420.         ## Buttons ##
  5421.         trace_window.update_idletasks()
  5422.         Ybut=int(trace_window.winfo_height())-30
  5423.         Xbut=int(trace_window.winfo_width()/2)
  5424.  
  5425.         self.Trace_Close = Button(trace_window,text="Cancel",command=Close_Click)
  5426.         self.Trace_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
  5427.         ################################################################################
  5428.  
  5429.     ################################################################################
  5430.     #                            EGV Send Window                                   #
  5431.     ################################################################################
  5432.     def EGV_Send_Window(self,EGV_filename):
  5433.        
  5434.         egv_send = Toplevel(width=400, height=180)
  5435.         egv_send.grab_set() # Use grab_set to prevent user input in the main window during calculations
  5436.         egv_send.resizable(0,0)
  5437.         egv_send.title('EGV Send')
  5438.         egv_send.iconname("EGV Send")
  5439.  
  5440.         D_Yloc  = 0
  5441.         D_dY = 28
  5442.         xd_label_L = 12
  5443.  
  5444.         w_label=150
  5445.         w_entry=40
  5446.         w_units=35
  5447.         xd_entry_L=xd_label_L+w_label+10
  5448.         xd_units_L=xd_entry_L+w_entry+5
  5449.  
  5450.         D_Yloc=D_Yloc+D_dY
  5451.         self.Label_Preprocess_CRC = Label(egv_send,text="Preprocess CRC Data")
  5452.         self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5453.         self.Checkbutton_Preprocess_CRC = Checkbutton(egv_send,text="", anchor=W)
  5454.         self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  5455.         self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc)
  5456.  
  5457.         D_Yloc=D_Yloc+D_dY
  5458.         self.Label_N_EGV_Passes = Label(egv_send,text="Number of EGV Passes")
  5459.         self.Label_N_EGV_Passes.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5460.         self.Entry_N_EGV_Passes = Entry(egv_send,width="15")
  5461.         self.Entry_N_EGV_Passes.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  5462.         self.Entry_N_EGV_Passes.configure(textvariable=self.n_egv_passes)
  5463.         self.n_egv_passes.trace_variable("w", self.Entry_N_EGV_Passes_Callback)
  5464.         self.entry_set(self.Entry_N_EGV_Passes,self.Entry_N_EGV_Passes_Check(),2)
  5465.  
  5466.         D_Yloc=D_Yloc+D_dY
  5467.         font_entry_width=215
  5468.         self.Label_Inkscape_Path = Label(egv_send,text="EGV File:")
  5469.         self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  5470.  
  5471.         EGV_Name = os.path.basename(EGV_filename)
  5472.         self.Label_Inkscape_Path = Label(egv_send,text=EGV_Name,anchor="w") #,bg="yellow")
  5473.         self.Label_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=200, height=21,anchor="nw")
  5474.        
  5475.         ## Buttons ##
  5476.         egv_send.update_idletasks()
  5477.         Ybut=int(egv_send.winfo_height())-30
  5478.         Xbut=int(egv_send.winfo_width()/2)
  5479.  
  5480.         self.EGV_Close = Button(egv_send,text="Cancel")
  5481.         self.EGV_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="e")
  5482.         self.EGV_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click)
  5483.  
  5484.         def Close_and_Send_Click():
  5485.             win_id=self.grab_current()
  5486.             win_id.destroy()
  5487.             self.Open_EGV(EGV_filename, n_passes=int( float(self.n_egv_passes.get()) ))
  5488.            
  5489.         self.EGV_Send = Button(egv_send,text="Send EGV Data",command=Close_and_Send_Click)
  5490.         self.EGV_Send.place(x=Xbut, y=Ybut, width=130, height=30, anchor="w")
  5491.         ################################################################################
  5492.        
  5493.        
  5494. ################################################################################
  5495. #             Function for outputting messages to different locations          #
  5496. #            depending on what options are enabled                             #
  5497. ################################################################################
  5498. def fmessage(text,newline=True):
  5499.     global QUIET
  5500.     if (not QUIET):
  5501.         if newline==True:
  5502.             try:
  5503.                 sys.stdout.write(text)
  5504.                 sys.stdout.write("\n")
  5505.                 debug_message(traceback.format_exc())
  5506.             except:
  5507.                 debug_message(traceback.format_exc())
  5508.                 pass
  5509.         else:
  5510.             try:
  5511.                 sys.stdout.write(text)
  5512.                 debug_message(traceback.format_exc())
  5513.             except:
  5514.                 debug_message(traceback.format_exc())
  5515.                 pass
  5516.  
  5517. ################################################################################
  5518. #                               Message Box                                    #
  5519. ################################################################################
  5520. def message_box(title,message):
  5521.     title = "%s (K40 Whisperer V%s)" %(title,version)
  5522.     if VERSION == 3:
  5523.         tkinter.messagebox.showinfo(title,message)
  5524.     else:
  5525.         tkMessageBox.showinfo(title,message)
  5526.         pass
  5527.  
  5528. ################################################################################
  5529. #                          Message Box ask OK/Cancel                           #
  5530. ################################################################################
  5531. def message_ask_ok_cancel(title, mess):
  5532.     if VERSION == 3:
  5533.         result=tkinter.messagebox.askokcancel(title, mess)
  5534.     else:
  5535.         result=tkMessageBox.askokcancel(title, mess)
  5536.     return result
  5537.  
  5538. ################################################################################
  5539. #                         Debug Message Box                                    #
  5540. ################################################################################
  5541. def debug_message(message):
  5542.     global DEBUG
  5543.     title = "Debug Message"
  5544.     if DEBUG:
  5545.         if VERSION == 3:
  5546.             tkinter.messagebox.showinfo(title,message)
  5547.         else:
  5548.             tkMessageBox.showinfo(title,message)
  5549.             pass
  5550.  
  5551. ################################################################################
  5552. #                         Choose Units Dialog                                  #
  5553. ################################################################################
  5554. if VERSION < 3:
  5555.     import tkSimpleDialog
  5556. else:
  5557.     import tkinter.simpledialog as tkSimpleDialog
  5558.  
  5559. class UnitsDialog(tkSimpleDialog.Dialog):
  5560.     def body(self, master):
  5561.         self.resizable(0,0)
  5562.         self.title('Units')
  5563.         self.iconname("Units")
  5564.        
  5565.         self.uom = StringVar()
  5566.         self.uom.set("Millimeters")
  5567.  
  5568.         Label(master, text="Select DXF Import Units:").grid(row=0)
  5569.         Radio_Units_IN = Radiobutton(master,text="Inches",        value="Inches")
  5570.         Radio_Units_MM = Radiobutton(master,text="Millimeters",   value="Millimeters")
  5571.         Radio_Units_CM = Radiobutton(master,text="Centimeters",   value="Centimeters")
  5572.        
  5573.         Radio_Units_IN.grid(row=1, sticky=W)
  5574.         Radio_Units_MM.grid(row=2, sticky=W)
  5575.         Radio_Units_CM.grid(row=3, sticky=W)
  5576.  
  5577.         Radio_Units_IN.configure(variable=self.uom)
  5578.         Radio_Units_MM.configure(variable=self.uom)
  5579.         Radio_Units_CM.configure(variable=self.uom)
  5580.  
  5581.     def apply(self):
  5582.         self.result = self.uom.get()
  5583.         return
  5584.  
  5585.  
  5586. class toplevel_dummy():
  5587.     def winfo_exists(self):
  5588.         return False
  5589.    
  5590. class pxpiDialog(tkSimpleDialog.Dialog):
  5591.        
  5592.     def __init__(self,
  5593.                  parent,
  5594.                  units = "mm",
  5595.                  SVG_Size            =None,
  5596.                  SVG_ViewBox         =None,
  5597.                  SVG_inkscape_version=None):
  5598.  
  5599.         self.result = None
  5600.         self.svg_pxpi   = StringVar()
  5601.         self.other      = StringVar()
  5602.         self.svg_width  = StringVar()
  5603.         self.svg_height = StringVar()
  5604.         self.svg_units  = StringVar()
  5605.         self.fixed_size = False
  5606.         self.svg_units.set(units)
  5607.         if units=="mm":
  5608.             self.scale=1.0
  5609.         else:
  5610.             self.scale=1/25.4
  5611.  
  5612.        
  5613.         ###################################
  5614.         ##       Set initial pxpi          #
  5615.         ###################################
  5616.         pxpi = 72.0
  5617.         if SVG_inkscape_version != None:
  5618.             if SVG_inkscape_version >=.92:
  5619.                 pxpi = 96.0
  5620.             else:
  5621.                 pxpi = 90.0
  5622.  
  5623.         self.svg_pxpi.set("%d"%(pxpi))
  5624.         self.other.set("%d"%(pxpi))
  5625.  
  5626.         ###################################
  5627.         ##       Set minx/miny            #
  5628.         ###################################
  5629.         if SVG_ViewBox!=None and SVG_ViewBox[0]!=None and SVG_ViewBox[1]!=None:
  5630.             self.minx_pixels = SVG_ViewBox[0]
  5631.             self.miny_pixels = SVG_ViewBox[1]
  5632.         else:
  5633.             self.minx_pixels = 0.0
  5634.             self.miny_pixels = 0.0
  5635.            
  5636.         ###################################
  5637.         ##       Set Initial Size         #
  5638.         ###################################
  5639.         if SVG_Size!=None and SVG_Size[2]!=None and SVG_Size[3]!=None:
  5640.             self.width_pixels = SVG_Size[2]
  5641.             self.height_pixels = SVG_Size[3]
  5642.         elif SVG_ViewBox!=None and SVG_ViewBox[2]!=None and SVG_ViewBox[3]!=None:
  5643.             self.width_pixels = SVG_ViewBox[2]
  5644.             self.height_pixels = SVG_ViewBox[3]
  5645.         else:
  5646.             self.width_pixels  = 500.0
  5647.             self.height_pixels = 500.0
  5648.         ###################################
  5649.         ##       Set Initial Size         #
  5650.         ###################################
  5651.         if SVG_Size[0]!=None and SVG_Size[1]!=None:
  5652.             width  = SVG_Size[0]
  5653.             height = SVG_Size[1]
  5654.             self.fixed_size=True
  5655.         else:
  5656.             width  = self.width_pixels/float(self.svg_pxpi.get())*25.4
  5657.             height = self.height_pixels/float(self.svg_pxpi.get())*25.4
  5658.            
  5659.         self.svg_width.set("%f" %(width*self.scale))
  5660.         self.svg_height.set("%f" %(height*self.scale))
  5661.         ###################################
  5662.         tkSimpleDialog.Dialog.__init__(self, parent)
  5663.  
  5664.  
  5665.     def body(self, master):
  5666.         self.resizable(0,0)
  5667.         self.title('SVG Import Scale:')
  5668.         self.iconname("SVG Scale")
  5669.        
  5670.         ###########################################################################
  5671.         def Entry_custom_Check():
  5672.             try:
  5673.                 value = float(self.other.get())
  5674.                 if  value <= 0.0:
  5675.                     return 2 # Value is invalid number
  5676.             except:
  5677.                 return 3     # Value not a number
  5678.             return 0         # Value is a valid number
  5679.         def Entry_custom_Callback(varName, index, mode):
  5680.             if Entry_custom_Check() > 0:
  5681.                 Entry_Custom_pxpi.configure( bg = 'red' )
  5682.             else:
  5683.                 Entry_Custom_pxpi.configure( bg = 'white' )
  5684.                 pxpi = float(self.other.get())
  5685.                 width  = self.width_pixels/pxpi*25.4
  5686.                 height = self.height_pixels/pxpi*25.4
  5687.                 if self.fixed_size:
  5688.                     pass
  5689.                 else:
  5690.                     Set_Value(width=width*self.scale,height=height*self.scale)
  5691.                 self.svg_pxpi.set("custom")
  5692.         ###################################################
  5693.         def Entry_Width_Check():
  5694.             try:
  5695.                 value = float(self.svg_width.get())/self.scale
  5696.                 if  value <= 0.0:
  5697.                     return 2 # Value is invalid number
  5698.             except:
  5699.                 return 3     # Value not a number
  5700.             return 0         # Value is a valid number
  5701.         def Entry_Width_Callback(varName, index, mode):
  5702.             if Entry_Width_Check() > 0:
  5703.                 Entry_Custom_Width.configure( bg = 'red' )
  5704.             else:
  5705.                 Entry_Custom_Width.configure( bg = 'white' )
  5706.                 width = float(self.svg_width.get())/self.scale
  5707.                 pxpi = self.width_pixels*25.4/width
  5708.                 height = self.height_pixels/pxpi*25.4
  5709.                 Set_Value(other=pxpi,height=height*self.scale)
  5710.                 self.svg_pxpi.set("custom")
  5711.         ###################################################
  5712.         def Entry_Height_Check():
  5713.             try:
  5714.                 value = float(self.svg_height.get())
  5715.                 if  value <= 0.0:
  5716.                     return 2 # Value is invalid number
  5717.             except:
  5718.                 return 3     # Value not a number
  5719.             return 0         # Value is a valid number
  5720.         def Entry_Height_Callback(varName, index, mode):
  5721.             if Entry_Height_Check() > 0:
  5722.                 Entry_Custom_Height.configure( bg = 'red' )
  5723.             else:
  5724.                 Entry_Custom_Height.configure( bg = 'white' )
  5725.                 height = float(self.svg_height.get())/self.scale
  5726.                 pxpi = self.height_pixels*25.4/height
  5727.                 width = self.width_pixels/pxpi*25.4
  5728.                 Set_Value(other=pxpi,width=width*self.scale)
  5729.                 self.svg_pxpi.set("custom")
  5730.         ###################################################      
  5731.         def SVG_pxpi_callback(varName, index, mode):
  5732.             if self.svg_pxpi.get() == "custom":
  5733.                 try:
  5734.                     pxpi=float(self.other.get())
  5735.                 except:
  5736.                     pass
  5737.             else:
  5738.                 pxpi=float(self.svg_pxpi.get())
  5739.                 width  = self.width_pixels/pxpi*25.4
  5740.                 height = self.height_pixels/pxpi*25.4
  5741.                 if self.fixed_size:
  5742.                     Set_Value(other=pxpi)
  5743.                 else:
  5744.                     Set_Value(other=pxpi,width=width*self.scale,height=height*self.scale)
  5745.                
  5746.         ###########################################################################
  5747.                    
  5748.         def Set_Value(other=None,width=None,height=None):
  5749.             self.svg_pxpi.trace_vdelete("w",self.trace_id_svg_pxpi)
  5750.             self.other.trace_vdelete("w",self.trace_id_pxpi)
  5751.             self.svg_width.trace_vdelete("w",self.trace_id_width)
  5752.             self.svg_height.trace_vdelete("w",self.trace_id_height)
  5753.             self.update_idletasks()
  5754.            
  5755.             if other != None:
  5756.                 self.other.set("%f" %(other))
  5757.             if width != None:
  5758.                 self.svg_width.set("%f" %(width))
  5759.             if height != None:
  5760.                 self.svg_height.set("%f" %(height))
  5761.            
  5762.             self.trace_id_svg_pxpi = self.svg_pxpi.trace_variable("w", SVG_pxpi_callback)
  5763.             self.trace_id_pxpi     = self.other.trace_variable("w", Entry_custom_Callback)
  5764.             self.trace_id_width   = self.svg_width.trace_variable("w", Entry_Width_Callback)
  5765.             self.trace_id_height  = self.svg_height.trace_variable("w", Entry_Height_Callback)
  5766.             self.update_idletasks()
  5767.            
  5768.         ###########################################################################
  5769.         t0="This dialog opens if the SVG file you are opening\n"
  5770.         t1="does not contain enough information to determine\n"
  5771.         t2="the intended physical size of the design.\n"
  5772.         t3="Select an SVG Import Scale:\n"
  5773.         Title_Text0 = Label(master, text=t0+t1+t2, anchor=W)
  5774.         Title_Text1 = Label(master, text=t3, anchor=W)
  5775.        
  5776.         Radio_SVG_pxpi_96   = Radiobutton(master,text=" 96 units/in", value="96")
  5777.         Label_SVG_pxpi_96   = Label(master,text="(File saved with Inkscape v0.92 or newer)", anchor=W)
  5778.        
  5779.         Radio_SVG_pxpi_90   = Radiobutton(master,text=" 90 units/in", value="90")
  5780.         Label_SVG_pxpi_90   = Label(master,text="(File saved with Inkscape v0.91 or older)", anchor=W)
  5781.        
  5782.         Radio_SVG_pxpi_72   = Radiobutton(master,text=" 72 units/in", value="72")
  5783.         Label_SVG_pxpi_72   = Label(master,text="(File saved with Adobe Illustrator)", anchor=W)
  5784.  
  5785.         Radio_Res_Custom = Radiobutton(master,text=" Custom:", value="custom")
  5786.         Bottom_row       = Label(master, text=" ")
  5787.        
  5788.  
  5789.         Entry_Custom_pxpi   = Entry(master,width="10")
  5790.         Entry_Custom_pxpi.configure(textvariable=self.other)
  5791.         Label_pxpi_units =  Label(master,text="units/in", anchor=W)
  5792.         self.trace_id_pxpi = self.other.trace_variable("w", Entry_custom_Callback)
  5793.  
  5794.         Label_Width =  Label(master,text="Width", anchor=W)
  5795.         Entry_Custom_Width   = Entry(master,width="10")
  5796.         Entry_Custom_Width.configure(textvariable=self.svg_width)
  5797.         Label_Width_units =  Label(master,textvariable=self.svg_units, anchor=W)
  5798.         self.trace_id_width = self.svg_width.trace_variable("w", Entry_Width_Callback)
  5799.  
  5800.         Label_Height =  Label(master,text="Height", anchor=W)
  5801.         Entry_Custom_Height   = Entry(master,width="10")
  5802.         Entry_Custom_Height.configure(textvariable=self.svg_height)
  5803.         Label_Height_units =  Label(master,textvariable=self.svg_units, anchor=W)
  5804.         self.trace_id_height = self.svg_height.trace_variable("w", Entry_Height_Callback)
  5805.  
  5806.         if self.fixed_size == True:
  5807.              Entry_Custom_Width.configure(state="disabled")
  5808.              Entry_Custom_Height.configure(state="disabled")
  5809.         ###########################################################################
  5810.         rn=0
  5811.         Title_Text0.grid(row=rn,column=0,columnspan=5, sticky=W)
  5812.        
  5813.         rn=rn+1
  5814.         Title_Text1.grid(row=rn,column=0,columnspan=5, sticky=W)
  5815.  
  5816.         rn=rn+1
  5817.         Radio_SVG_pxpi_96.grid(    row=rn, sticky=W)
  5818.         Label_SVG_pxpi_96.grid(    row=rn, column=1,columnspan=50, sticky=W)
  5819.  
  5820.         rn=rn+1
  5821.         Radio_SVG_pxpi_90.grid(    row=rn, sticky=W)
  5822.         Label_SVG_pxpi_90.grid(    row=rn, column=1,columnspan=50, sticky=W)
  5823.        
  5824.         rn=rn+1
  5825.         Radio_SVG_pxpi_72.grid(    row=rn, column=0, sticky=W)
  5826.         Label_SVG_pxpi_72.grid(    row=rn, column=1,columnspan=50, sticky=W)
  5827.        
  5828.         rn=rn+1
  5829.         Radio_Res_Custom.grid(    row=rn, column=0, sticky=W)
  5830.         Entry_Custom_pxpi.grid(    row=rn, column=1, sticky=E)
  5831.         Label_pxpi_units.grid(     row=rn, column=2, sticky=W)
  5832.        
  5833.         rn=rn+1
  5834.         Label_Width.grid(         row=rn, column=0, sticky=E)
  5835.         Entry_Custom_Width.grid(  row=rn, column=1, sticky=E)
  5836.         Label_Width_units.grid(   row=rn, column=2, sticky=W)
  5837.  
  5838.         rn=rn+1
  5839.         Label_Height.grid(        row=rn, column=0, sticky=E)
  5840.         Entry_Custom_Height.grid( row=rn, column=1, sticky=E)
  5841.         Label_Height_units.grid(  row=rn, column=2, sticky=W)
  5842.  
  5843.         rn=rn+1
  5844.         Bottom_row.grid(row=rn,columnspan=50)
  5845.  
  5846.         Radio_SVG_pxpi_96.configure  (variable=self.svg_pxpi)
  5847.         Radio_SVG_pxpi_90.configure  (variable=self.svg_pxpi)
  5848.         Radio_SVG_pxpi_72.configure  (variable=self.svg_pxpi)
  5849.         Radio_Res_Custom.configure  (variable=self.svg_pxpi)
  5850.         self.trace_id_svg_pxpi = self.svg_pxpi.trace_variable("w", SVG_pxpi_callback)
  5851.         ###########################################################################
  5852.    
  5853.     def apply(self):
  5854.         width  = float(self.svg_width.get())/self.scale
  5855.         height = float(self.svg_height.get())/self.scale
  5856.         pxpi    = float(self.other.get())
  5857.         viewbox = [self.minx_pixels, self.miny_pixels, width/25.4*pxpi, height/25.4*pxpi]
  5858.         self.result = pxpi,viewbox
  5859.         return
  5860.        
  5861. ################################################################################
  5862. #                          Startup Application                                 #
  5863. ################################################################################
  5864.    
  5865. root = Tk()
  5866. app = Application(root)
  5867. app.master.title(title_text)
  5868. app.master.iconname("K40")
  5869. app.master.minsize(800,560)
  5870. app.master.geometry("800x560")
  5871. try:
  5872.     try:
  5873.         import tkFont
  5874.         default_font = tkFont.nametofont("TkDefaultFont")
  5875.     except:
  5876.         import tkinter.font
  5877.         default_font = tkinter.font.nametofont("TkDefaultFont")
  5878.  
  5879.     default_font.configure(size=9)
  5880.     default_font.configure(family='arial')
  5881.     #print(default_font.cget("size"))
  5882.     #print(default_font.cget("family"))
  5883. except:
  5884.     debug_message("Font Set Failed.")
  5885.  
  5886. ################################## Set Icon  ########################################
  5887. Icon_Set=False
  5888.  
  5889. try:
  5890.     #debug_message("Icon set %s" %(sys.argv[0]))
  5891.     root.iconbitmap(default="emblem")
  5892.     #debug_message("Icon set worked %s" %(sys.argv[0]))
  5893.     Icon_Set=True
  5894. except:
  5895.     debug_message(traceback.format_exc())
  5896.     Icon_Set=False
  5897.        
  5898. if not Icon_Set:
  5899.     try:
  5900.         scorch_ico_B64=b'R0lGODlhEAAQAIYAAA\
  5901.        AAABAQEBYWFhcXFxsbGyUlJSYmJikpKSwsLC4uLi8vLzExMTMzMzc3Nzg4ODk5OTs7Oz4+PkJCQkRERE\
  5902.        VFRUtLS0xMTE5OTlNTU1dXV1xcXGBgYGVlZWhoaGtra3FxcXR0dHh4eICAgISEhI+Pj5mZmZ2dnaKioq\
  5903.        Ojo62tra6urrS0tLi4uLm5ub29vcLCwsbGxsjIyMzMzM/Pz9PT09XV1dbW1tjY2Nzc3OHh4eLi4uXl5e\
  5904.        fn5+jo6Ovr6+/v7/Hx8fLy8vT09PX19fn5+fv7+/z8/P7+/v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
  5905.        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
  5906.        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
  5907.        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEKAEkALAAAAAAQABAAQAj/AJMIFBhBQYAACRIkWbgwAA\
  5908.        4kEFEECACAxBAkGH8ESEKgBZIiAIQECBAjAA8kNwIkScKgQhAkRggAIJACCZIaJxgk2clgAY4OAAoEAO\
  5909.        ABCIIDSZIwkIHEBw0YFAAA6IGDCBIkLAhMyICka9cAKZCIRTLEBIMkaA0MSNGjSBEVIgpESEK3LgMCI1\
  5910.        aAWCFDA4EDSQInwaDACBEAImLwCAFARw4HFJJcgGADyZEAL3YQcMGBBpIjHx4EeIGkRoMFJgakWADABx\
  5911.        IkPwIgcIGkdm0AMJDo1g3jQBIBRZAINyKAwxEkyHEUSMIcwYYbEgwYmQGgyI8SD5Jo327hgIIAAQ5cBs\
  5912.        CQpHySgAA7'
  5913.         icon_im =PhotoImage(data=scorch_ico_B64, format='gif')
  5914.         root.call('wm', 'iconphoto', root._w, '-default', icon_im)
  5915.     except:
  5916.         pass
  5917. #####################################################################################
  5918.  
  5919.  
  5920. if LOAD_MSG != "":
  5921.     message_box("K40 Whisperer",LOAD_MSG)
  5922.  
  5923. opts, args = None, None
  5924. try:
  5925.     opts, args = getopt.getopt(sys.argv[1:], "hpd",["help", "pi", "debug"])
  5926. except:
  5927.     print('Unable interpret command line options')
  5928.     sys.exit()
  5929.  
  5930. for option, value in opts:
  5931.     if option in ('-h','--help'):
  5932.         print(' ')
  5933.         print('Usage: python k40_whisperer.py [-h -p]')
  5934.         print('-h    : print this help (also --help)')
  5935.         print('-p    : Small screen option (for small raspberry pi display) (also --pi)')
  5936.         sys.exit()
  5937.     elif option in ('-p','--pi'):
  5938.         print("pi mode")
  5939.         app.master.minsize(480,320)
  5940.         app.master.geometry("480x320")
  5941.     elif option in ('-d','--debug'):
  5942.         DEBUG=True
  5943.  
  5944. if DEBUG:
  5945.     import inspect
  5946. debug_message("Debuging is turned on.")
  5947.    
  5948. root.mainloop()
  5949.  
Advertisement
Comments
  • j0h
    j0h
    77 days
    Comment was deleted
  • j0h
    j0h
    77 days
    # text 0.47 KB | 0 0
    1. Ok for real, I didnt expect to hack this thing so fast. It will work, but it is not safe, its jank AF.
    2. to use: $python ./Mod.py -i -o/path/to/svg.svg -v
    3. ##Had to mod line 3842 to prevent an on initialization stop action.
    4. #The Mod: self.stop[0]=False it was true.
    5.  
    6.  
    7. -h for command line arg help.
    8. -v vector cuts.
    9. -i initializes.
    10. -o opens a file. Only svg files are configured right now.
    11.  
    12. Still need to write a terminate function for when all CLI arg functions are complete.
Add Comment
Please, Sign In to add comment
Advertisement