Advertisement
j0h

Untitled

j0h
May 23rd, 2019
394
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 163.54 KB | None | 0 0
  1. #!/usr/bin/python
  2. """
  3.    K40 Whisperer  Now with CLI!!!
  4.  
  5.    Copyright (C) <2018>  <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.19'
  21. title_text = "K40 Whisperer V"+version
  22. import matplotlib
  23. matplotlib.use('Agg')
  24. import sys
  25. from math import *
  26. from egv import egv
  27. from nano_library import K40_CLASS
  28. from dxf import DXF_CLASS
  29. from svg_reader import SVG_READER
  30. from svg_reader import SVG_TEXT_EXCEPTION
  31. from g_code_library import G_Code_Rip
  32. from interpolate import interpolate
  33.  
  34. import inkex
  35. import simplestyle
  36. import simpletransform
  37. import cubicsuperpath
  38. import cspsubdiv
  39. import traceback
  40.  
  41.  
  42. #DEBUG = True
  43. DEBUG = False
  44.  
  45. VERSION = sys.version_info[0]
  46. LOAD_MSG = ""
  47.  
  48. if VERSION == 3:
  49.     from tkinter import *
  50.     from tkinter.filedialog import *
  51.     import tkinter.messagebox
  52.     MAXINT = sys.maxsize
  53.    
  54. else:
  55.     from Tkinter import *
  56.     from tkFileDialog import *
  57.     import tkMessageBox
  58.     MAXINT = sys.maxint
  59.  
  60. if VERSION < 3 and sys.version_info[1] < 6:
  61.     def next(item):
  62.         return item.next()
  63.    
  64. try:
  65.     import psyco
  66.     psyco.full()
  67.     LOAD_MSG = LOAD_MSG+"\nPsyco Loaded\n"
  68. except:
  69.     pass
  70.  
  71. import math
  72. from time import time
  73. import os
  74. import re
  75. import binascii
  76. import getopt
  77. import operator
  78. import webbrowser
  79. from PIL import Image
  80. from PIL import ImageOps
  81. try:
  82.     Image.warnings.simplefilter('ignore', Image.DecompressionBombWarning)
  83. except:
  84.     pass
  85. try:
  86.     from PIL import ImageTk
  87.     from PIL import _imaging
  88. except:
  89.     pass #Don't worry everything will still work
  90.  
  91. QUIET = False
  92.  
  93. class ECoord():
  94.     def __init__(self):
  95.         self.reset()
  96.        
  97.     def reset(self):
  98.         self.image      = None
  99.         self.reset_path()
  100.  
  101.     def reset_path(self):
  102.         self.ecoords    = []
  103.         self.len        = 0
  104.         self.move       = 0
  105.         self.sorted     = False
  106.         self.bounds     = (0,0,0,0)
  107.         self.gcode_time = 0        
  108.  
  109.     def make_ecoords(self,coords,scale=1):
  110.         self.reset()
  111.         self.len  = 0
  112.         self.move = 0
  113.        
  114.         xmax, ymax = -1e10, -1e10
  115.         xmin, ymin =  1e10,  1e10
  116.         self.ecoords=[]
  117.         Acc=.001
  118.         oldx = oldy = -99990.0
  119.         first_stroke = True
  120.         loop=0
  121.         for line in coords:
  122.             XY = line
  123.             x1 = XY[0]*scale
  124.             y1 = XY[1]*scale
  125.             x2 = XY[2]*scale
  126.             y2 = XY[3]*scale
  127.             dxline= x2-x1
  128.             dyline= y2-y1
  129.             len_line=sqrt(dxline*dxline + dyline*dyline)
  130.            
  131.             dx = oldx - x1
  132.             dy = oldy - y1
  133.             dist   = sqrt(dx*dx + dy*dy)
  134.             # check and see if we need to move to a new discontinuous start point
  135.             if (dist > Acc) or first_stroke:
  136.                 loop = loop+1
  137.                 self.ecoords.append([x1,y1,loop])
  138.                 if not first_stroke:
  139.                     self.move = self.move + dist
  140.                 first_stroke = False
  141.                
  142.             self.len = self.len + len_line
  143.             self.ecoords.append([x2,y2,loop])
  144.             oldx, oldy = x2, y2
  145.             xmax=max(xmax,x1,x2)
  146.             ymax=max(ymax,y1,y2)
  147.             xmin=min(xmin,x1,x2)
  148.             ymin=min(ymin,y1,y2)
  149.         self.bounds = (xmin,xmax,ymin,ymax)
  150.  
  151.     def set_ecoords(self,ecoords,data_sorted=False):
  152.         self.ecoords = ecoords
  153.         self.computeEcoordsLen()
  154.         self.data_sorted=data_sorted
  155.  
  156.     def set_image(self,PIL_image):
  157.         self.image = PIL_image
  158.  
  159.     def computeEcoordsLen(self):
  160.         xmax, ymax = -1e10, -1e10
  161.         xmin, ymin =  1e10,  1e10
  162.        
  163.         if self.ecoords == [] :
  164.             return
  165.         on = 0
  166.         move = 0
  167.         time = 0
  168.         for i in range(2,len(self.ecoords)):
  169.             x1 = self.ecoords[i-1][0]
  170.             y1 = self.ecoords[i-1][1]
  171.             x2 = self.ecoords[i][0]
  172.             y2 = self.ecoords[i][1]
  173.             loop      = self.ecoords[i  ][2]
  174.             loop_last = self.ecoords[i-1][2]
  175.            
  176.             xmax=max(xmax,x1,x2)
  177.             ymax=max(ymax,y1,y2)
  178.             xmin=min(xmin,x1,x2)
  179.             ymin=min(ymin,y1,y2)
  180.            
  181.             dx = x2-x1
  182.             dy = y2-y1
  183.             dist = sqrt(dx*dx + dy*dy)
  184.            
  185.             if len(self.ecoords[i]) > 3:
  186.                 feed = self.ecoords[i][3]
  187.                 time = time + dist/feed*60
  188.                
  189.             if loop == loop_last:
  190.                 on   = on + dist
  191.             else:
  192.                 move = move + dist
  193.             #print "on= ",on," move= ",move
  194.         self.bounds = (xmin,xmax,ymin,ymax)
  195.         self.len = on
  196.         self.move = move
  197.         self.gcode_time = time
  198.    
  199.    
  200. ################################################################################
  201. class Application(Frame):
  202.     def __init__(self, master):
  203.         Frame.__init__(self, master)
  204.         self.w = 780
  205.         self.h = 490
  206.         frame = Frame(master, width= self.w, height=self.h)
  207.         self.master = master
  208.         self.x = -1
  209.         self.y = -1
  210.         self.createWidgets()
  211.  
  212.     def resetPath(self):
  213.         self.RengData  = ECoord()
  214.         self.VengData  = ECoord()
  215.         self.VcutData  = ECoord()
  216.         self.GcodeData = ECoord()
  217.         self.SCALE = 1
  218.         self.Design_bounds = (0,0,0,0)
  219.         self.UI_image = None
  220.         #if self.HomeUR.get():
  221.         self.move_head_window_temporary([0.0,0.0])
  222.         #else:
  223.         #    self.move_head_window_temporary([0.0,0.0])
  224.            
  225.         self.pos_offset=[0.0,0.0]
  226.        
  227.     def createWidgets(self):
  228.         self.initComplete = 0
  229.         self.stop=[]
  230.         self.stop.append(False)
  231.        
  232.         self.k40 = None
  233.        
  234.         self.master.bind("<Configure>", self.Master_Configure)
  235.         self.master.bind('<Enter>', self.bindConfigure)
  236.         self.master.bind('<F1>', self.KEY_F1)
  237.         self.master.bind('<F5>', self.KEY_F5)
  238.  
  239.         self.master.bind('<Control-Left>' , self.Move_Left)
  240.         self.master.bind('<Control-Right>', self.Move_Right)
  241.         self.master.bind('<Control-Up>'   , self.Move_Up)
  242.         self.master.bind('<Control-Down>' , self.Move_Down)
  243.  
  244.         self.include_Reng = BooleanVar()
  245.         self.include_Rpth = BooleanVar()
  246.         self.include_Veng = BooleanVar()
  247.         self.include_Vcut = BooleanVar()
  248.         self.include_Gcde = BooleanVar()
  249.         self.include_Time = BooleanVar()
  250.  
  251.         self.advanced = BooleanVar()
  252.        
  253.         self.halftone     = BooleanVar()
  254.         self.mirror       = BooleanVar()
  255.         self.rotate       = BooleanVar()
  256.         self.inputCSYS    = BooleanVar()
  257.         self.HomeUR       = BooleanVar()
  258.         self.engraveUP    = BooleanVar()
  259.         self.init_home    = BooleanVar()
  260.         self.pre_pr_crc   = BooleanVar()
  261.         self.inside_first = BooleanVar()
  262.  
  263.         self.ht_size    = StringVar()
  264.         self.Reng_feed  = StringVar()
  265.         self.Veng_feed  = StringVar()
  266.         self.Vcut_feed  = StringVar()
  267.  
  268.         self.Reng_passes = StringVar()
  269.         self.Veng_passes = StringVar()
  270.         self.Vcut_passes = StringVar()
  271.         self.Gcde_passes = StringVar()
  272.        
  273.        
  274.         self.board_name = StringVar()
  275.         self.units      = StringVar()
  276.         self.jog_step   = StringVar()
  277.         self.rast_step  = StringVar()
  278.         self.funits     = StringVar()
  279.        
  280.  
  281.         self.bezier_M1     = StringVar()
  282.         self.bezier_M2     = StringVar()
  283.         self.bezier_weight = StringVar()
  284.  
  285.         self.LaserXsize = StringVar()
  286.         self.LaserYsize = StringVar()
  287.  
  288.         self.LaserXscale = StringVar()
  289.         self.LaserYscale = StringVar()
  290.  
  291.         self.gotoX = StringVar()
  292.         self.gotoY = StringVar()
  293.  
  294.         self.inkscape_path = StringVar()
  295.         self.t_timeout  = StringVar()
  296.         self.n_timeouts  = StringVar()
  297.        
  298.         self.Reng_time = StringVar()
  299.         self.Veng_time = StringVar()
  300.         self.Vcut_time = StringVar()
  301.         self.Gcde_time = StringVar()
  302.        
  303.         ###########################################################################
  304.         #                         INITILIZE VARIABLES                             #
  305.         #    if you want to change a default setting this is the place to do it   #
  306.         ###########################################################################
  307.         self.include_Reng.set(1)
  308.         self.include_Rpth.set(0)
  309.         self.include_Veng.set(1)
  310.         self.include_Vcut.set(1)
  311.         self.include_Gcde.set(1)
  312.         self.include_Time.set(0)
  313.         self.advanced.set(0)
  314.        
  315.         self.halftone.set(0)
  316.         self.mirror.set(0)
  317.         self.rotate.set(0)
  318.         self.inputCSYS.set(0)
  319.         self.HomeUR.set(0)
  320.         self.engraveUP.set(0)
  321.         self.init_home.set(1)
  322.         self.pre_pr_crc.set(1)
  323.         self.inside_first.set(1)
  324.        
  325.         self.ht_size.set(500)
  326.  
  327.         self.Reng_feed.set("100")
  328.         self.Veng_feed.set("20")
  329.         self.Vcut_feed.set("10")
  330.         self.Reng_passes.set("1")
  331.         self.Veng_passes.set("1")
  332.         self.Vcut_passes.set("1")
  333.         self.Gcde_passes.set("1")
  334.        
  335.        
  336.         self.jog_step.set("10.0")
  337.         self.rast_step.set("0.002")
  338.        
  339.         self.bezier_weight.set("3.5")
  340.         self.bezier_M1.set("2.5")
  341.         self.bezier_M2.set("0.50")
  342.  
  343.         self.bezier_weight_default = float(self.bezier_weight.get())
  344.         self.bezier_M1_default     = float(self.bezier_M1.get())
  345.         self.bezier_M2_default     = float(self.bezier_M2.get())
  346.        
  347.                                        
  348.         self.board_name.set("LASER-M2") # Options are
  349.                                         #    "LASER-M2",
  350.                                         #    "LASER-M1",
  351.                                         #    "LASER-M",
  352.                                         #    "LASER-B2",
  353.                                         #    "LASER-B1",
  354.                                         #    "LASER-B",
  355.                                         #    "LASER-A"
  356.  
  357.  
  358.         self.units.set("mm")            # Options are "in" and "mm"
  359.         self.t_timeout.set("2000")  
  360.         self.n_timeouts.set("30")
  361.  
  362.         self.HOME_DIR    = os.path.expanduser("~")
  363.        
  364.         if not os.path.isdir(self.HOME_DIR):
  365.             self.HOME_DIR = ""
  366.  
  367.         self.DESIGN_FILE = (self.HOME_DIR+"/None")
  368.        
  369.         self.aspect_ratio =  0
  370.         self.segID   = []
  371.        
  372.         self.LaserXsize.set("325")
  373.         self.LaserYsize.set("220")
  374.        
  375.         self.LaserXscale.set("1.000")
  376.         self.LaserYscale.set("1.000")
  377.  
  378.         self.gotoX.set("0.0")
  379.         self.gotoY.set("0.0")
  380.        
  381.         self.laserX    = 0.0
  382.         self.laserY    = 0.0
  383.         self.PlotScale = 1.0
  384.  
  385.         # PAN and ZOOM STUFF
  386.         self.panx = 0
  387.         self.panx = 0
  388.         self.lastx = 0
  389.         self.lasty = 0
  390.         self.move_start_x = 0
  391.         self.move_start_y = 0
  392.  
  393.        
  394.         self.RengData  = ECoord()
  395.         self.VengData  = ECoord()
  396.         self.VcutData  = ECoord()
  397.         self.GcodeData = ECoord()
  398.         self.SCALE = 1
  399.         self.Design_bounds = (0,0,0,0)
  400.         self.UI_image = None
  401.         self.pos_offset=[0.0,0.0]
  402.  
  403.        
  404.         # Derived variables
  405.         if self.units.get() == 'in':
  406.             self.funits.set('in/min')
  407.             self.units_scale = 1.0
  408.         else:
  409.             self.units.set('mm')
  410.             self.funits.set('mm/s')
  411.             self.units_scale = 25.4
  412.        
  413.         self.statusMessage = StringVar()
  414.         self.statusMessage.set("Welcome to K40 Whisperer")
  415.        
  416.        
  417.         self.Reng_time.set("0")
  418.         self.Veng_time.set("0")
  419.         self.Vcut_time.set("0")
  420.         self.Gcde_time.set("0")
  421.        
  422.         ##########################################################################
  423.         ###                     END INITILIZING VARIABLES                      ###
  424.         ##########################################################################
  425.  
  426.         # make a Status Bar
  427.         self.statusbar = Label(self.master, textvariable=self.statusMessage, \
  428.                                    bd=1, relief=SUNKEN , height=1)
  429.         self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM)
  430.        
  431.  
  432.         # Canvas
  433.         lbframe = Frame( self.master )
  434.         self.PreviewCanvas_frame = lbframe
  435.         self.PreviewCanvas = Canvas(lbframe, width=self.w-(220+20), height=self.h-200, background="grey")
  436.         self.PreviewCanvas.pack(side=LEFT, fill=BOTH, expand=1)
  437.         self.PreviewCanvas_frame.place(x=230, y=10)
  438.  
  439.         self.PreviewCanvas.tag_bind('LaserTag',"<1>"              , self.mousePanStart)
  440.         self.PreviewCanvas.tag_bind('LaserTag',"<B1-Motion>"      , self.mousePan)
  441.         self.PreviewCanvas.tag_bind('LaserTag',"<ButtonRelease-1>", self.mousePanStop)
  442.  
  443.         # Left Column #
  444.         self.separator1 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  445.         self.separator2 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  446.         self.separator3 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  447.         self.separator4 = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  448.        
  449.         self.Label_Reng_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
  450.         self.Entry_Reng_feed   = Entry(self.master,width="15")
  451.         self.Entry_Reng_feed.configure(textvariable=self.Reng_feed,justify='center',fg="black")
  452.         self.Reng_feed.trace_variable("w", self.Entry_Reng_feed_Callback)
  453.         self.NormalColor =  self.Entry_Reng_feed.cget('bg')
  454.  
  455.         self.Label_Veng_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
  456.         self.Entry_Veng_feed   = Entry(self.master,width="15")
  457.         self.Entry_Veng_feed.configure(textvariable=self.Veng_feed,justify='center',fg="blue")
  458.         self.Veng_feed.trace_variable("w", self.Entry_Veng_feed_Callback)
  459.         self.NormalColor =  self.Entry_Veng_feed.cget('bg')
  460.  
  461.         self.Label_Vcut_feed_u = Label(self.master,textvariable=self.funits, anchor=W)
  462.         self.Entry_Vcut_feed   = Entry(self.master,width="15")
  463.         self.Entry_Vcut_feed.configure(textvariable=self.Vcut_feed,justify='center',fg="red")
  464.         self.Vcut_feed.trace_variable("w", self.Entry_Vcut_feed_Callback)
  465.         self.NormalColor =  self.Entry_Vcut_feed.cget('bg')
  466.  
  467.         # Buttons
  468.         self.Reng_Button  = Button(self.master,text="Raster Engrave", command=self.Raster_Eng)
  469.         self.Veng_Button  = Button(self.master,text="Vector Engrave", command=self.Vector_Eng)
  470.         self.Vcut_Button  = Button(self.master,text="Vector Cut"    , command=self.Vector_Cut)
  471.         self.Grun_Button  = Button(self.master,text="Run G-Code"    , command=self.Gcode_Cut)
  472.        
  473.         self.Label_Position_Control = Label(self.master,text="Position Controls:", anchor=W)
  474.        
  475.         self.Initialize_Button = Button(self.master,text="Initialize Laser Cutter", command=self.Initialize_Laser)
  476.  
  477.         self.Open_Button       = Button(self.master,text="Open\nDesign File",   command=self.menu_File_Open_Design)
  478.         self.Reload_Button     = Button(self.master,text="Reload\nDesign File", command=self.menu_Reload_Design)
  479.        
  480.         self.Home_Button       = Button(self.master,text="Home",             command=self.Home)
  481.         self.UnLock_Button     = Button(self.master,text="Unlock Rail",     command=self.Unlock)
  482.         self.Stop_Button       = Button(self.master,text="Stop",             command=self.Stop)
  483.  
  484.         try:
  485.             self.left_image  = self.Imaging_Free(Image.open("left.png"),bg=None)
  486.             self.right_image = self.Imaging_Free(Image.open("right.png"),bg=None)
  487.             self.up_image    = self.Imaging_Free(Image.open("up.png"),bg=None)
  488.             self.down_image  = self.Imaging_Free(Image.open("down.png"),bg=None)
  489.            
  490.             self.Right_Button   = Button(self.master,image=self.right_image, command=self.Move_Right)
  491.             self.Left_Button    = Button(self.master,image=self.left_image,  command=self.Move_Left)
  492.             self.Up_Button      = Button(self.master,image=self.up_image,    command=self.Move_Up)
  493.             self.Down_Button    = Button(self.master,image=self.down_image,  command=self.Move_Down)
  494.  
  495.             self.UL_image  = self.Imaging_Free(Image.open("UL.png"),bg=None)
  496.             self.UR_image  = self.Imaging_Free(Image.open("UR.png"),bg=None)
  497.             self.LR_image  = self.Imaging_Free(Image.open("LR.png"),bg=None)
  498.             self.LL_image  = self.Imaging_Free(Image.open("LL.png"),bg=None)
  499.             self.CC_image  = self.Imaging_Free(Image.open("CC.png"),bg=None)
  500.            
  501.             self.UL_Button = Button(self.master,image=self.UL_image, command=self.Move_UL)
  502.             self.UR_Button = Button(self.master,image=self.UR_image, command=self.Move_UR)
  503.             self.LR_Button = Button(self.master,image=self.LR_image, command=self.Move_LR)
  504.             self.LL_Button = Button(self.master,image=self.LL_image, command=self.Move_LL)
  505.             self.CC_Button = Button(self.master,image=self.CC_image, command=self.Move_CC)
  506.            
  507.         except:
  508.             self.Right_Button   = Button(self.master,text=">",          command=self.Move_Right)
  509.             self.Left_Button    = Button(self.master,text="<",          command=self.Move_Left)
  510.             self.Up_Button      = Button(self.master,text="^",          command=self.Move_Up)
  511.             self.Down_Button    = Button(self.master,text="v",          command=self.Move_Down)
  512.  
  513.             self.UL_Button = Button(self.master,text=" ", command=self.Move_UL)
  514.             self.UR_Button = Button(self.master,text=" ", command=self.Move_UR)
  515.             self.LR_Button = Button(self.master,text=" ", command=self.Move_LR)
  516.             self.LL_Button = Button(self.master,text=" ", command=self.Move_LL)
  517.             self.CC_Button = Button(self.master,text=" ", command=self.Move_CC)
  518.  
  519.         self.Label_Step   = Label(self.master,text="Jog Step", anchor=CENTER )
  520.         self.Label_Step_u = Label(self.master,textvariable=self.units, anchor=W)
  521.         self.Entry_Step   = Entry(self.master,width="15")
  522.         self.Entry_Step.configure(textvariable=self.jog_step, justify='center')
  523.         self.jog_step.trace_variable("w", self.Entry_Step_Callback)
  524.  
  525.         ###########################################################################
  526.         self.GoTo_Button    = Button(self.master,text="Move To", command=self.GoTo)
  527.        
  528.         self.Entry_GoToX   = Entry(self.master,width="15",justify='center')
  529.         self.Entry_GoToX.configure(textvariable=self.gotoX)
  530.         self.gotoX.trace_variable("w", self.Entry_GoToX_Callback)
  531.         self.Entry_GoToY   = Entry(self.master,width="15",justify='center')
  532.         self.Entry_GoToY.configure(textvariable=self.gotoY)
  533.         self.gotoY.trace_variable("w", self.Entry_GoToY_Callback)
  534.        
  535.         self.Label_GoToX   = Label(self.master,text="X", anchor=CENTER )
  536.         self.Label_GoToY   = Label(self.master,text="Y", anchor=CENTER )
  537.         ###########################################################################
  538.         # End Left Column #
  539.  
  540.         # Advanced Column     #
  541.         self.separator_vert = Frame(self.master, height=2, bd=1, relief=SUNKEN)
  542.         self.Label_Advanced_column = Label(self.master,text="Advanced Settings",anchor=CENTER)
  543.         self.separator_adv = Frame(self.master, height=2, bd=1, relief=SUNKEN)      
  544.  
  545.         self.Label_Halftone_adv = Label(self.master,text="Halftone (Dither)")
  546.         self.Checkbutton_Halftone_adv = Checkbutton(self.master,text=" ", anchor=W)
  547.         self.Checkbutton_Halftone_adv.configure(variable=self.halftone)
  548.         self.halftone.trace_variable("w", self.menu_View_Refresh_Callback)
  549.  
  550.         self.Label_Mirror_adv = Label(self.master,text="Mirror Design")
  551.         self.Checkbutton_Mirror_adv = Checkbutton(self.master,text=" ", anchor=W)
  552.         self.Checkbutton_Mirror_adv.configure(variable=self.mirror)
  553.         self.mirror.trace_variable("w", self.menu_View_Mirror_Refresh_Callback)
  554.  
  555.         self.Label_Rotate_adv = Label(self.master,text="Rotate Design")
  556.         self.Checkbutton_Rotate_adv = Checkbutton(self.master,text=" ", anchor=W)
  557.         self.Checkbutton_Rotate_adv.configure(variable=self.rotate)
  558.         self.rotate.trace_variable("w", self.menu_View_Mirror_Refresh_Callback)
  559.    
  560.         self.Label_inputCSYS_adv = Label(self.master,text="Use Input CSYS")
  561.         self.Checkbutton_inputCSYS_adv = Checkbutton(self.master,text=" ", anchor=W)
  562.         self.Checkbutton_inputCSYS_adv.configure(variable=self.inputCSYS)
  563.         self.inputCSYS.trace_variable("w", self.menu_View_inputCSYS_Refresh_Callback)
  564.  
  565.         self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First")
  566.         self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ", anchor=W)
  567.         self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first)
  568.         self.inside_first.trace_variable("w", self.menu_Inside_First_Callback)
  569.  
  570.         self.Label_Reng_passes = Label(self.master,text="Raster Eng. Passes")
  571.         self.Entry_Reng_passes   = Entry(self.master,width="15")
  572.         self.Entry_Reng_passes.configure(textvariable=self.Reng_passes,justify='center',fg="black")
  573.         self.Reng_passes.trace_variable("w", self.Entry_Reng_passes_Callback)
  574.         self.NormalColor =  self.Entry_Reng_passes.cget('bg')
  575.  
  576.         self.Label_Veng_passes = Label(self.master,text="Vector Eng. Passes")
  577.         self.Entry_Veng_passes   = Entry(self.master,width="15")
  578.         self.Entry_Veng_passes.configure(textvariable=self.Veng_passes,justify='center',fg="blue")
  579.         self.Veng_passes.trace_variable("w", self.Entry_Veng_passes_Callback)
  580.         self.NormalColor =  self.Entry_Veng_passes.cget('bg')
  581.  
  582.         self.Label_Vcut_passes = Label(self.master,text="Vector Cut Passes")
  583.         self.Entry_Vcut_passes   = Entry(self.master,width="15")
  584.         self.Entry_Vcut_passes.configure(textvariable=self.Vcut_passes,justify='center',fg="red")
  585.         self.Vcut_passes.trace_variable("w", self.Entry_Vcut_passes_Callback)
  586.         self.NormalColor =  self.Entry_Vcut_passes.cget('bg')
  587.  
  588.         self.Label_Gcde_passes = Label(self.master,text="G-Code Passes")
  589.         self.Entry_Gcde_passes   = Entry(self.master,width="15")
  590.         self.Entry_Gcde_passes.configure(textvariable=self.Gcde_passes,justify='center',fg="black")
  591.         self.Gcde_passes.trace_variable("w", self.Entry_Gcde_passes_Callback)
  592.         self.NormalColor =  self.Entry_Gcde_passes.cget('bg')
  593.  
  594.        
  595.         self.Hide_Adv_Button = Button(self.master,text="Hide Advanced", command=self.Hide_Advanced)
  596.        
  597.         # End Right Column #
  598.  
  599.         #GEN Setting Window Entry initializations
  600.         self.Entry_Sspeed    = Entry()
  601.         self.Entry_BoxGap    = Entry()
  602.         self.Entry_ContAngle = Entry()
  603.  
  604.         # Make Menu Bar
  605.         self.menuBar = Menu(self.master, relief = "raised", bd=2)
  606.  
  607.         top_File = Menu(self.menuBar, tearoff=0)
  608.         top_File.add("command", label = "Save Settings File", command = self.menu_File_Save)
  609.         top_File.add("command", label = "Read Settings File", command = self.menu_File_Open_Settings_File)
  610.  
  611.         top_File.add_separator()
  612.         top_File.add("command", label = "Open Design (SVG/DXF/G-Code)"  , command = self.menu_File_Open_Design)
  613.         top_File.add("command", label = "Reload Design"          , command = self.menu_Reload_Design)
  614.  
  615.         if DEBUG:
  616.             top_File.add_separator()
  617.             top_File.add("command", label = "Open EGV File"     , command = self.menu_File_Open_EGV)
  618.  
  619.    
  620.         top_File.add_separator()
  621.         top_File.add("command", label = "Exit"              , command = self.menu_File_Quit)
  622.        
  623.         self.menuBar.add("cascade", label="File", menu=top_File)
  624.  
  625.         #top_Edit = Menu(self.menuBar, tearoff=0)
  626.         #self.menuBar.add("cascade", label="Edit", menu=top_Edit)
  627.  
  628.         top_View = Menu(self.menuBar, tearoff=0)
  629.         top_View.add("command", label = "Refresh   <F5>", command = self.menu_View_Refresh)
  630.         top_View.add_separator()
  631.         top_View.add_checkbutton(label = "Show Raster Image"  ,  variable=self.include_Reng ,command= self.menu_View_Refresh)
  632.         if DEBUG:
  633.             top_View.add_checkbutton(label = "Show Raster Paths"  ,  variable=self.include_Rpth ,command= self.menu_View_Refresh)
  634.         top_View.add_checkbutton(label = "Show Vector Engrave",  variable=self.include_Veng ,command= self.menu_View_Refresh)
  635.         top_View.add_checkbutton(label = "Show Vector Cut"    ,  variable=self.include_Vcut ,command= self.menu_View_Refresh)
  636.         top_View.add_checkbutton(label = "Show G-Code Paths"  ,  variable=self.include_Gcde ,command= self.menu_View_Refresh)
  637.         top_View.add_checkbutton(label = "Show Time Estimates",  variable=self.include_Time ,command= self.menu_View_Refresh)
  638.  
  639.         #top_View.add_separator()
  640.         #top_View.add("command", label = "computeAccurateReng",command= self.computeAccurateReng)
  641.         #top_View.add("command", label = "computeAccurateVeng",command= self.computeAccurateVeng)
  642.         #top_View.add("command", label = "computeAccurateVcut",command= self.computeAccurateVcut)
  643.  
  644.         self.menuBar.add("cascade", label="View", menu=top_View)
  645.  
  646.  
  647.         top_USB = Menu(self.menuBar, tearoff=0)
  648.         top_USB.add("command", label = "Reset USB", command = self.Reset)
  649.         top_USB.add("command", label = "Release USB", command = self.Release_USB)
  650.         top_USB.add("command", label = "Initialize Laser", command = self.Initialize_Laser)
  651.         self.menuBar.add("cascade", label="USB", menu=top_USB)
  652.        
  653.  
  654.         top_Settings = Menu(self.menuBar, tearoff=0)
  655.         top_Settings.add("command", label = "General Settings", command = self.GEN_Settings_Window)
  656.         top_Settings.add("command", label = "Raster Settings",  command = self.RASTER_Settings_Window)
  657.         top_Settings.add_separator()
  658.         top_Settings.add_checkbutton(label = "Advanced Settings", variable=self.advanced ,command= self.menu_View_Refresh)
  659.        
  660.         self.menuBar.add("cascade", label="Settings", menu=top_Settings)
  661.        
  662.         top_Help = Menu(self.menuBar, tearoff=0)
  663.         top_Help.add("command", label = "About (e-mail)", command = self.menu_Help_About)
  664.         top_Help.add("command", label = "Web Page", command = self.menu_Help_Web)
  665.         self.menuBar.add("cascade", label="Help", menu=top_Help)
  666.  
  667.         self.master.config(menu=self.menuBar)
  668.  
  669.         ##########################################################################
  670.         #                  Config File and command line options                  #
  671.         ##########################################################################
  672.         config_file = "k40_whisperer.txt"
  673.         home_config1 = self.HOME_DIR + "/" + config_file
  674.         if ( os.path.isfile(config_file) ):
  675.             self.Open_Settings_File(config_file)
  676.         elif ( os.path.isfile(home_config1) ):
  677.             self.Open_Settings_File(home_config1)
  678.         arguments = len(sys.argv) - 1
  679.         if arguments >=1:
  680.         # read commandline arguments, first
  681.             fullCmdArguments = sys.argv
  682.  
  683.         # - further arguments
  684.             argumentList = fullCmdArguments[1:]
  685.         #opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
  686.             unixOptions = "cghHio:rsnvVux:y:"  
  687.             gnuOptions = ["help","go","stop","home","init","open","cut","raster", "vector", "verbose","unlock"]  
  688.  
  689.             try:  
  690.                 arguments, values = getopt.getopt(argumentList, unixOptions, gnuOptions)
  691.             except getopt.error as err:  
  692.             # output error, and return with an error code
  693.                 print (str(err))
  694.                 sys.exit(2)
  695.  
  696.             # evaluate given options
  697.             for currentArgument, currentValue in arguments:  
  698.                 if currentArgument in ("-i", "--init"):
  699.                     print ("initializing the laser")
  700.                     self.Initialize_Laser()
  701.                     #sage()
  702.                     #command=self.Initialize_Laser
  703.                 elif currentArgument in ("-H", "--home"):
  704.                     print ("move to the home position")
  705.                     self.Home()
  706.                 elif currentArgument in ("-h", "--help"):
  707.                     print ("CLI arguments are as follows")
  708.                     print ("-g --go     Starts the job with whatever other arguments")
  709.                     print ("-s --stop   Stops the job, doesnt go home, or un initialize")
  710.                     print ("-H --home   Sends the cutting head to the home [0,0] position")
  711.                     print ("-i --init   Initializes the laser, or prints errors if it fails")
  712.                     print ("-o --open   Requires an SVG file to open")
  713.                     print ("-h --help   Prints this dialog")
  714.                     print ("-c --cut    Tell the laser to cut")
  715.                     print ("-r --raster Raster Engrave")
  716.                     print ("-v --vector Vector Engrave")
  717.                     print ("-V          Verbose mode lo U wish.. I guess I could set debug mode")
  718.                     print ("-u --unlock Unlock the print head")
  719.                     print ("-x <Number> move to X-Cordinate ")
  720.                     print ("-y <Number> move to Y-Cordinate ")
  721.                     print (" ")
  722.                     print (" ")
  723.                     print ("Example Useage: $python k40_whisperer.py -i -H -o c.svg -r ")
  724.                     exit()
  725.                 elif currentArgument in ("-o", "--open"):
  726.                     print (("opening an svg (%s)") % (currentValue))
  727.                     self.Open_SVG(currentValue)
  728.                 elif currentArgument in ("-g", "--go"):
  729.                     print ("Start cutting or moving the head")
  730.                     #This option doesn't translate into a direct action like the other functions do.
  731.                 elif currentArgument in ("-s", "--stop"):
  732.                     print ("Stop Cutting::dont check or make a pop up, just stop")
  733.                     self.CLI_Stop()
  734.                     #self.Stop()
  735.                 elif currentArgument in ("-u", "--unlock"):
  736.                     print ("unlocked the print head")
  737.                     self.Unlock()
  738.                 elif currentArgument in ("-c", "cut"):
  739.                     print ("cuts the open svg file")
  740.                     self.Vector_Cut()
  741.                 elif currentArgument in ("-r", "--raster"):
  742.                     print ("raster Engraves the opened file")
  743.                     self.Raster_Eng()
  744.                 elif currentArgument in ("-v", "--vector"):
  745.                     print ("Vector Engraves the opend file")
  746.                     self.Vector_Eng()
  747.                 elif currentArgument in ("-V"):
  748.                     print ("Verbose mode lol u wish, well, there is debug mode")
  749.                     print ("Version 0.19 K40_whisperer source")
  750.                     print ("Version 0.0  K40 CLI source")
  751.                 elif currentArgument in ("x"):
  752.                     print ("Move to X Coordinate " % (currentValue))
  753.                     self.gotoX.set(currentValue)
  754.                     self.GoTo()
  755.                 elif currentArgument in ("y"):
  756.                     print("Move to Y Coordnate %s" % (currentValue))
  757.                     self.gotoY.set(currentValue)
  758.                     self.GoTo()
  759.  
  760.                 else:
  761.                     print ("FOILED! put in some args if you want CLI mode")
  762.                    
  763.  
  764. ####Original DEV-OPS be liek: close if you have CLI arguments.            
  765. #
  766. #        opts, args = None, None
  767. #        try:
  768. #            opts, args = getopt.getopt(sys.argv[1:], "ho:",["help", "other_option"])
  769. #            print args[1:]
  770. #        except:
  771. #            debug_message('Unable to interpret command line options')
  772. #            sys.exit()
  773. ##        for option, value in opts:
  774. ##            if option in ('-h','--help'):
  775. ##                fmessage(' ')
  776. ##                fmessage('Usage: python .py [-g file]')
  777. ##                fmessage('-o    : unknown other option (also --other_option)')
  778. ##                fmessage('-h    : print this help (also --help)\n')
  779. ##                sys.exit()
  780. ##            if option in ('-o','--other_option'):
  781. ##                pass
  782.  
  783.         ##########################################################################
  784.  
  785. ################################################################################
  786.     def entry_set(self, val2, calc_flag=0, new=0):
  787.         if calc_flag == 0 and new==0:
  788.             try:
  789.                 self.statusbar.configure( bg = 'yellow' )
  790.                 val2.configure( bg = 'yellow' )
  791.                 self.statusMessage.set(" Recalculation required.")
  792.             except:
  793.                 pass
  794.         elif calc_flag == 3:
  795.             try:
  796.                 val2.configure( bg = 'red' )
  797.                 self.statusbar.configure( bg = 'red' )
  798.                 self.statusMessage.set(" Value should be a number. ")
  799.             except:
  800.                 pass
  801.         elif calc_flag == 2:
  802.             try:
  803.                 self.statusbar.configure( bg = 'red' )
  804.                 val2.configure( bg = 'red' )
  805.             except:
  806.                 pass
  807.         elif (calc_flag == 0 or calc_flag == 1) and new==1 :
  808.             try:
  809.                 self.statusbar.configure( bg = 'white' )
  810.                 self.statusMessage.set(" ")
  811.                 val2.configure( bg = 'white' )
  812.             except:
  813.                 pass
  814.         elif (calc_flag == 1) and new==0 :
  815.             try:
  816.                 self.statusbar.configure( bg = 'white' )
  817.                 self.statusMessage.set(" ")
  818.                 val2.configure( bg = 'white' )
  819.             except:
  820.                 pass
  821.  
  822.         elif (calc_flag == 0 or calc_flag == 1) and new==2:
  823.             return 0
  824.         return 1
  825.  
  826. ################################################################################
  827.     def Write_Config_File(self, event):
  828.         config_data = self.WriteConfig()
  829.         config_file = "k40_whisperer.txt"
  830.         configname_full = self.HOME_DIR + "/" + config_file
  831.  
  832.         win_id=self.grab_current()
  833.         if ( os.path.isfile(configname_full) ):
  834.             if not message_ask_ok_cancel("Replace", "Replace Exiting Configuration File?\n"+configname_full):
  835.                 try:
  836.                     win_id.withdraw()
  837.                     win_id.deiconify()
  838.                 except:
  839.                     pass
  840.                 return
  841.         try:
  842.             fout = open(configname_full,'w')
  843.         except:
  844.             self.statusMessage.set("Unable to open file for writing: %s" %(configname_full))
  845.             self.statusbar.configure( bg = 'red' )
  846.             return
  847.         for line in config_data:
  848.             try:
  849.                 fout.write(line+'\n')
  850.             except:
  851.                 fout.write('(skipping line)\n')
  852.         fout.close
  853.         self.statusMessage.set("Configuration File Saved: %s" %(configname_full))
  854.         self.statusbar.configure( bg = 'white' )
  855.         try:
  856.             win_id.withdraw()
  857.             win_id.deiconify()
  858.         except:
  859.             pass
  860.  
  861.     ################################################################################
  862.     def WriteConfig(self):
  863.         global Zero
  864.         header = []
  865.         header.append('( K40 Whisperer Settings: '+version+' )')
  866.         header.append('( by Scorch - 2017 )')
  867.         header.append("(=========================================================)")
  868.         # BOOL
  869.         header.append('(k40_whisperer_set include_Reng  %s )'  %( int(self.include_Reng.get())  ))
  870.         header.append('(k40_whisperer_set include_Veng  %s )'  %( int(self.include_Veng.get())  ))
  871.         header.append('(k40_whisperer_set include_Vcut  %s )'  %( int(self.include_Vcut.get())  ))
  872.         header.append('(k40_whisperer_set include_Gcde  %s )'  %( int(self.include_Gcde.get())  ))
  873.         header.append('(k40_whisperer_set include_Time  %s )'  %( int(self.include_Time.get())  ))
  874.        
  875.         header.append('(k40_whisperer_set halftone      %s )'  %( int(self.halftone.get())      ))
  876.         header.append('(k40_whisperer_set HomeUR        %s )'  %( int(self.HomeUR.get())        ))
  877.         header.append('(k40_whisperer_set inputCSYS     %s )'  %( int(self.inputCSYS.get())     ))
  878.         header.append('(k40_whisperer_set advanced      %s )'  %( int(self.advanced.get())      ))
  879.         header.append('(k40_whisperer_set mirror        %s )'  %( int(self.mirror.get())        ))
  880.         header.append('(k40_whisperer_set rotate        %s )'  %( int(self.rotate.get())        ))
  881.        
  882.         header.append('(k40_whisperer_set engraveUP     %s )'  %( int(self.engraveUP.get())     ))
  883.         header.append('(k40_whisperer_set init_home     %s )'  %( int(self.init_home.get())     ))
  884.         header.append('(k40_whisperer_set pre_pr_crc    %s )'  %( int(self.pre_pr_crc.get())    ))
  885.         header.append('(k40_whisperer_set inside_first  %s )'  %( int(self.inside_first.get())  ))
  886.  
  887.         # STRING.get()
  888.         header.append('(k40_whisperer_set board_name    %s )'  %( self.board_name.get()     ))
  889.         header.append('(k40_whisperer_set units         %s )'  %( self.units.get()          ))
  890.         header.append('(k40_whisperer_set Reng_feed     %s )'  %( self.Reng_feed.get()      ))
  891.         header.append('(k40_whisperer_set Veng_feed     %s )'  %( self.Veng_feed.get()      ))
  892.         header.append('(k40_whisperer_set Vcut_feed     %s )'  %( self.Vcut_feed.get()      ))
  893.         header.append('(k40_whisperer_set jog_step      %s )'  %( self.jog_step.get()       ))
  894.  
  895.         header.append('(k40_whisperer_set Reng_passes   %s )'  %( self.Reng_passes.get()    ))
  896.         header.append('(k40_whisperer_set Veng_passes   %s )'  %( self.Veng_passes.get()    ))
  897.         header.append('(k40_whisperer_set Vcut_passes   %s )'  %( self.Vcut_passes.get()    ))
  898.         header.append('(k40_whisperer_set Gcde_passes   %s )'  %( self.Gcde_passes.get()    ))
  899.  
  900.         header.append('(k40_whisperer_set rast_step     %s )'  %( self.rast_step.get()      ))
  901.         header.append('(k40_whisperer_set ht_size       %s )'  %( self.ht_size.get()        ))
  902.        
  903.         header.append('(k40_whisperer_set LaserXsize    %s )'  %( self.LaserXsize.get()     ))
  904.         header.append('(k40_whisperer_set LaserYsize    %s )'  %( self.LaserYsize.get()     ))
  905.         header.append('(k40_whisperer_set LaserXscale   %s )'  %( self.LaserXscale.get()    ))
  906.         header.append('(k40_whisperer_set LaserYscale   %s )'  %( self.LaserYscale.get()    ))
  907.         header.append('(k40_whisperer_set gotoX         %s )'  %( self.gotoX.get()          ))
  908.         header.append('(k40_whisperer_set gotoY         %s )'  %( self.gotoY.get()          ))
  909.  
  910.         header.append('(k40_whisperer_set bezier_M1     %s )'  %( self.bezier_M1.get()      ))
  911.         header.append('(k40_whisperer_set bezier_M2     %s )'  %( self.bezier_M2.get()      ))
  912.        
  913.         header.append('(k40_whisperer_set bezier_weight %s )'  %( self.bezier_weight.get()  ))
  914.  
  915.  
  916.  
  917.        
  918.         header.append('(k40_whisperer_set t_timeout     %s )'  %( self.t_timeout.get()      ))
  919.         header.append('(k40_whisperer_set n_timeouts    %s )'  %( self.n_timeouts.get()     ))
  920.        
  921.         header.append('(k40_whisperer_set designfile    \042%s\042 )' %( self.DESIGN_FILE   ))
  922.         header.append('(k40_whisperer_set inkscape_path \042%s\042 )' %( self.inkscape_path.get() ))
  923.  
  924.  
  925.         self.jog_step
  926.         header.append("(=========================================================)")
  927.  
  928.         return header
  929.         ######################################################
  930.  
  931.     def Quit_Click(self, event):
  932.         self.statusMessage.set("Exiting!")
  933.         root.destroy()
  934.  
  935.     def mousePanStart(self,event):
  936.         self.panx = event.x
  937.         self.pany = event.y
  938.         self.move_start_x = event.x
  939.         self.move_start_y = event.y
  940.        
  941.     def mousePan(self,event):
  942.         all = self.PreviewCanvas.find_all()
  943.         dx = event.x-self.panx
  944.         dy = event.y-self.pany
  945.  
  946.         self.PreviewCanvas.move('LaserTag', dx, dy)
  947.         self.lastx = self.lastx + dx
  948.         self.lasty = self.lasty + dy
  949.         self.panx = event.x
  950.         self.pany = event.y
  951.        
  952.     def mousePanStop(self,event):
  953.         Xold = round(self.laserX,3)
  954.         Yold = round(self.laserY,3)
  955.  
  956.         can_dx = event.x-self.move_start_x
  957.         can_dy = -(event.y-self.move_start_y)
  958.        
  959.         dx = can_dx*self.PlotScale
  960.         dy = can_dy*self.PlotScale
  961.         if self.HomeUR.get():
  962.             dx = -dx
  963.         self.laserX,self.laserY = self.XY_in_bounds(dx,dy)
  964.         DXmils = round((self.laserX - Xold)*1000.0,0)
  965.         DYmils = round((self.laserY - Yold)*1000.0,0)
  966.         self.Send_Rapid_Move(DXmils,DYmils)
  967.         self.menu_View_Refresh()
  968.  
  969.     def LASER_Size(self):
  970.         MINX = 0.0
  971.         MAXY = 0.0
  972.         if self.units.get()=="in":
  973.             MAXX =  float(self.LaserXsize.get())
  974.             MINY = -float(self.LaserYsize.get())
  975.         else:
  976.             MAXX =  float(self.LaserXsize.get())/25.4
  977.             MINY = -float(self.LaserYsize.get())/25.4
  978.  
  979.         return (MAXX-MINX,MAXY-MINY)
  980.  
  981.  
  982.     def XY_in_bounds(self,dx_inches,dy_inches):
  983.         MINX = 0.0
  984.         MAXY = 0.0
  985.         if self.units.get()=="in":
  986.             MAXX =  float(self.LaserXsize.get())
  987.             MINY = -float(self.LaserYsize.get())
  988.         else:
  989.             MAXX =  float(self.LaserXsize.get())/25.4
  990.             MINY = -float(self.LaserYsize.get())/25.4
  991.  
  992.         if self.inputCSYS.get() and self.RengData.image == None:
  993.             xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  994.         else:
  995.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  996.        
  997.         X = self.laserX + dx_inches
  998.         X = min(MAXX-(xmax-xmin),X)
  999.         X = max(MINX,X)
  1000.        
  1001.         Y = self.laserY + dy_inches
  1002.         Y = max(MINY+(ymax-ymin),Y)
  1003.         Y = min(MAXY,Y)
  1004.        
  1005.         X = round(X,3)
  1006.         Y = round(Y,3)
  1007.         return X,Y
  1008.  
  1009. ##    def computeAccurateVeng(self):
  1010. ##        self.update_gui("Optimize vector engrave.")
  1011. ##        self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords),data_sorted=True)
  1012. ##        self.refreshTime()
  1013. ##            
  1014. ##    def computeAccurateVcut(self):
  1015. ##        self.update_gui("Optimize vector cut.")
  1016. ##        self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True)
  1017. ##        self.refreshTime()
  1018. ##
  1019. ##    def computeAccurateReng(self):
  1020. ##        self.update_gui("Calculating Raster engrave.")
  1021. ##        if self.RengData.image != None:        
  1022. ##            if self.RengData.ecoords == []:
  1023. ##                self.make_raster_coords()
  1024. ##        self.RengData.sorted = True
  1025. ##        self.refreshTime()
  1026.  
  1027.  
  1028.     def format_time(self,time_in_seconds):
  1029.         # format the duration from seconds to something human readable
  1030.         if time_in_seconds >=0 :
  1031.             s = round(time_in_seconds)
  1032.             m,s=divmod(s,60)
  1033.             h,m=divmod(m,60)
  1034.             res = ""
  1035.             if h > 0:
  1036.                 res =  "%dh " %(h)
  1037.             if m > 0:
  1038.                 res += "%dm " %(m)
  1039.             if h == 0:
  1040.                 res += "%ds " %(s)
  1041.             #L=len(res)
  1042.             #for i in range(L,8):
  1043.             #    res =  res+" "
  1044.             return res
  1045.         else :
  1046.             return "?"
  1047.  
  1048.     def refreshTime(self):
  1049.         if not self.include_Time.get():
  1050.             return
  1051.         if self.units.get() == 'in':
  1052.             factor =  60.0
  1053.         else :
  1054.             factor = 25.4
  1055.  
  1056.         Raster_eng_feed = float(self.Reng_feed.get()) / factor
  1057.         Vector_eng_feed = float(self.Veng_feed.get()) / factor
  1058.         Vector_cut_feed = float(self.Vcut_feed.get()) / factor
  1059.        
  1060.         Raster_eng_passes = float(self.Reng_passes.get())
  1061.         Vector_eng_passes = float(self.Veng_passes.get())
  1062.         Vector_cut_passes = float(self.Vcut_passes.get())
  1063.         Gcode_passes      = float(self.Gcde_passes.get())
  1064.  
  1065.         rapid_feed = 100.0 / 25.4   # 100 mm/s move feed to be confirmed
  1066.  
  1067.        
  1068.         #if self.RengData.sorted:
  1069.         #    wim, him = self.RengData.image.size
  1070.         #    Reng_time  =  ( (self.RengData.len)/Raster_eng_feed + (him/self.input_dpi)/rapid_feed) * Raster_eng_passes
  1071.         #else:
  1072.         try:
  1073.             wim, him = self.RengData.image.size
  1074.             Reng_time  =   ((wim/self.input_dpi * him/self.input_dpi)/ float(self.rast_step.get()) ) / Raster_eng_feed*Raster_eng_passes
  1075.         except:
  1076.             Reng_time = 0
  1077.  
  1078.         Veng_time  =  (self.VengData.len / Vector_eng_feed + self.VengData.move / rapid_feed) * Vector_eng_passes
  1079.         Vcut_time  =  (self.VcutData.len / Vector_cut_feed + self.VcutData.move / rapid_feed) * Vector_cut_passes
  1080.         Gcode_time =  self.GcodeData.gcode_time * Gcode_passes
  1081.                
  1082.         self.Reng_time.set("Raster Engrave: %s" %(self.format_time(Reng_time)))
  1083.         self.Veng_time.set("Vector Engrave: %s" %(self.format_time(Veng_time)))
  1084.         self.Vcut_time.set("    Vector Cut: %s" %(self.format_time(Vcut_time)))
  1085.         self.Gcde_time.set("         Gcode: %s" %(self.format_time(Gcode_time)))
  1086.        
  1087.         ##########################################
  1088.         cszw = int(self.PreviewCanvas.cget("width"))
  1089.         cszh = int(self.PreviewCanvas.cget("height"))
  1090.         HUD_vspace = 15
  1091.         HUD_X = cszw-5
  1092.         HUD_Y = cszh-5
  1093.         self.PreviewCanvas.delete("HUD")
  1094.         if self.GcodeData.ecoords == []:
  1095.             self.PreviewCanvas.create_text(HUD_X, HUD_Y             , fill = "red"  ,text =self.Vcut_time.get(), anchor="se",tags="HUD")
  1096.             self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace  , fill = "blue" ,text =self.Veng_time.get(), anchor="se",tags="HUD")
  1097.             self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace*2, fill = "black",text =self.Reng_time.get(), anchor="se",tags="HUD")
  1098.         else:
  1099.             self.PreviewCanvas.create_text(HUD_X, HUD_Y, fill = "black",text =self.Gcde_time.get(), anchor="se",tags="HUD")
  1100.         ##########################################
  1101.  
  1102.  
  1103.     def Settings_ReLoad_Click(self, event):
  1104.         win_id=self.grab_current()
  1105.  
  1106.     def Close_Current_Window_Click(self):
  1107.         win_id=self.grab_current()
  1108.         win_id.destroy()
  1109.        
  1110.     # Left Column #
  1111.     #############################
  1112.     def Entry_Reng_feed_Check(self):
  1113.         try:
  1114.             value = float(self.Reng_feed.get())
  1115.             if  value <= 0.0:
  1116.                 self.statusMessage.set(" Feed Rate should be greater than 0.0 ")
  1117.                 return 2 # Value is invalid number
  1118.         except:
  1119.             return 3     # Value not a number
  1120.         self.refreshTime()
  1121.         return 0         # Value is a valid number
  1122.     def Entry_Reng_feed_Callback(self, varName, index, mode):
  1123.         self.entry_set(self.Entry_Reng_feed, self.Entry_Reng_feed_Check(), new=1)        
  1124.     #############################
  1125.     def Entry_Veng_feed_Check(self):
  1126.         try:
  1127.             value = float(self.Veng_feed.get())
  1128.             if  value <= 0.0:
  1129.                 self.statusMessage.set(" Feed Rate should be greater than 0.0 ")
  1130.                 return 2 # Value is invalid number
  1131.         except:
  1132.             return 3     # Value not a number
  1133.         self.refreshTime()
  1134.         return 0         # Value is a valid number
  1135.     def Entry_Veng_feed_Callback(self, varName, index, mode):
  1136.         self.entry_set(self.Entry_Veng_feed, self.Entry_Veng_feed_Check(), new=1)
  1137.     #############################
  1138.     def Entry_Vcut_feed_Check(self):
  1139.         try:
  1140.             value = float(self.Vcut_feed.get())
  1141.             if  value <= 0.0:
  1142.                 self.statusMessage.set(" Feed Rate should be greater than 0.0 ")
  1143.                 return 2 # Value is invalid number
  1144.         except:
  1145.             return 3     # Value not a number
  1146.         self.refreshTime()
  1147.         return 0         # Value is a valid number
  1148.     def Entry_Vcut_feed_Callback(self, varName, index, mode):
  1149.         self.entry_set(self.Entry_Vcut_feed, self.Entry_Vcut_feed_Check(), new=1)
  1150.        
  1151.     #############################
  1152.     def Entry_Step_Check(self):
  1153.         try:
  1154.             value = float(self.jog_step.get())
  1155.             if  value <= 0.0:
  1156.                 self.statusMessage.set(" Step should be greater than 0.0 ")
  1157.                 return 2 # Value is invalid number
  1158.         except:
  1159.             return 3     # Value not a number
  1160.         return 0         # Value is a valid number
  1161.     def Entry_Step_Callback(self, varName, index, mode):
  1162.         self.entry_set(self.Entry_Step, self.Entry_Step_Check(), new=1)
  1163.  
  1164.  
  1165.     #############################
  1166.     def Entry_GoToX_Check(self):
  1167.         try:
  1168.             value = float(self.gotoX.get())
  1169.             if  (value < 0.0) and (not self.HomeUR.get()):
  1170.                 self.statusMessage.set(" Value should be greater than 0.0 ")
  1171.                 return 2 # Value is invalid number
  1172.             elif (value > 0.0) and self.HomeUR.get():
  1173.                 self.statusMessage.set(" Value should be less than 0.0 ")
  1174.                 return 2 # Value is invalid number
  1175.         except:
  1176.             return 3     # Value not a number
  1177.         return 0         # Value is a valid number
  1178.     def Entry_GoToX_Callback(self, varName, index, mode):
  1179.         self.entry_set(self.Entry_GoToX, self.Entry_GoToX_Check(), new=1)
  1180.  
  1181.     #############################
  1182.     def Entry_GoToY_Check(self):
  1183.         try:
  1184.             value = float(self.gotoY.get())
  1185.             if  value > 0.0:
  1186.                 self.statusMessage.set(" Value should be less than 0.0 ")
  1187.                 return 2 # Value is invalid number
  1188.         except:
  1189.             return 3     # Value not a number
  1190.         return 0         # Value is a valid number
  1191.     def Entry_GoToY_Callback(self, varName, index, mode):
  1192.         self.entry_set(self.Entry_GoToY, self.Entry_GoToY_Check(), new=1)
  1193.        
  1194.     #############################
  1195.     def Entry_Rstep_Check(self):
  1196.         try:
  1197.             value = self.get_raster_step_1000in()
  1198.             if  value <= 0 or value > 63:
  1199.                 self.statusMessage.set(" Step should be between 0.001 and 0.063 in")
  1200.                 return 2 # Value is invalid number
  1201.         except:
  1202.             return 3     # Value not a number
  1203.         return 0         # Value is a valid number
  1204.     def Entry_Rstep_Callback(self, varName, index, mode):
  1205.         self.entry_set(self.Entry_Rstep, self.Entry_Rstep_Check(), new=1)
  1206.  
  1207.     #############################
  1208.     # End Left Column #
  1209.     #############################
  1210.     def bezier_weight_Callback(self, varName=None, index=None, mode=None):
  1211.         self.bezier_plot()
  1212.        
  1213.     def bezier_M1_Callback(self, varName=None, index=None, mode=None):
  1214.         self.bezier_plot()
  1215.  
  1216.     def bezier_M2_Callback(self, varName=None, index=None, mode=None):
  1217.         self.bezier_plot()
  1218.  
  1219.     def bezier_plot(self):
  1220.         self.BezierCanvas.delete('bez')
  1221.  
  1222.         #self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="black", capstyle="round", width = 2, tags='bez')
  1223.         M1 = float(self.bezier_M1.get())
  1224.         M2 = float(self.bezier_M2.get())
  1225.         w  = float(self.bezier_weight.get())
  1226.         num = 10
  1227.         x,y = self.generate_bezier(M1,M2,w,n=num)
  1228.         for i in range(0,num):
  1229.             self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="black", \
  1230.                                            capstyle="round", width = 2, tags='bez')
  1231.         self.BezierCanvas.create_text(128, 0, text="Output Level vs. Input Level",anchor="n", tags='bez')
  1232.            
  1233.     #############################
  1234.     def Entry_Timeout_Check(self):
  1235.         try:
  1236.             value = float(self.t_timeout.get())
  1237.             if  value <= 0.0:
  1238.                 self.statusMessage.set(" Timeout should be greater than 0 ")
  1239.                 return 2 # Value is invalid number
  1240.         except:
  1241.             return 3     # Value not a number
  1242.         return 0         # Value is a valid number
  1243.     def Entry_Timeout_Callback(self, varName, index, mode):
  1244.         self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(), new=1)
  1245.  
  1246.     #############################
  1247.     def Entry_N_Timeouts_Check(self):
  1248.         try:
  1249.             value = float(self.n_timeouts.get())
  1250.             if  value <= 0.0:
  1251.                 self.statusMessage.set(" N_Timeouts should be greater than 0 ")
  1252.                 return 2 # Value is invalid number
  1253.         except:
  1254.             return 3     # Value not a number
  1255.         return 0         # Value is a valid number
  1256.     def Entry_N_Timeouts_Callback(self, varName, index, mode):
  1257.         self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(), new=1)
  1258.        
  1259.     #############################
  1260.     def Entry_Laser_Area_Width_Check(self):
  1261.         try:
  1262.             value = float(self.LaserXsize.get())
  1263.             if  value <= 0.0:
  1264.                 self.statusMessage.set(" Width should be greater than 0 ")
  1265.                 return 2 # Value is invalid number
  1266.         except:
  1267.             return 3     # Value not a number
  1268.         return 0         # Value is a valid number
  1269.     def Entry_Laser_Area_Width_Callback(self, varName, index, mode):
  1270.         self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(), new=1)
  1271.  
  1272.     #############################
  1273.     def Entry_Laser_Area_Height_Check(self):
  1274.         try:
  1275.             value = float(self.LaserYsize.get())
  1276.             if  value <= 0.0:
  1277.                 self.statusMessage.set(" Height should be greater than 0 ")
  1278.                 return 2 # Value is invalid number
  1279.         except:
  1280.             return 3     # Value not a number
  1281.         return 0         # Value is a valid number
  1282.     def Entry_Laser_Area_Height_Callback(self, varName, index, mode):
  1283.         self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(), new=1)
  1284.  
  1285.  
  1286.     #############################
  1287.     def Entry_Laser_X_Scale_Check(self):
  1288.         try:
  1289.             value = float(self.LaserXscale.get())
  1290.             if  value <= 0.0:
  1291.                 self.statusMessage.set(" Scale should be greater than 0 ")
  1292.                 return 2 # Value is invalid number
  1293.         except:
  1294.             return 3     # Value not a number
  1295.         return 0         # Value is a valid number
  1296.     def Entry_Laser_X_Scale_Callback(self, varName, index, mode):
  1297.         self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(), new=1)
  1298.     #############################
  1299.     def Entry_Laser_Y_Scale_Check(self):
  1300.         try:
  1301.             value = float(self.LaserYscale.get())
  1302.             if  value <= 0.0:
  1303.                 self.statusMessage.set(" Height should be greater than 0 ")
  1304.                 return 2 # Value is invalid number
  1305.         except:
  1306.             return 3     # Value not a number
  1307.         return 0         # Value is a valid number
  1308.     def Entry_Laser_Y_Scale_Callback(self, varName, index, mode):
  1309.         self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(), new=1)
  1310.  
  1311.     # Advanced Column #
  1312.     #############################
  1313.     def Entry_Reng_passes_Check(self):
  1314.         try:
  1315.             value = int(self.Reng_passes.get())
  1316.             if  value < 1:
  1317.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1318.                 return 2 # Value is invalid number
  1319.         except:
  1320.             return 3     # Value not a number
  1321.         self.refreshTime()
  1322.         return 0         # Value is a valid number
  1323.     def Entry_Reng_passes_Callback(self, varName, index, mode):
  1324.         self.entry_set(self.Entry_Reng_passes, self.Entry_Reng_passes_Check(), new=1)        
  1325.     #############################
  1326.     def Entry_Veng_passes_Check(self):
  1327.         try:
  1328.             value = int(self.Veng_passes.get())
  1329.             if  value < 1:
  1330.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1331.                 return 2 # Value is invalid number
  1332.         except:
  1333.             return 3     # Value not a number
  1334.         self.refreshTime()
  1335.         return 0         # Value is a valid number
  1336.     def Entry_Veng_passes_Callback(self, varName, index, mode):
  1337.         self.entry_set(self.Entry_Veng_passes, self.Entry_Veng_passes_Check(), new=1)
  1338.     #############################
  1339.     def Entry_Vcut_passes_Check(self):
  1340.         try:
  1341.             value = int(self.Vcut_passes.get())
  1342.             if  value < 1:
  1343.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1344.                 return 2 # Value is invalid number
  1345.         except:
  1346.             return 3     # Value not a number
  1347.         self.refreshTime()
  1348.         return 0         # Value is a valid number
  1349.     def Entry_Vcut_passes_Callback(self, varName, index, mode):
  1350.         self.entry_set(self.Entry_Vcut_passes, self.Entry_Vcut_passes_Check(), new=1)
  1351.        
  1352.     #############################
  1353.     def Entry_Gcde_passes_Check(self):
  1354.         try:
  1355.             value = int(self.Gcde_passes.get())
  1356.             if  value < 1:
  1357.                 self.statusMessage.set(" Number of passes should be greater than 0 ")
  1358.                 return 2 # Value is invalid number
  1359.         except:
  1360.             return 3     # Value not a number
  1361.         return 0         # Value is a valid number
  1362.     def Entry_Gcde_passes_Callback(self, varName, index, mode):
  1363.         self.entry_set(self.Entry_Gcde_passes, self.Entry_Gcde_passes_Check(), new=1)
  1364.        
  1365.     #############################
  1366.  
  1367.  
  1368.  
  1369.  
  1370.  
  1371.     ##########################################################################
  1372.     ##########################################################################
  1373.     def Check_All_Variables(self):
  1374.         pass
  1375. ##        MAIN_error_cnt= \
  1376. ##        self.entry_set(self.Entry_Yscale, self.Entry_Yscale_Check()    ,2) +\
  1377. ##        self.entry_set(self.Entry_Toptol, self.Entry_Toptol_Check()    ,2)
  1378. ##
  1379. ##        GEN_error_cnt= \
  1380. ##        self.entry_set(self.Entry_ContAngle,self.Entry_ContAngle_Check(),2)
  1381.  
  1382. ##        ERROR_cnt = MAIN_error_cnt + GEN_error_cnt
  1383. ##
  1384. ##        if (ERROR_cnt > 0):
  1385. ##            self.statusbar.configure( bg = 'red' )
  1386. ##        if (GEN_error_cnt > 0):
  1387. ##            self.statusMessage.set(\
  1388. ##                " Entry Error Detected: Check Entry Values in General Settings Window ")
  1389. ##        if (MAIN_error_cnt > 0):
  1390. ##            self.statusMessage.set(\
  1391. ##                " Entry Error Detected: Check Entry Values in Main Window ")
  1392. ##
  1393. ##        return ERROR_cnt
  1394.  
  1395.  
  1396.  
  1397.     #############################
  1398.     def Inkscape_Path_Click(self, event):
  1399.         win_id=self.grab_current()
  1400.         newfontdir = askopenfilename(filetypes=[("Executable Files",("inkscape.exe","*inkscape*")),\
  1401.                                                 ("All Files","*")],\
  1402.                                                  initialdir=self.inkscape_path.get())
  1403.         if newfontdir != "" and newfontdir != ():
  1404.             self.inkscape_path.set(newfontdir.encode("utf-8"))
  1405.         try:
  1406.             win_id.withdraw()
  1407.             win_id.deiconify()
  1408.         except:
  1409.             pass
  1410.  
  1411.  
  1412.     def Entry_units_var_Callback(self):
  1413.         if (self.units.get() == 'in') and (self.funits.get()=='mm/s'):
  1414.             self.funits.set('in/min')
  1415.             self.Scale_Linear_Inputs('in')
  1416.         elif (self.units.get() == 'mm') and (self.funits.get()=='in/min'):
  1417.             self.funits.set('mm/s')
  1418.             self.Scale_Linear_Inputs('mm')
  1419.            
  1420.     def Scale_Linear_Inputs(self, new_units=None):
  1421.         if new_units=='in':
  1422.             self.units_scale = 1.0
  1423.             factor  = 1/25.4
  1424.             vfactor = 60.0/25.4
  1425.         elif new_units=='mm':
  1426.             factor  = 25.4
  1427.             vfactor = 25.4/60.0
  1428.             self.units_scale = 25.4
  1429.         else:
  1430.             return
  1431.         self.LaserXsize.set( self.Scale_Text_Value('%.2f',self.LaserXsize.get(),factor) )
  1432.         self.LaserYsize.set( self.Scale_Text_Value('%.2f',self.LaserYsize.get(),factor) )
  1433.         self.jog_step.set  ( self.Scale_Text_Value('%.3f',self.jog_step.get()  ,factor) )
  1434.         self.gotoX.set     ( self.Scale_Text_Value('%.3f',self.gotoX.get()     ,factor) )
  1435.         self.gotoY.set     ( self.Scale_Text_Value('%.3f',self.gotoY.get()     ,factor) )
  1436.         self.Reng_feed.set ( self.Scale_Text_Value('%.1f',self.Reng_feed.get() ,vfactor) )
  1437.         self.Veng_feed.set ( self.Scale_Text_Value('%.1f',self.Veng_feed.get() ,vfactor) )
  1438.         self.Vcut_feed.set ( self.Scale_Text_Value('%.1f',self.Vcut_feed.get() ,vfactor) )
  1439.  
  1440.     def Scale_Text_Value(self,format_txt,Text_Value,factor):
  1441.         try:
  1442.             return format_txt %(float(Text_Value)*factor )
  1443.         except:
  1444.             return ''
  1445.  
  1446.     def menu_File_Open_Settings_File(self):
  1447.         init_dir = os.path.dirname(self.DESIGN_FILE)
  1448.         if ( not os.path.isdir(init_dir) ):
  1449.             init_dir = self.HOME_DIR
  1450.         fileselect = askopenfilename(filetypes=[("Settings Files","*.txt"),\
  1451.                                                 ("All Files","*")],\
  1452.                                                  initialdir=init_dir)
  1453.         if fileselect != '' and fileselect != ():
  1454.             self.Open_Settings_File(fileselect)
  1455.  
  1456.  
  1457.     def menu_Reload_Design(self):
  1458.         file_full = self.DESIGN_FILE
  1459.         file_name = os.path.basename(file_full)
  1460.         if ( os.path.isfile(file_full) ):
  1461.             filname = file_full
  1462.         elif ( os.path.isfile( file_name ) ):
  1463.             filname = file_name
  1464.         elif ( os.path.isfile( self.HOME_DIR+"/"+file_name ) ):
  1465.             filname = self.HOME_DIR+"/"+file_name
  1466.         else:
  1467.             self.statusMessage.set("file not found: %s" %(os.path.basename(file_full)) )
  1468.             self.statusbar.configure( bg = 'red' )
  1469.             return
  1470.        
  1471.        
  1472.         Name, fileExtension = os.path.splitext(filname)
  1473.         TYPE=fileExtension.upper()
  1474.         if TYPE=='.DXF':
  1475.             self.Open_DXF(filname)
  1476.         elif TYPE=='.SVG':
  1477.             self.Open_SVG(filname)
  1478.         else:
  1479.             self.Open_G_Code(filname)
  1480.         self.menu_View_Refresh()
  1481.        
  1482.  
  1483.     def menu_File_Open_Design(self):
  1484.         init_dir = os.path.dirname(self.DESIGN_FILE)
  1485.         if ( not os.path.isdir(init_dir) ):
  1486.             init_dir = self.HOME_DIR
  1487.  
  1488.         fileselect = askopenfilename(filetypes=[("Design Files", ("*.svg","*.dxf")),
  1489.                                             ("G-Code Files", ("*.ngc","*.gcode","*.g","*.tap")),\
  1490.                                             ("DXF Files","*.dxf"),\
  1491.                                             ("SVG Files","*.svg"),\
  1492.                                             ("All Files","*"),\
  1493.                                             ("Design Files ", ("*.svg","*.dxf"))],\
  1494.                                             initialdir=init_dir)
  1495.        
  1496.         if ( not os.path.isfile(fileselect) ):
  1497.             return
  1498.                
  1499.         Name, fileExtension = os.path.splitext(fileselect)
  1500.         self.update_gui("Opening '%s'" % fileselect )
  1501.         TYPE=fileExtension.upper()
  1502.         if TYPE=='.DXF':
  1503.             self.Open_DXF(fileselect)
  1504.         elif TYPE=='.SVG':
  1505.             self.Open_SVG(fileselect)
  1506.         else:
  1507.             self.Open_G_Code(fileselect)
  1508.  
  1509.            
  1510.         self.DESIGN_FILE = fileselect
  1511.         self.menu_View_Refresh()
  1512.        
  1513.  
  1514.     def menu_File_Open_EGV(self):
  1515.         init_dir = os.path.dirname(self.DESIGN_FILE)
  1516.         if ( not os.path.isdir(init_dir) ):
  1517.             init_dir = self.HOME_DIR
  1518.         fileselect = askopenfilename(filetypes=[("Engraver Files", ("*.egv","*.EGV")),\
  1519.                                                     ("All Files","*")],\
  1520.                                                      initialdir=init_dir)
  1521.  
  1522.         if fileselect != '' and fileselect != ():
  1523.             self.DESIGN_FILE = fileselect
  1524.             self.Open_EGV(fileselect)
  1525.             self.menu_View_Refresh()
  1526.            
  1527.     def Open_EGV(self,filemname):
  1528.         pass
  1529.         EGV_data=[]
  1530.         data=""
  1531.         with open(filemname) as f:
  1532.             while True:
  1533.                 c = f.read(1)
  1534.                 if not c:
  1535.                   break
  1536.                 if c=='\n' or c==' ' or c=='\r':
  1537.                     pass
  1538.                 else:
  1539.                     data=data+"%c" %c
  1540.                     EGV_data.append(ord(c))
  1541.         if message_ask_ok_cancel("EGV", "Send EGV Data to Laser...."):
  1542.             self.send_egv_data(EGV_data)
  1543.  
  1544.        
  1545.     def Open_SVG(self,filemname):
  1546.         self.resetPath()
  1547.                
  1548.         self.SVG_FILE = filemname
  1549.         svg_reader =  SVG_READER()
  1550.         svg_reader.set_inkscape_path(self.inkscape_path.get())
  1551.         self.input_dpi = 1000
  1552.         svg_reader.image_dpi = self.input_dpi
  1553.         try:
  1554.             try:
  1555.                 svg_reader.parse(self.SVG_FILE)
  1556.                 svg_reader.make_paths()
  1557.             except SVG_TEXT_EXCEPTION as e:
  1558.                 svg_reader = SVG_READER()
  1559.                 svg_reader.set_inkscape_path(self.inkscape_path.get())
  1560.                 self.statusMessage.set("Converting TEXT to PATHS.")
  1561.                 self.master.update()
  1562.                 svg_reader.parse(self.SVG_FILE)
  1563.                 svg_reader.make_paths(txt2paths=True)
  1564.                
  1565.         except StandardError as e:
  1566.             msg1 = "SVG file load failed: "
  1567.             msg2 = "%s" %(e)
  1568.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  1569.             self.statusbar.configure( bg = 'red' )
  1570.             message_box(msg1, msg2)
  1571.             debug_message(traceback.format_exc())
  1572.             return
  1573.         except:
  1574.             self.statusMessage.set("Unable To open SVG File: %s" %(filemname))
  1575.             debug_message(traceback.format_exc())
  1576.             return
  1577.         xmax = svg_reader.Xsize/25.4
  1578.         ymax = svg_reader.Ysize/25.4
  1579.         xmin = 0
  1580.         ymin = 0
  1581.  
  1582.         self.Design_bounds = (xmin,xmax,ymin,ymax)
  1583.        
  1584.         ##########################
  1585.         ###   Create ECOORDS   ###
  1586.         ##########################
  1587.         self.VcutData.make_ecoords(svg_reader.cut_lines,scale=1/25.4)
  1588.         self.VengData.make_ecoords(svg_reader.eng_lines,scale=1/25.4)
  1589.  
  1590.         ##########################
  1591.         ###   Load Image       ###
  1592.         ##########################
  1593.         self.RengData.set_image(svg_reader.raster_PIL)
  1594.        
  1595.         if (self.RengData.image != None):
  1596.             self.wim, self.him = self.RengData.image.size
  1597.             self.aspect_ratio =  float(self.wim-1) / float(self.him-1)
  1598.             #self.make_raster_coords()
  1599.         self.refreshTime()
  1600.  
  1601.     def make_ecoords(self,coords,scale=1):
  1602.         xmax, ymax = -1e10, -1e10
  1603.         xmin, ymin =  1e10,  1e10
  1604.         ecoords=[]
  1605.         Acc=.001
  1606.         oldx = oldy = -99990.0
  1607.         first_stroke = True
  1608.         loop=0
  1609.         for line in coords:
  1610.             XY = line
  1611.             x1 = XY[0]*scale
  1612.             y1 = XY[1]*scale
  1613.             x2 = XY[2]*scale
  1614.             y2 = XY[3]*scale
  1615.             dx = oldx - x1
  1616.             dy = oldy - y1
  1617.             dist = sqrt(dx*dx + dy*dy)
  1618.             # check and see if we need to move to a new discontinuous start point
  1619.             if (dist > Acc) or first_stroke:
  1620.                 loop = loop+1
  1621.                 first_stroke = False
  1622.                 ecoords.append([x1,y1,loop])
  1623.             ecoords.append([x2,y2,loop])
  1624.             oldx, oldy = x2, y2
  1625.             xmax=max(xmax,x1,x2)
  1626.             ymax=max(ymax,y1,y2)
  1627.             xmin=min(xmin,x1,x2)
  1628.             ymin=min(ymin,y1,y2)
  1629.         bounds = (xmin,xmax,ymin,ymax)
  1630.         return ecoords,bounds
  1631.  
  1632. ##    def convert_greyscale(self,image):
  1633. ##        image = image.convert('RGB')
  1634. ##        x_lim, y_lim = image.size
  1635. ##        grey = Image.new("L", image.size, color=255)
  1636. ##        
  1637. ##        pixel = image.load()
  1638. ##        grey_pixel = grey.load()
  1639. ##        
  1640. ##        for y in range(1, y_lim):
  1641. ##            self.statusMessage.set("Converting to greyscale: %.1f %%" %( (100.0*y)/y_lim ) )
  1642. ##            self.master.update()
  1643. ##            for x in range(1, x_lim):
  1644. ##                value = pixel[x, y]
  1645. ##                grey_pixel[x,y] = int( value[0]*.333 + value[1]*.333 +value[2]*.333 )
  1646. ##                #grey_pixel[x,y] = int( value[0]*.210 + value[1]*.720 +value[2]*.007 )
  1647. ##                grey_pixel[x,y] = int( value[0]*.299 + value[1]*.587 +value[2]*.114 )
  1648. ##
  1649. ##        grey.save("adjusted_grey.png","PNG")
  1650. ##        return grey
  1651.  
  1652.    
  1653.     #####################################################################
  1654.     def make_raster_coords(self):
  1655.             ecoords=[]
  1656.             if (self.RengData.image != None):
  1657.                 cutoff=128
  1658.                 image_temp = self.RengData.image.convert("L")
  1659.  
  1660.                 if self.mirror.get():
  1661.                     image_temp = ImageOps.mirror(image_temp)
  1662.  
  1663.                 if self.rotate.get():
  1664.                     #image_temp = image_temp.rotate(90,expand=True)
  1665.                     image_temp = self.rotate_raster(image_temp)
  1666.  
  1667.                 Xscale = float(self.LaserXscale.get())
  1668.                 Yscale = float(self.LaserYscale.get())
  1669.                 if Xscale != 1.0 or Yscale != 1.0:
  1670.                     wim,him = image_temp.size
  1671.                     nw = int(wim*Xscale)
  1672.                     nh = int(him*Yscale)
  1673.                     image_temp = image_temp.resize((nw,nh))
  1674.  
  1675.                    
  1676.                 if self.halftone.get():
  1677.                     #start = time()
  1678.                     ht_size_mils =  round( 1000.0 / float(self.ht_size.get()) ,1)
  1679.                     npixels = int( round(ht_size_mils,1) )
  1680.                     if npixels == 0:
  1681.                         return
  1682.                     wim,him = image_temp.size
  1683.                     # Convert to Halftoning and save
  1684.                     nw=int(wim / npixels)
  1685.                     nh=int(him / npixels)
  1686.                     image_temp = image_temp.resize((nw,nh))
  1687.                    
  1688.                     image_temp = self.convert_halftoning(image_temp)
  1689.                     image_temp = image_temp.resize((wim,him))
  1690.                     #print time()-start
  1691.                    
  1692.                 if DEBUG:
  1693.                     image_name = os.path.expanduser("~")+"/IMAGE.png"
  1694.                     image_temp.save(image_name,"PNG")
  1695.  
  1696.                 Reng_np = image_temp.load()
  1697.                 wim,him = image_temp.size
  1698.                 #######################################
  1699.                 x=0
  1700.                 y=0
  1701.                 loop=1
  1702.                
  1703.                 Raster_step = self.get_raster_step_1000in()
  1704.                 for i in range(0,him,Raster_step):
  1705.                     if i%100 ==0:
  1706.                         self.statusMessage.set("Raster Engraving: Creating Scan Lines: %.1f %%" %( (100.0*i)/him ) )
  1707.                         self.master.update()
  1708.                     if self.stop[0]==True:
  1709.                         raise StandardError("Action stopped by User.")
  1710.                     line = []
  1711.                     cnt=1
  1712.                     for j in range(1,wim):
  1713.                         if (Reng_np[j,i] == Reng_np[j-1,i]):
  1714.                             cnt = cnt+1
  1715.                         else:
  1716.                             laser = "U" if Reng_np[j-1,i] > cutoff else "D"
  1717.                             line.append((cnt,laser))
  1718.                             cnt=1
  1719.                     laser = "U" if Reng_np[j-1,i] > cutoff else "D"
  1720.                     line.append((cnt,laser))
  1721.                    
  1722.                     y=(him-i)/1000.0
  1723.                     x=0
  1724.                     rng = range(0,len(line),1)
  1725.                        
  1726.                     for i in rng:
  1727.                         seg = line[i]
  1728.                         delta = seg[0]/1000.0
  1729.                         if seg[1]=="D":
  1730.                             loop=loop+1
  1731.                             ecoords.append([x      ,y,loop])
  1732.                             ecoords.append([x+delta,y,loop])
  1733.                         x = x + delta
  1734.                        
  1735.             if ecoords!=[]:
  1736.                 self.RengData.set_ecoords(ecoords,data_sorted=True)
  1737.     #######################################################################
  1738.  
  1739.  
  1740.     def rotate_raster(self,image_in):
  1741.         wim,him = image_in.size
  1742.         im_rotated = Image.new("L", (him, wim), "white")
  1743.  
  1744.         image_in_np   = image_in.load()
  1745.         im_rotated_np = im_rotated.load()
  1746.        
  1747.         for i in range(1,him):
  1748.             for j in range(1,wim):
  1749.                 im_rotated_np[i,wim-j] = image_in_np[j,i]
  1750.         return im_rotated
  1751.    
  1752.     def get_raster_step_1000in(self):
  1753.         val_in = float(self.rast_step.get())
  1754.         value = int(round(val_in*1000.0,1))
  1755.         return value
  1756.  
  1757.  
  1758.     def generate_bezier(self,M1,M2,w,n=100):
  1759.         if (M1==M2):
  1760.             x1=0
  1761.             y1=0
  1762.         else:
  1763.             x1 = 255*(1-M2)/(M1-M2)
  1764.             y1 = M1*x1
  1765.         x=[]
  1766.         y=[]
  1767.         # Calculate Bezier Curve
  1768.         for step in range(0,n+1):
  1769.             t    = float(step)/float(n)
  1770.             Ct   = 1 / ( pow(1-t,2)+2*(1-t)*t*w+pow(t,2) )
  1771.             x.append( Ct*( 2*(1-t)*t*w*x1+pow(t,2)*255) )
  1772.             y.append( Ct*( 2*(1-t)*t*w*y1+pow(t,2)*255) )
  1773.         return x,y
  1774.  
  1775.     '''This Example opens an Image and transform the image into halftone.  -Isai B. Cicourel'''
  1776.     # Create a Half-tone version of the image
  1777.     def convert_halftoning(self,image):
  1778.         image = image.convert('L')
  1779.         x_lim, y_lim = image.size
  1780.         pixel = image.load()
  1781.        
  1782.         M1 = float(self.bezier_M1.get())
  1783.         M2 = float(self.bezier_M2.get())
  1784.         w  = float(self.bezier_weight.get())
  1785.        
  1786.         if w > 0:
  1787.             x,y = self.generate_bezier(M1,M2,w)
  1788.            
  1789.             interp = interpolate(x, y) # Set up interpolate class
  1790.             val_map=[]
  1791.             # Map Bezier Curve to values between 0 and 255
  1792.             for val in range(0,256):
  1793.                 val_out = int(round(interp[val])) # Get the interpolated value at each value
  1794.                 val_map.append(val_out)
  1795.             # Adjust image
  1796.             for y in range(1, y_lim):
  1797.                 self.statusMessage.set("Raster Engraving: Adjusting Image Darkness: %.1f %%" %( (100.0*y)/y_lim ) )
  1798.                 self.master.update()
  1799.                 for x in range(1, x_lim):
  1800.                     pixel[x, y] = val_map[ pixel[x, y] ]
  1801.  
  1802.         self.statusMessage.set("Raster Engraving: Creating Halftone Image." )
  1803.         self.master.update()
  1804.         image = image.convert('1')
  1805.         return image
  1806.  
  1807.     #######################################################################
  1808.  
  1809.     def Open_G_Code(self,filename):
  1810.         self.resetPath()
  1811.        
  1812.         g_rip = G_Code_Rip()
  1813.         try:
  1814.             MSG = g_rip.Read_G_Code(filename, XYarc2line = True, arc_angle=2, units="in", Accuracy="")
  1815.             Error_Text = ""
  1816.             if MSG!=[]:
  1817.                 for line in MSG:
  1818.                     Error_Text = Error_Text + line + "\n"
  1819.                     message_box("G-Code Messages", Error_Text)
  1820.         except StandardError as e:
  1821.             msg1 = "G-Code Load Failed:  "
  1822.             msg2 = "Filename: %s" %(filename)
  1823.             msg3 = "%s" %(e)
  1824.             self.statusMessage.set((msg1+msg3).split("\n")[0] )
  1825.             self.statusbar.configure( bg = 'red' )
  1826.             message_box(msg1, "%s\n%s" %(msg2,msg3))
  1827.             debug_message(traceback.format_exc())
  1828.  
  1829.            
  1830.         ecoords= g_rip.generate_laser_paths(g_rip.g_code_data)
  1831.         self.GcodeData.set_ecoords(ecoords,data_sorted=True)
  1832.         self.Design_bounds = self.GcodeData.bounds
  1833.  
  1834.        
  1835.     def Open_DXF(self,filemname):
  1836.         self.resetPath()
  1837.        
  1838.         self.DXF_FILE = filemname
  1839.         dxf_import=DXF_CLASS()
  1840.         segarc = 2
  1841.         try:
  1842.             fd = open(self.DXF_FILE)
  1843.             dxf_import.GET_DXF_DATA(fd,tol_deg=segarc)
  1844.             fd.close()
  1845.         except StandardError as e:
  1846.             msg1 = "DXF Load Failed:"
  1847.             msg2 = "%s" %(e)
  1848.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  1849.             self.statusbar.configure( bg = 'red' )
  1850.             message_box(msg1, msg2)
  1851.             debug_message(traceback.format_exc())
  1852.         except:
  1853.             fmessage("Unable To open Drawing Exchange File (DXF) file.")
  1854.             debug_message(traceback.format_exc())
  1855.             return
  1856.        
  1857.         new_origin=False
  1858.         dxf_engrave_coords = dxf_import.DXF_COORDS_GET_TYPE(engrave=True, new_origin=False)
  1859.         dxf_cut_coords     = dxf_import.DXF_COORDS_GET_TYPE(engrave=False,new_origin=False)
  1860.        
  1861.         dxf_units = dxf_import.units
  1862.         if dxf_import.dxf_messages != "":
  1863.             msg_split=dxf_import.dxf_messages.split("\n")
  1864.             msg_split.sort()
  1865.             msg_split.append("")
  1866.             mcnt=1
  1867.             msg_out = ""
  1868.             for i in range(1,len(msg_split)):
  1869.                 if msg_split[i-1]==msg_split[i]:
  1870.                     mcnt=mcnt+1
  1871.                 else:
  1872.                     if msg_split[i-1]!="":
  1873.                         msg_line = "%s (%d places)\n" %(msg_split[i-1],mcnt)
  1874.                         msg_out = msg_out + msg_line
  1875.                     mcnt=1
  1876.             message_box("DXF Import:",msg_out)
  1877.            
  1878.         if dxf_units=="Unitless":
  1879.             d = UnitsDialog(root)
  1880.             dxf_units = d.result
  1881.  
  1882.         if dxf_units=="Inches":
  1883.             dxf_scale = 1.0
  1884.         elif dxf_units=="Feet":
  1885.             dxf_scale = 12.0
  1886.         elif dxf_units=="Miles":
  1887.             dxf_scale = 5280.0*12.0
  1888.         elif dxf_units=="Millimeters":
  1889.             dxf_scale = 1.0/25.4
  1890.         elif dxf_units=="Centimeters":
  1891.             dxf_scale = 1.0/2.54
  1892.         elif dxf_units=="Meters":
  1893.             dxf_scale = 1.0/254.0
  1894.         elif dxf_units=="Kilometers":
  1895.             dxf_scale = 1.0/254000.0
  1896.         elif dxf_units=="Microinches":
  1897.             dxf_scale = 1.0/1000000.0
  1898.         elif dxf_units=="Mils":
  1899.             dxf_scale = 1.0/1000.0
  1900.         else:
  1901.             return
  1902.        
  1903.         ##########################
  1904.         ###   Create ECOORDS   ###
  1905.         ##########################
  1906.         self.VcutData.make_ecoords(dxf_cut_coords    ,scale=dxf_scale)
  1907.         self.VengData.make_ecoords(dxf_engrave_coords,scale=dxf_scale)
  1908.  
  1909.         xmin = min(self.VcutData.bounds[0],self.VengData.bounds[0])
  1910.         xmax = max(self.VcutData.bounds[1],self.VengData.bounds[1])
  1911.         ymin = min(self.VcutData.bounds[2],self.VengData.bounds[2])
  1912.         ymax = max(self.VcutData.bounds[3],self.VengData.bounds[3])
  1913.         self.Design_bounds = (xmin,xmax,ymin,ymax)
  1914.  
  1915.  
  1916.     def Open_Settings_File(self,filename):
  1917.         try:
  1918.             fin = open(filename,'r')
  1919.         except:
  1920.             fmessage("Unable to open file: %s" %(filename))
  1921.             return
  1922.        
  1923.         text_codes=[]
  1924.         ident = "k40_whisperer_set"
  1925.         for line in fin:
  1926.             if ident in line:
  1927.                 # BOOL
  1928.                 if "include_Reng"  in line:
  1929.                     self.include_Reng.set(line[line.find("include_Reng"):].split()[1])
  1930.                 elif "include_Veng"  in line:
  1931.                     self.include_Veng.set(line[line.find("include_Veng"):].split()[1])
  1932.                 elif "include_Vcut"  in line:
  1933.                     self.include_Vcut.set(line[line.find("include_Vcut"):].split()[1])
  1934.                 elif "include_Gcde"  in line:
  1935.                     self.include_Gcde.set(line[line.find("include_Gcde"):].split()[1])
  1936.                 elif "include_Time"  in line:
  1937.                     self.include_Time.set(line[line.find("include_Time"):].split()[1])
  1938.                 elif "halftone"  in line:
  1939.                     self.halftone.set(line[line.find("halftone"):].split()[1])
  1940.                 elif "HomeUR"  in line:
  1941.                     self.HomeUR.set(line[line.find("HomeUR"):].split()[1])                    
  1942.                 elif "inputCSYS"  in line:
  1943.                     self.inputCSYS.set(line[line.find("inputCSYS"):].split()[1])
  1944.                 elif "advanced"  in line:
  1945.                     self.advanced.set(line[line.find("advanced"):].split()[1])
  1946.                 elif "mirror"  in line:
  1947.                     self.mirror.set(line[line.find("mirror"):].split()[1])
  1948.                 elif "rotate"  in line:
  1949.                     self.rotate.set(line[line.find("rotate"):].split()[1])
  1950.                 elif "engraveUP"  in line:
  1951.                     self.engraveUP.set(line[line.find("engraveUP"):].split()[1])
  1952.                 elif "init_home"  in line:
  1953.                     self.init_home.set(line[line.find("init_home"):].split()[1])
  1954.                 elif "pre_pr_crc"  in line:
  1955.                     self.pre_pr_crc.set(line[line.find("pre_pr_crc"):].split()[1])
  1956.                 elif "inside_first"  in line:
  1957.                     self.inside_first.set(line[line.find("inside_first"):].split()[1])
  1958.        
  1959.                 # STRING.set()
  1960.                 elif "board_name" in line:
  1961.                     self.board_name.set(line[line.find("board_name"):].split()[1])
  1962.                 elif "units"    in line:
  1963.                     self.units.set(line[line.find("units"):].split()[1])
  1964.                 elif "Reng_feed"    in line:
  1965.                      self.Reng_feed .set(line[line.find("Reng_feed"):].split()[1])
  1966.                 elif "Veng_feed"    in line:
  1967.                      self.Veng_feed .set(line[line.find("Veng_feed"):].split()[1])  
  1968.                 elif "Vcut_feed"    in line:
  1969.                      self.Vcut_feed.set(line[line.find("Vcut_feed"):].split()[1])
  1970.                 elif "jog_step"    in line:
  1971.                      self.jog_step.set(line[line.find("jog_step"):].split()[1])
  1972.                      
  1973.                 elif "Reng_passes"    in line:
  1974.                      self.Reng_passes.set(line[line.find("Reng_passes"):].split()[1])
  1975.                 elif "Veng_passes"    in line:
  1976.                      self.Veng_passes.set(line[line.find("Veng_passes"):].split()[1])
  1977.                 elif "Vcut_passes"    in line:
  1978.                      self.Vcut_passes.set(line[line.find("Vcut_passes"):].split()[1])
  1979.                 elif "Gcde_passes"    in line:
  1980.                      self.Gcde_passes.set(line[line.find("Gcde_passes"):].split()[1])
  1981.  
  1982.                 elif "rast_step"    in line:
  1983.                      self.rast_step.set(line[line.find("rast_step"):].split()[1])
  1984.                 elif "ht_size"    in line:
  1985.                      self.ht_size.set(line[line.find("ht_size"):].split()[1])
  1986.  
  1987.                 elif "LaserXsize"    in line:
  1988.                      self.LaserXsize.set(line[line.find("LaserXsize"):].split()[1])
  1989.                 elif "LaserYsize"    in line:
  1990.                      self.LaserYsize.set(line[line.find("LaserYsize"):].split()[1])
  1991.                 elif "LaserXscale"    in line:
  1992.                      self.LaserXscale.set(line[line.find("LaserXscale"):].split()[1])
  1993.                 elif "LaserYscale"    in line:
  1994.                      self.LaserYscale.set(line[line.find("LaserYscale"):].split()[1])
  1995.                      
  1996.                 elif "gotoX"    in line:
  1997.                      self.gotoX.set(line[line.find("gotoX"):].split()[1])
  1998.                 elif "gotoY"    in line:
  1999.                      self.gotoY.set(line[line.find("gotoY"):].split()[1])
  2000.  
  2001.                 elif "bezier_M1"    in line:
  2002.                      self.bezier_M1.set(line[line.find("bezier_M1"):].split()[1])
  2003.                 elif "bezier_M2"    in line:
  2004.                      self.bezier_M2.set(line[line.find("bezier_M2"):].split()[1])
  2005.                 elif "bezier_weight"    in line:
  2006.                      self.bezier_weight.set(line[line.find("bezier_weight"):].split()[1])
  2007.        
  2008.                 elif "t_timeout"    in line:
  2009.                      self.t_timeout.set(line[line.find("t_timeout"):].split()[1])
  2010.                 elif "n_timeouts"    in line:
  2011.                      self.n_timeouts.set(line[line.find("n_timeouts"):].split()[1])
  2012.  
  2013.                 elif "designfile"    in line:
  2014.                        self.DESIGN_FILE=(line[line.find("designfile"):].split("\042")[1])
  2015.                 elif "inkscape_path"    in line:
  2016.                      self.inkscape_path.set(line[line.find("inkscape_path"):].split("\042")[1])
  2017.                      
  2018.         fin.close()
  2019.  
  2020.         fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
  2021.         init_file=os.path.basename(fileName)
  2022.        
  2023.         if init_file != "None":
  2024.             if ( os.path.isfile(self.DESIGN_FILE) ):
  2025.                 pass
  2026.             else:
  2027.                 self.statusMessage.set("Image file not found: %s " %(self.DESIGN_FILE))
  2028.  
  2029.         if self.units.get() == 'in':
  2030.             self.funits.set('in/min')
  2031.             self.units_scale = 1.0
  2032.         else:
  2033.             self.units.set('mm')
  2034.             self.funits.set('mm/s')
  2035.             self.units_scale = 25.4
  2036.  
  2037.         temp_name, fileExtension = os.path.splitext(filename)
  2038.         file_base=os.path.basename(temp_name)
  2039.            
  2040.         if self.initComplete == 1:
  2041.             self.menu_Mode_Change()
  2042.             self.DESIGN_FILE = filename
  2043.            
  2044.     ##########################################################################
  2045.     ##########################################################################
  2046.     def menu_File_Save(self):
  2047.         #if (self.Check_All_Variables() > 0):
  2048.         #    return
  2049.  
  2050.         settings_data = self.WriteConfig()
  2051.         init_dir = os.path.dirname(self.DESIGN_FILE)
  2052.         if ( not os.path.isdir(init_dir) ):
  2053.             init_dir = self.HOME_DIR
  2054.            
  2055.         fileName, fileExtension = os.path.splitext(self.DESIGN_FILE)
  2056.         init_file=os.path.basename(fileName)
  2057.  
  2058.         filename = asksaveasfilename(defaultextension='.txt', \
  2059.                                      filetypes=[("Text File","*.txt")],\
  2060.                                      initialdir=init_dir,\
  2061.                                      initialfile= init_file )
  2062.  
  2063.         if filename != '' and filename != ():
  2064.             try:
  2065.                 fout = open(filename,'w')
  2066.             except:
  2067.                 self.statusMessage.set("Unable to open file for writing: %s" %(filename))
  2068.                 self.statusbar.configure( bg = 'red' )
  2069.                 return
  2070.  
  2071.             for line in settings_data:
  2072.                 try:
  2073.                     fout.write(line+'\n')
  2074.                 except:
  2075.                     fout.write('(skipping line)\n')
  2076.                     debug_message(traceback.format_exc())
  2077.             fout.close
  2078.             self.statusMessage.set("File Saved: %s" %(filename))
  2079.             self.statusbar.configure( bg = 'white' )
  2080.        
  2081.     def Get_Design_Bounds(self):
  2082.         if self.rotate.get():
  2083.             ymin =  self.Design_bounds[0]
  2084.             ymax =  self.Design_bounds[1]
  2085.             xmin = -self.Design_bounds[3]
  2086.             xmax = -self.Design_bounds[2]
  2087.         else:
  2088.             xmin,xmax,ymin,ymax = self.Design_bounds
  2089.         return (xmin,xmax,ymin,ymax)
  2090.    
  2091.     def Move_UL(self,dummy=None):
  2092.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2093.         if self.HomeUR.get():
  2094.             Xnew = self.laserX + (xmax-xmin)
  2095.             DX = round((xmax-xmin)*1000.0)
  2096.         else:
  2097.             Xnew = self.laserX
  2098.             DX = 0
  2099.            
  2100.         (Xsize,Ysize)=self.LASER_Size()
  2101.         if Xnew <= Xsize+.001:
  2102.             self.move_head_window_temporary([DX,0.0])
  2103.         else:
  2104.             pass
  2105.  
  2106.     def Move_UR(self,dummy=None):
  2107.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2108.         if self.HomeUR.get():
  2109.             Xnew = self.laserX
  2110.             DX = 0
  2111.         else:
  2112.             Xnew = self.laserX + (xmax-xmin)
  2113.             DX = round((xmax-xmin)*1000.0)
  2114.  
  2115.         (Xsize,Ysize)=self.LASER_Size()
  2116.         if Xnew <= Xsize+.001:
  2117.             self.move_head_window_temporary([DX,0.0])
  2118.         else:
  2119.             pass
  2120.    
  2121.     def Move_LR(self,dummy=None):
  2122.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2123.         if self.HomeUR.get():
  2124.             Xnew = self.laserX
  2125.             DX = 0
  2126.         else:
  2127.             Xnew = self.laserX + (xmax-xmin)
  2128.             DX = round((xmax-xmin)*1000.0)
  2129.            
  2130.         Ynew = self.laserY - (ymax-ymin)
  2131.         (Xsize,Ysize)=self.LASER_Size()
  2132.         if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
  2133.             DY = round((ymax-ymin)*1000.0)
  2134.             self.move_head_window_temporary([DX,-DY])
  2135.         else:
  2136.             pass
  2137.    
  2138.     def Move_LL(self,dummy=None):
  2139.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2140.         if self.HomeUR.get():
  2141.             Xnew = self.laserX + (xmax-xmin)
  2142.             DX = round((xmax-xmin)*1000.0)
  2143.         else:
  2144.             Xnew = self.laserX
  2145.             DX = 0
  2146.            
  2147.         Ynew = self.laserY - (ymax-ymin)
  2148.         (Xsize,Ysize)=self.LASER_Size()
  2149.         if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
  2150.             DY = round((ymax-ymin)*1000.0)
  2151.             self.move_head_window_temporary([DX,-DY])
  2152.         else:
  2153.             pass
  2154.  
  2155.     def Move_CC(self,dummy=None):
  2156.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2157.         if self.HomeUR.get():
  2158.             Xnew = self.laserX + (xmax-xmin)/2.0
  2159.             DX = round((xmax-xmin)/2.0*1000.0)
  2160.         else:
  2161.             Xnew = self.laserX + (xmax-xmin)/2.0
  2162.             DX = round((xmax-xmin)/2.0*1000.0)
  2163.  
  2164.            
  2165.         Ynew = self.laserY - (ymax-ymin)/2.0
  2166.         (Xsize,Ysize)=self.LASER_Size()
  2167.         if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001:
  2168.             DY = round((ymax-ymin)/2.0*1000.0)
  2169.             self.move_head_window_temporary([DX,-DY])
  2170.         else:
  2171.             pass
  2172.  
  2173.  
  2174.     def Move_Right(self,dummy=None):
  2175.         JOG_STEP = float( self.jog_step.get() )
  2176.         self.Rapid_Move( JOG_STEP,0 )
  2177.  
  2178.     def Move_Left(self,dummy=None):
  2179.         JOG_STEP = float( self.jog_step.get() )
  2180.         self.Rapid_Move( -JOG_STEP,0 )
  2181.  
  2182.     def Move_Up(self,dummy=None):
  2183.         JOG_STEP = float( self.jog_step.get() )
  2184.         self.Rapid_Move( 0,JOG_STEP )
  2185.  
  2186.     def Move_Down(self,dummy=None):
  2187.         JOG_STEP = float( self.jog_step.get() )
  2188.         self.Rapid_Move( 0,-JOG_STEP )
  2189.  
  2190.     def Rapid_Move(self,dx,dy):
  2191.         if self.units.get()=="in":
  2192.             dx_inches = round(dx,3)
  2193.             dy_inches = round(dy,3)
  2194.         else:
  2195.             dx_inches = round(dx/25.4,3)
  2196.             dy_inches = round(dy/25.4,3)
  2197.  
  2198.         if (self.HomeUR.get()):
  2199.             dx_inches = -dx_inches
  2200.  
  2201.         Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches)
  2202.         dxmils = (Xnew - self.laserX)*1000.0
  2203.         dymils = (Ynew - self.laserY)*1000.0
  2204.        
  2205.         self.Send_Rapid_Move(dxmils,dymils)
  2206.            
  2207.         self.laserX  = Xnew
  2208.         self.laserY  = Ynew
  2209.         self.menu_View_Refresh()
  2210.  
  2211.     def Send_Rapid_Move(self,dxmils,dymils):
  2212.         try:
  2213.             if self.k40 != None:
  2214.                 if float(self.LaserXscale.get()) != 1.0 or float(self.LaserYscale.get()) != 1.0:
  2215.                     dxmils = int(round(dxmils *float(self.LaserXscale.get())))
  2216.                     dymils = int(round(dymils *float(self.LaserYscale.get())))
  2217.                 self.k40.rapid_move(dxmils,dymils)
  2218.         except StandardError as e:
  2219.             msg1 = "Rapid Move Failed: "
  2220.             msg2 = "%s" %(e)
  2221.             if msg2 == "":
  2222.                 formatted_lines = traceback.format_exc().splitlines()
  2223.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2224.             self.statusbar.configure( bg = 'red' )
  2225.             message_box(msg1, msg2)
  2226.             debug_message(traceback.format_exc())
  2227.  
  2228.     def update_gui(self, message=None):
  2229.         if message!=None:
  2230.             self.statusMessage.set(message)  
  2231.         self.master.update()
  2232.  
  2233.     def set_gui(self,new_state="normal"):
  2234.         self.menuBar.entryconfigure("File"    , state=new_state)
  2235.         self.menuBar.entryconfigure("View"    , state=new_state)
  2236.         self.menuBar.entryconfigure("USB"     , state=new_state)
  2237.         self.menuBar.entryconfigure("Settings", state=new_state)
  2238.         self.menuBar.entryconfigure("Help"    , state=new_state)
  2239.         self.PreviewCanvas.configure(state=new_state)
  2240.        
  2241.         for w in self.master.winfo_children():
  2242.             try:
  2243.                 w.configure(state=new_state)
  2244.             except:
  2245.                 pass
  2246.         self.Stop_Button.configure(state="normal")
  2247.         self.statusbar.configure(state="normal")
  2248.         self.master.update()
  2249.  
  2250.     def Vector_Cut(self):
  2251.         self.stop[0]=False
  2252.         self.set_gui("disabled")
  2253.         self.statusbar.configure( bg = 'green' )
  2254.         self.statusMessage.set("Vector Cut: Processing Vector Data.")
  2255.         self.master.update()
  2256.         if self.VcutData.ecoords!=[]:
  2257.             self.send_data("Vector_Cut")
  2258.         else:
  2259.             self.statusbar.configure( bg = 'yellow' )
  2260.             self.statusMessage.set("No vector data to cut")
  2261.         self.set_gui("normal")
  2262.        
  2263.     def Vector_Eng(self):
  2264.         self.stop[0]=False
  2265.         self.set_gui("disabled")
  2266.         self.statusbar.configure( bg = 'green' )
  2267.         self.statusMessage.set("Vector Engrave: Processing Vector Data.")
  2268.         self.master.update()
  2269.         if self.VengData.ecoords!=[]:
  2270.             self.send_data("Vector_Eng")
  2271.         else:
  2272.             self.statusbar.configure( bg = 'yellow' )
  2273.             self.statusMessage.set("No vector data to engrave")
  2274.         self.set_gui("normal")
  2275.  
  2276.     def Raster_Eng(self):
  2277.         self.stop[0]=False
  2278.         self.set_gui("disabled")
  2279.         self.statusbar.configure( bg = 'green' )
  2280.         self.statusMessage.set("Raster Engraving: Processing Image Data.")
  2281.         self.master.update()
  2282.         try:
  2283.             self.make_raster_coords()
  2284.             if self.RengData.ecoords!=[]:
  2285.                 self.send_data("Raster_Eng")
  2286.             else:
  2287.                 self.statusbar.configure( bg = 'yellow' )
  2288.                 self.statusMessage.set("No raster data to engrave")
  2289.         except StandardError as e:
  2290.             msg1 = "Making Raster Data Stopped: "
  2291.             msg2 = "%s" %(e)
  2292.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2293.             self.statusbar.configure( bg = 'red' )
  2294.             message_box(msg1, msg2)
  2295.             debug_message(traceback.format_exc())
  2296.         self.set_gui("normal")
  2297.  
  2298.  
  2299.     def Gcode_Cut(self):
  2300.         self.stop[0]=False
  2301.         self.set_gui("disabled")
  2302.         self.statusbar.configure( bg = 'green' )
  2303.         self.statusMessage.set("G Code Cutting.")
  2304.         self.master.update()
  2305.         if self.GcodeData.ecoords!=[]:
  2306.             self.send_data("Gcode_Cut")
  2307.         else:
  2308.             self.statusbar.configure( bg = 'yellow' )
  2309.             self.statusMessage.set("No g-code data to cut")
  2310.         self.set_gui("normal")
  2311.  
  2312.  
  2313.     ################################################################################
  2314.     def Sort_Paths(self,ecoords,i_loop=2):
  2315.         ##########################
  2316.         ###   find loop ends   ###
  2317.         ##########################
  2318.         Lbeg=[]
  2319.         Lend=[]
  2320.         if len(ecoords)>0:
  2321.             Lbeg.append(0)
  2322.             loop_old=ecoords[0][i_loop]
  2323.             for i in range(1,len(ecoords)):
  2324.                 loop = ecoords[i][i_loop]
  2325.                 if loop != loop_old:
  2326.                     Lbeg.append(i)
  2327.                     Lend.append(i-1)
  2328.                 loop_old=loop
  2329.             Lend.append(i)
  2330.  
  2331.         #######################################################
  2332.         # Find new order based on distance to next beg or end #
  2333.         #######################################################
  2334.         order_out = []
  2335.         use_beg=0
  2336.         if len(ecoords)>0:
  2337.             order_out.append([Lbeg[0],Lend[0]])
  2338.         inext = 0
  2339.         total=len(Lbeg)
  2340.         for i in range(total-1):
  2341.             if use_beg==1:
  2342.                 ii=Lbeg.pop(inext)
  2343.                 Lend.pop(inext)
  2344.             else:
  2345.                 ii=Lend.pop(inext)
  2346.                 Lbeg.pop(inext)
  2347.  
  2348.             Xcur = ecoords[ii][0]
  2349.             Ycur = ecoords[ii][1]
  2350.  
  2351.             dx = Xcur - ecoords[ Lbeg[0] ][0]
  2352.             dy = Ycur - ecoords[ Lbeg[0] ][1]
  2353.             min_dist = dx*dx + dy*dy
  2354.  
  2355.             dxe = Xcur - ecoords[ Lend[0] ][0]
  2356.             dye = Ycur - ecoords[ Lend[0] ][1]
  2357.             min_diste = dxe*dxe + dye*dye
  2358.  
  2359.             inext=0
  2360.             inexte=0
  2361.             for j in range(1,len(Lbeg)):
  2362.                 dx = Xcur - ecoords[ Lbeg[j] ][0]
  2363.                 dy = Ycur - ecoords[ Lbeg[j] ][1]
  2364.                 dist = dx*dx + dy*dy
  2365.                 if dist < min_dist:
  2366.                     min_dist=dist
  2367.                     inext=j
  2368.                 ###
  2369.                 dxe = Xcur - ecoords[ Lend[j] ][0]
  2370.                 dye = Ycur - ecoords[ Lend[j] ][1]
  2371.                 diste = dxe*dxe + dye*dye
  2372.                 if diste < min_diste:
  2373.                     min_diste=diste
  2374.                     inexte=j
  2375.                 ###
  2376.             if min_diste < min_dist:
  2377.                 inext=inexte
  2378.                 order_out.append([Lend[inexte],Lbeg[inexte]])
  2379.                 use_beg=1
  2380.             else:
  2381.                 order_out.append([Lbeg[inext],Lend[inext]])
  2382.                 use_beg=0
  2383.         ###########################################################
  2384.         return order_out
  2385.    
  2386.     #####################################################
  2387.     # determine if a point is inside a given polygon or not
  2388.     # Polygon is a list of (x,y) pairs.
  2389.     # http://www.ariel.com.au/a/python-point-int-poly.html
  2390.     #####################################################
  2391.     def point_inside_polygon(self,x,y,poly):
  2392.         n = len(poly)
  2393.         inside = -1
  2394.         p1x = poly[0][0]
  2395.         p1y = poly[0][1]
  2396.         for i in range(n+1):
  2397.             p2x = poly[i%n][0]
  2398.             p2y = poly[i%n][1]
  2399.             if y > min(p1y,p2y):
  2400.                 if y <= max(p1y,p2y):
  2401.                     if x <= max(p1x,p2x):
  2402.                         if p1y != p2y:
  2403.                             xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
  2404.                         if p1x == p2x or x <= xinters:
  2405.                             inside = inside * -1
  2406.             p1x,p1y = p2x,p2y
  2407.  
  2408.         return inside
  2409.  
  2410.     def optimize_paths(self,ecoords):
  2411.         order_out = self.Sort_Paths(ecoords)
  2412.         lastx=-999
  2413.         lasty=-999
  2414.         Acc=0.004
  2415.         cuts=[]
  2416.  
  2417.         for line in order_out:
  2418.             temp=line
  2419.             if temp[0] > temp[1]:
  2420.                 step = -1
  2421.             else:
  2422.                 step = 1
  2423.  
  2424.             loop_old = -1
  2425.            
  2426.             for i in range(temp[0],temp[1]+step,step):
  2427.                 x1   = ecoords[i][0]
  2428.                 y1   = ecoords[i][1]
  2429.                 loop = ecoords[i][2]
  2430.                 # check and see if we need to move to a new discontinuous start point
  2431.                 if (loop != loop_old):
  2432.                     dx = x1-lastx
  2433.                     dy = y1-lasty
  2434.                     dist = sqrt(dx*dx + dy*dy)
  2435.                     if dist > Acc:
  2436.                         cuts.append([[x1,y1]])
  2437.                     else:
  2438.                         cuts[-1].append([x1,y1])
  2439.                 else:
  2440.                     cuts[-1].append([x1,y1])
  2441.                 lastx = x1
  2442.                 lasty = y1
  2443.                 loop_old = loop
  2444.         #####################################################
  2445.         # For each loop determine if other loops are inside #
  2446.         #####################################################
  2447.         Nloops=len(cuts)
  2448.         self.LoopTree=[]
  2449.         for iloop in range(Nloops):
  2450.             self.LoopTree.append([])
  2451. ##            CUR_PCT=float(iloop)/Nloops*100.0
  2452. ##            if (not self.batch.get()):
  2453. ##                self.statusMessage.set('Determining Which Side of Loop to Cut: %d of %d' %(iloop+1,Nloops))
  2454. ##                self.master.update()
  2455.             ipoly = cuts[iloop]
  2456.             ## Check points in other loops (could just check one) ##
  2457.             if ipoly != []:
  2458.                 for jloop in range(Nloops):
  2459.                     if jloop != iloop:
  2460.                         inside = 0
  2461.                         inside = inside + self.point_inside_polygon(cuts[jloop][0][0],cuts[jloop][0][1],ipoly)
  2462.                         if inside > 0:
  2463.                             self.LoopTree[iloop].append(jloop)
  2464.         #####################################################
  2465.         for i in range(Nloops):
  2466.             lns=[]
  2467.             lns.append(i)
  2468.             self.remove_self_references(lns,self.LoopTree[i])
  2469.  
  2470.         self.order=[]
  2471.         self.loops = range(Nloops)
  2472.         for i in range(Nloops):
  2473.             if self.LoopTree[i]!=[]:
  2474.                 self.addlist(self.LoopTree[i])
  2475.                 self.LoopTree[i]=[]
  2476.             if self.loops[i]!=[]:
  2477.                 self.order.append(self.loops[i])
  2478.                 self.loops[i]=[]
  2479.         ecoords_out = []
  2480.         for i in self.order:
  2481.             line = cuts[i]
  2482.             for coord in line:
  2483.                 ecoords_out.append([coord[0],coord[1],i])
  2484.         return ecoords_out
  2485.            
  2486.     def remove_self_references(self,loop_numbers,loops):
  2487.         for i in range(0,len(loops)):
  2488.             for j in range(0,len(loop_numbers)):
  2489.                 if loops[i]==loop_numbers[j]:
  2490.                     loops.pop(i)
  2491.                     return
  2492.             if self.LoopTree[loops[i]]!=[]:
  2493.                 loop_numbers.append(loops[i])
  2494.                 self.remove_self_references(loop_numbers,self.LoopTree[loops[i]])
  2495.  
  2496.     def addlist(self,list):
  2497.         for i in list:
  2498.             try: #this try/except is a bad hack fix to a recursion error. It should be fixed properly later.
  2499.                 if self.LoopTree[i]!=[]:
  2500.                     self.addlist(self.LoopTree[i]) #too many recursions here causes cmp error
  2501.                     self.LoopTree[i]=[]
  2502.             except:
  2503.                 pass
  2504.             if self.loops[i]!=[]:
  2505.                 self.order.append(self.loops[i])
  2506.                 self.loops[i]=[]
  2507.  
  2508.  
  2509.     def mirror_rotate_vector_coords(self,coords):
  2510.         xmin = self.Design_bounds[0]
  2511.         xmax = self.Design_bounds[1]
  2512.         coords_rotate_mirror=[]
  2513.        
  2514.         for i in range(len(coords)):
  2515.             coords_rotate_mirror.append(coords[i][:])
  2516.             if self.mirror.get():
  2517.                 coords_rotate_mirror[i][0]=xmin+xmax-coords_rotate_mirror[i][0]
  2518.             if self.rotate.get():
  2519.                 x = coords_rotate_mirror[i][0]
  2520.                 y = coords_rotate_mirror[i][1]
  2521.                 coords_rotate_mirror[i][0] = -y
  2522.                 coords_rotate_mirror[i][1] =  x
  2523.                
  2524.         return coords_rotate_mirror
  2525.  
  2526.     def scale_vector_coords(self,coords,startx,starty):
  2527.         Xscale = float(self.LaserXscale.get())
  2528.         Yscale = float(self.LaserYscale.get())
  2529.         coords_scale=[]
  2530.         if Xscale != 1.0 or Yscale != 1.0:
  2531.             for i in range(len(coords)):
  2532.                 coords_scale.append(coords[i][:])
  2533.                 x = coords_scale[i][0]
  2534.                 y = coords_scale[i][1]
  2535.                 coords_scale[i][0] = x*Xscale
  2536.                 coords_scale[i][1] = y*Yscale
  2537.             scaled_startx = startx*Xscale
  2538.             scaled_starty = starty*Yscale
  2539.         else:
  2540.             coords_scale = coords
  2541.             scaled_startx = startx
  2542.             scaled_starty = starty
  2543.  
  2544.         return coords_scale,scaled_startx,scaled_starty
  2545.  
  2546.     def send_data(self,operation_type=None):
  2547.         if self.k40 == None:
  2548.             self.statusMessage.set("Laser Cutter is not Initialized...")
  2549.             self.statusbar.configure( bg = 'red' )
  2550.             return
  2551.        
  2552.         try:
  2553.             if self.units.get()=='in':
  2554.                 feed_factor = 25.4/60.0
  2555.             else:
  2556.                 feed_factor = 1.0
  2557.                
  2558.             if self.inputCSYS.get() and self.RengData.image == None:
  2559.                 xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  2560.             else:
  2561.                 xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2562.            
  2563.  
  2564.             self.move_head_window_temporary([0,0])
  2565.             startx = xmin
  2566.             starty = ymax
  2567.  
  2568.             if self.HomeUR.get():
  2569.                 FlipXoffset = abs(xmax-xmin)
  2570.                 if self.rotate.get():
  2571.                     startx = -xmin
  2572.             else:
  2573.                 FlipXoffset = 0
  2574.            
  2575.             data=[]
  2576.             egv_inst = egv(target=lambda s:data.append(s))
  2577.            
  2578.             if (operation_type=="Vector_Cut") and  (self.VcutData.ecoords!=[]):
  2579.                 num_passes = int(self.Vcut_passes.get())
  2580.                 Feed_Rate = float(self.Vcut_feed.get())*feed_factor
  2581.                 self.statusMessage.set("Vector Cut: Determining Cut Order....")
  2582.                 self.master.update()
  2583.                 if not self.VcutData.sorted and self.inside_first.get():
  2584.                     self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True)
  2585.                 self.statusMessage.set("Generating EGV data...")
  2586.                 self.master.update()
  2587.  
  2588.                 Vcut_coords = self.VcutData.ecoords
  2589.                 if self.mirror.get() or self.rotate.get():
  2590.                     Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords)
  2591.  
  2592.                 Vcut_coords,startx,starty = self.scale_vector_coords(Vcut_coords,startx,starty)
  2593.                    
  2594.                 egv_inst.make_egv_data(
  2595.                                                 Vcut_coords,                      \
  2596.                                                 startX=startx,                    \
  2597.                                                 startY=starty,                    \
  2598.                                                 Feed = Feed_Rate,                 \
  2599.                                                 board_name=self.board_name.get(), \
  2600.                                                 Raster_step = 0,                  \
  2601.                                                 update_gui=self.update_gui,       \
  2602.                                                 stop_calc=self.stop,              \
  2603.                                                 FlipXoffset=FlipXoffset
  2604.                                                 )
  2605.  
  2606.  
  2607.             if (operation_type=="Vector_Eng") and  (self.VengData.ecoords!=[]):
  2608.                 num_passes = int(self.Veng_passes.get())
  2609.                 Feed_Rate = float(self.Veng_feed.get())*feed_factor
  2610.                 self.statusMessage.set("Vector Engrave: Determining Cut Order....")
  2611.                 self.master.update()
  2612.                 if not self.VengData.sorted and self.inside_first.get():
  2613.                     self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords),data_sorted=True)
  2614.                 self.statusMessage.set("Generating EGV data...")
  2615.                 self.master.update()
  2616.  
  2617.                 Veng_coords = self.VengData.ecoords
  2618.                 if self.mirror.get() or self.rotate.get():
  2619.                     Veng_coords = self.mirror_rotate_vector_coords(Veng_coords)
  2620.  
  2621.                 Veng_coords,startx,starty = self.scale_vector_coords(Veng_coords,startx,starty)
  2622.                    
  2623.                 egv_inst.make_egv_data(
  2624.                                                 Veng_coords,                      \
  2625.                                                 startX=startx,                    \
  2626.                                                 startY=starty,                    \
  2627.                                                 Feed = Feed_Rate,                 \
  2628.                                                 board_name=self.board_name.get(), \
  2629.                                                 Raster_step = 0,                  \
  2630.                                                 update_gui=self.update_gui,       \
  2631.                                                 stop_calc=self.stop,              \
  2632.                                                 FlipXoffset=FlipXoffset
  2633.                                                 )
  2634.  
  2635.             if (operation_type=="Raster_Eng") and  (self.RengData.ecoords!=[]):
  2636.                 num_passes = int(self.Reng_passes.get())
  2637.                 Feed_Rate = float(self.Reng_feed.get())*feed_factor
  2638.                 Raster_step = self.get_raster_step_1000in()
  2639.                 if not self.engraveUP.get():
  2640.                     Raster_step = -Raster_step
  2641.                    
  2642.                 raster_startx = 0
  2643.                 raster_starty = float(self.LaserYscale.get())*starty
  2644.  
  2645.                 self.statusMessage.set("Generating EGV data...")
  2646.                 self.master.update()
  2647.                 egv_inst.make_egv_data(
  2648.                                                 self.RengData.ecoords,            \
  2649.                                                 startX=raster_startx,             \
  2650.                                                 startY=raster_starty,             \
  2651.                                                 Feed = Feed_Rate,                 \
  2652.                                                 board_name=self.board_name.get(), \
  2653.                                                 Raster_step = Raster_step,        \
  2654.                                                 update_gui=self.update_gui,       \
  2655.                                                 stop_calc=self.stop,              \
  2656.                                                 FlipXoffset=FlipXoffset
  2657.                                                 )
  2658.                
  2659.                 self.Reng=[]
  2660.  
  2661.             if (operation_type=="Gcode_Cut") and (self.GcodeData!=[]):
  2662.                 num_passes = int(self.Gcde_passes.get())
  2663.                 self.statusMessage.set("Generating EGV data...")
  2664.                 self.master.update()
  2665.  
  2666.                 Gcode_coords = self.GcodeData.ecoords
  2667.                 if self.mirror.get() or self.rotate.get():
  2668.                     Gcode_coords = self.mirror_rotate_vector_coords(Gcode_coords)
  2669.  
  2670.                 Gcode_coords,startx,starty = self.scale_vector_coords(Gcode_coords,startx,starty)
  2671.                
  2672.                 egv_inst.make_egv_data(
  2673.                                                 Gcode_coords,                     \
  2674.                                                 startX=startx,                    \
  2675.                                                 startY=starty,                    \
  2676.                                                 Feed = None,                      \
  2677.                                                 board_name=self.board_name.get(), \
  2678.                                                 Raster_step = 0,                  \
  2679.                                                 update_gui=self.update_gui,       \
  2680.                                                 stop_calc=self.stop,              \
  2681.                                                 FlipXoffset=FlipXoffset
  2682.                                                 )
  2683.                
  2684.             self.master.update()
  2685.             self.send_egv_data(data, num_passes)
  2686.             self.menu_View_Refresh()
  2687.         except MemoryError as e:
  2688.             raise StandardError("Memory Error:  Out of Memory.")
  2689.             debug_message(traceback.format_exc())
  2690.        
  2691.         except StandardError as e:
  2692.             msg1 = "Sending Data Stopped: "
  2693.             msg2 = "%s" %(e)
  2694.             if msg2 == "":
  2695.                 formatted_lines = traceback.format_exc().splitlines()
  2696.             self.statusMessage.set((msg1+msg2).split("\n")[0] )
  2697.             self.statusbar.configure( bg = 'red' )
  2698.             message_box(msg1, msg2)
  2699.             debug_message(traceback.format_exc())
  2700.  
  2701.     def send_egv_data(self,data,num_passes=1):
  2702.         pre_process_CRC        = self.pre_pr_crc.get()
  2703.         if self.k40 != None:
  2704.             self.k40.timeout       = int(self.t_timeout.get())  
  2705.             self.k40.n_timeouts    = int(self.n_timeouts.get())
  2706.             self.k40.send_data(data,self.update_gui,self.stop,num_passes,pre_process_CRC)
  2707.         else:
  2708.             self.master.update()
  2709.        
  2710.         if DEBUG:
  2711.             print "Saving Data to File...."
  2712.             self.write_egv_to_file(data)
  2713.         #self.set_gui("normal")
  2714.         self.menu_View_Refresh()
  2715.        
  2716.     ##########################################################################
  2717.     ##########################################################################
  2718.     def write_egv_to_file(self,data):
  2719.         try:
  2720.             fname = os.path.expanduser("~")+"/EGV_DATA.EGV"
  2721.             fout = open(fname,'w')
  2722.         except:
  2723.             self.statusMessage.set("Unable to open file for writing: %s" %(fname))
  2724.             return
  2725.         for char_val in data:
  2726.             char = chr(char_val)
  2727.             if char == "N":
  2728.                 fout.write("\n")
  2729.                 fout.write("%s" %(char))
  2730.             elif char == "E":
  2731.                 fout.write("%s" %(char))
  2732.                 fout.write("\n")
  2733.             else:
  2734.                 fout.write("%s" %(char))
  2735.         fout.write("\n")
  2736.         fout.close
  2737.        
  2738.     def Home(self):
  2739.         if self.k40 != None:
  2740.             self.k40.home_position()
  2741.         self.laserX  = 0.0
  2742.         self.laserY  = 0.0
  2743.         self.pos_offset = [0.0,0.0]
  2744.         self.menu_View_Refresh()
  2745.  
  2746.     def GoTo(self):
  2747.         xpos = float(self.gotoX.get())
  2748.         ypos = float(self.gotoY.get())
  2749.         if self.k40 != None:
  2750.             self.k40.home_position()
  2751.         self.laserX  = 0.0
  2752.         self.laserY  = 0.0
  2753.         self.Rapid_Move(xpos,ypos)
  2754.         self.menu_View_Refresh()  
  2755.        
  2756.     def Reset(self):
  2757.         if self.k40 != None:
  2758.             try:
  2759.                 self.k40.reset_usb()
  2760.                 self.statusMessage.set("USB Reset Succeeded")
  2761.             except:
  2762.                 debug_message(traceback.format_exc())
  2763.                 pass
  2764.            
  2765.     def Stop(self,event=None):
  2766.         line1 = "The K40 Whisperer is currently Paused."
  2767.         line2 = "Press \"OK\" to stop current action."
  2768.         line3 = "Press \"Cancel\" to resume."
  2769.         if message_ask_ok_cancel("Stop Laser Job.", "%s\n\n%s\n%s" %(line1,line2,line3)):
  2770.             self.stop[0]=True
  2771.            
  2772.     def CLI_Stop(self,event=None):
  2773.         self.stop[0]=True
  2774.         print ("Print halted")
  2775.    
  2776.     def Hide_Advanced(self,event=None):
  2777.         self.advanced.set(0)
  2778.         self.menu_View_Refresh()
  2779.  
  2780.     def Release_USB(self):
  2781.         if self.k40 != None:
  2782.             try:
  2783.                 self.k40.release_usb()
  2784.                 self.statusMessage.set("USB Release Succeeded")
  2785.             except:
  2786.                 debug_message(traceback.format_exc())
  2787.                 pass
  2788.             self.k40=None
  2789.        
  2790.     def Initialize_Laser(self,junk=None):
  2791.         self.stop[0]=False
  2792.         self.Release_USB()
  2793.         self.k40=None
  2794.         self.move_head_window_temporary([0.0,0.0])      
  2795.         self.k40=K40_CLASS()
  2796.         try:
  2797.             self.k40.initialize_device()
  2798.             self.k40.say_hello()
  2799.             if self.init_home.get():
  2800.                 self.Home()
  2801.             else:
  2802.                 self.Unlock()
  2803.            
  2804.         except StandardError as e:
  2805.             error_text = "%s" %(e)
  2806.             if "BACKEND" in error_text.upper():
  2807.                 error_text = error_text + " (libUSB driver not installed)"
  2808.             self.statusMessage.set("USB Error: %s" %(error_text))
  2809.             self.statusbar.configure( bg = 'red' )
  2810.             self.k40=None
  2811.             debug_message(traceback.format_exc())
  2812.  
  2813.         except:
  2814.             self.statusMessage.set("Unknown USB Error")
  2815.             self.statusbar.configure( bg = 'red' )
  2816.             self.k40=None
  2817.             debug_message(traceback.format_exc())
  2818.            
  2819.     def Unlock(self):
  2820.         if self.k40 != None:
  2821.             try:
  2822.                 self.k40.unlock_rail()
  2823.                 self.statusMessage.set("Rail Unlock Succeeded")
  2824.                 self.statusbar.configure( bg = 'white' )
  2825.             except:
  2826.                 self.statusMessage.set("Rail Unlock Failed.")
  2827.                 self.statusbar.configure( bg = 'red' )
  2828.                 debug_message(traceback.format_exc())
  2829.                 pass
  2830.    
  2831.     ##########################################################################
  2832.     ##########################################################################
  2833.            
  2834.     def menu_File_Quit(self):
  2835.         if message_ask_ok_cancel("Exit", "Exiting...."):
  2836.             self.Quit_Click(None)
  2837.  
  2838.     def menu_View_Mirror_Refresh_Callback(self, varName, index, mode):
  2839.         self.RengData.reset_path()
  2840.         self.SCALE = 0
  2841.         self.menu_View_Refresh()
  2842.  
  2843.     def menu_View_inputCSYS_Refresh_Callback(self, varName, index, mode):
  2844.         self.move_head_window_temporary([0.0,0.0])
  2845.         self.SCALE = 0
  2846.         self.menu_View_Refresh()
  2847.  
  2848.     def menu_View_Refresh_Callback(self, varName, index, mode):
  2849.         self.SCALE = 0
  2850.         self.menu_View_Refresh()
  2851.  
  2852.     def menu_View_Refresh(self):
  2853.         try:
  2854.             app.master.title(title_text+"   "+ self.DESIGN_FILE)
  2855.         except:
  2856.             pass
  2857.         dummy_event = Event()
  2858.         dummy_event.widget=self.master
  2859.         self.Master_Configure(dummy_event,1)
  2860.         self.Plot_Data()
  2861.         xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  2862.         W = xmax-xmin
  2863.         H = ymax-ymin
  2864.  
  2865.         if self.units.get()=="in":
  2866.             X_display = self.laserX + self.pos_offset[0]/1000.0
  2867.             Y_display = self.laserY + self.pos_offset[1]/1000.0
  2868.             W_display = W
  2869.             H_display = H
  2870.             U_display = self.units.get()
  2871.         else:
  2872.             X_display = (self.laserX + self.pos_offset[0]/1000.0)*self.units_scale
  2873.             Y_display = (self.laserY + self.pos_offset[1]/1000.0)*self.units_scale
  2874.             W_display = W*self.units_scale
  2875.             H_display = H*self.units_scale
  2876.             U_display = self.units.get()
  2877.         if self.HomeUR.get():
  2878.             X_display = -X_display
  2879.  
  2880.         self.statusMessage.set(" Current Position: X=%.3f Y=%.3f    ( W X H )=( %.3f%s X %.3f%s ) "
  2881.                                 %(X_display,
  2882.                                   Y_display,
  2883.                                   W_display,
  2884.                                   U_display,
  2885.                                   H_display,
  2886.                                   U_display))
  2887.  
  2888.         self.statusbar.configure( bg = 'white' )
  2889.        
  2890.     def menu_Mode_Change_Callback(self, varName, index, mode):
  2891.         self.menu_View_Refresh()
  2892.  
  2893.     def menu_Inside_First_Callback(self, varName, index, mode):
  2894.         if self.GcodeData.ecoords != []:
  2895.             if self.VcutData.sorted == True:
  2896.                 self.menu_Reload_Design()
  2897.             elif self.VengData.sorted == True:
  2898.                 self.menu_Reload_Design()
  2899.        
  2900.  
  2901.     def menu_Mode_Change(self):
  2902.         dummy_event = Event()
  2903.         dummy_event.widget=self.master
  2904.         self.Master_Configure(dummy_event,1)
  2905.  
  2906.     def menu_View_Recalculate(self):
  2907.         pass
  2908.  
  2909.     def menu_Help_About(self):
  2910.         about = "K40 Whisperer by Scorch.\n"
  2911.         about = about + "\163\143\157\162\143\150\100\163\143\157\162"
  2912.         about = about + "\143\150\167\157\162\153\163\056\143\157\155\n"
  2913.         about = about + "http://www.scorchworks.com/"
  2914.         message_box("About k40_whisperer",about)
  2915.  
  2916.     def menu_Help_Web(self):
  2917.         webbrowser.open_new(r"http://www.scorchworks.com/K40whisperer/k40whisperer.html")
  2918.  
  2919.     def KEY_F1(self, event):
  2920.         self.menu_Help_About()
  2921.  
  2922.     def KEY_F5(self, event):
  2923.         self.menu_View_Refresh()
  2924.  
  2925.     def bindConfigure(self, event):
  2926.         if not self.initComplete:
  2927.             self.initComplete = 1
  2928.             self.menu_Mode_Change()
  2929.  
  2930.     def Master_Configure(self, event, update=0):
  2931.         if event.widget != self.master:
  2932.             return
  2933.         x = int(self.master.winfo_x())
  2934.         y = int(self.master.winfo_y())
  2935.         w = int(self.master.winfo_width())
  2936.         h = int(self.master.winfo_height())
  2937.         if (self.x, self.y) == (-1,-1):
  2938.             self.x, self.y = x,y
  2939.         if abs(self.w-w)>10 or abs(self.h-h)>10 or update==1:
  2940.             ###################################################
  2941.             #  Form changed Size (resized) adjust as required #
  2942.             ###################################################
  2943.             self.w=w
  2944.             self.h=h
  2945.  
  2946.             if True:                
  2947.                 # Left Column #
  2948.                 w_label=90
  2949.                 w_entry=48
  2950.                 w_units=52
  2951.  
  2952.                 x_label_L=10
  2953.                 x_entry_L=x_label_L+w_label+20-5
  2954.                 x_units_L=x_entry_L+w_entry+2
  2955.  
  2956.                 Yloc=15
  2957.                 self.Initialize_Button.place (x=12, y=Yloc, width=100*2, height=23)
  2958.                 Yloc=Yloc+33
  2959.  
  2960.                 self.Open_Button.place (x=12, y=Yloc, width=100, height=40)
  2961.                 self.Reload_Button.place(x=12+100, y=Yloc, width=100, height=40)                
  2962.  
  2963.                 Yloc=Yloc+50
  2964.                 self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2)
  2965.                 Yloc=Yloc+6
  2966.                 self.Label_Position_Control.place(x=x_label_L, y=Yloc, width=w_label*2, height=21)
  2967.  
  2968.                 Yloc=Yloc+25
  2969.                 self.Home_Button.place (x=12, y=Yloc, width=100, height=23)
  2970.                 self.UnLock_Button.place(x=12+100, y=Yloc, width=100, height=23)
  2971.  
  2972.                 Yloc=Yloc+33
  2973.                 self.Label_Step.place(x=x_label_L, y=Yloc, width=w_label, height=21)
  2974.                 self.Label_Step_u.place(x=x_units_L, y=Yloc, width=w_units, height=21)
  2975.                 self.Entry_Step.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
  2976.  
  2977.                 ###########################################################################
  2978.                 Yloc=Yloc+30
  2979.                 bsz=40
  2980.                 xoffst=35
  2981.                 self.UL_Button.place    (x=xoffst+12      ,  y=Yloc, width=bsz, height=bsz)
  2982.                 self.Up_Button.place    (x=xoffst+12+bsz  ,  y=Yloc, width=bsz, height=bsz)
  2983.                 self.UR_Button.place    (x=xoffst+12+bsz*2,  y=Yloc, width=bsz, height=bsz)
  2984.                 Yloc=Yloc+bsz
  2985.                 self.Left_Button.place  (x=xoffst+12      ,y=Yloc, width=bsz, height=bsz)
  2986.                 self.CC_Button.place    (x=xoffst+12+bsz  ,y=Yloc, width=bsz, height=bsz)
  2987.                 self.Right_Button.place (x=xoffst+12+bsz*2,y=Yloc, width=bsz, height=bsz)
  2988.                 Yloc=Yloc+bsz
  2989.                 self.LL_Button.place    (x=xoffst+12      ,  y=Yloc, width=bsz, height=bsz)
  2990.                 self.Down_Button.place  (x=xoffst+12+bsz  ,  y=Yloc, width=bsz, height=bsz)
  2991.                 self.LR_Button.place    (x=xoffst+12+bsz*2,  y=Yloc, width=bsz, height=bsz)
  2992.            
  2993.                
  2994.                 Yloc=Yloc+bsz
  2995.                 ###########################################################################
  2996.                 self.Label_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
  2997.                 self.Label_GoToY.place(x=x_units_L, y=Yloc, width=w_entry, height=23)
  2998.                 Yloc=Yloc+25
  2999.                 self.GoTo_Button.place (x=12, y=Yloc, width=100, height=23)
  3000.                 self.Entry_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23)
  3001.                 self.Entry_GoToY.place(x=x_units_L, y=Yloc, width=w_entry, height=23)
  3002.                 ###########################################################################
  3003.                            
  3004.  
  3005.                 #From Bottom up
  3006.                 BUinit = self.h-70
  3007.                 Yloc = BUinit
  3008.                 self.Stop_Button.place (x=12, y=Yloc, width=100*2, height=30)
  3009.                
  3010.                 self.Stop_Button.configure(bg='light coral')
  3011.                 Yloc=Yloc-10
  3012.  
  3013.                 wadv       = 220 #200
  3014.                 wadv_use   = wadv-20
  3015.                 Xvert_sep  = 220
  3016.                 Xadvanced  = Xvert_sep+10
  3017.                 w_label_adv= wadv-80 #  110 w_entry
  3018.  
  3019.                 if self.GcodeData.ecoords == []:
  3020.                     self.Grun_Button.place_forget()
  3021.                    
  3022.                     Yloc=Yloc-30
  3023.                     self.Vcut_Button.place  (x=12, y=Yloc, width=100, height=23)
  3024.                     self.Entry_Vcut_feed.place(  x=x_entry_L, y=Yloc, width=w_entry, height=23)
  3025.                     self.Label_Vcut_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
  3026.  
  3027.                     Yloc=Yloc-30
  3028.                     self.Veng_Button.place  (x=12, y=Yloc, width=100, height=23)
  3029.                     self.Entry_Veng_feed.place(  x=x_entry_L, y=Yloc, width=w_entry, height=23)
  3030.                     self.Label_Veng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)
  3031.                        
  3032.                     Yloc=Yloc-30
  3033.                     self.Reng_Button.place  (x=12, y=Yloc, width=100, height=23)
  3034.                     self.Entry_Reng_feed.place(  x=x_entry_L, y=Yloc, width=w_entry, height=23)
  3035.                     self.Label_Reng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23)  
  3036.                    
  3037.                 else:
  3038.                     self.Vcut_Button.place_forget()
  3039.                     self.Entry_Vcut_feed.place_forget()
  3040.                     self.Label_Vcut_feed_u.place_forget()
  3041.                    
  3042.                     self.Veng_Button.place_forget()
  3043.                     self.Entry_Veng_feed.place_forget()
  3044.                     self.Label_Veng_feed_u.place_forget()
  3045.                    
  3046.                     self.Reng_Button.place_forget()
  3047.                     self.Entry_Reng_feed.place_forget()
  3048.                     self.Label_Reng_feed_u.place_forget()
  3049.                    
  3050.                     Yloc=Yloc-30
  3051.                     self.Grun_Button.place  (x=12, y=Yloc, width=100*2, height=23)
  3052.                    
  3053.                
  3054.                 Yloc=Yloc-15
  3055.                 self.separator2.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2)
  3056.                 # End Left Column #
  3057.  
  3058.                 if self.advanced.get():
  3059.                    
  3060.                     self.PreviewCanvas.configure( width = self.w-240-wadv, height = self.h-50 )
  3061.                     self.PreviewCanvas_frame.place(x=220+wadv, y=10)
  3062.                     self.separator_vert.place(x=220, y=10,width=2, height=self.h-50)
  3063.  
  3064.                     adv_Yloc=15
  3065.                     self.Label_Advanced_column.place(x=Xadvanced, y=adv_Yloc, width=wadv_use, height=21)
  3066.                     adv_Yloc=adv_Yloc+25
  3067.                     self.separator_adv.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2)
  3068.  
  3069.                     adv_Yloc=adv_Yloc+15
  3070.                     self.Label_Halftone_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3071.                     self.Checkbutton_Halftone_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  3072.  
  3073.                     adv_Yloc=adv_Yloc+25
  3074.                     self.Label_Mirror_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3075.                     self.Checkbutton_Mirror_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  3076.  
  3077.                     adv_Yloc=adv_Yloc+25
  3078.                     self.Label_Rotate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3079.                     self.Checkbutton_Rotate_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  3080.  
  3081.                     adv_Yloc=adv_Yloc+25
  3082.                     self.Label_inputCSYS_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3083.                     self.Checkbutton_inputCSYS_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  3084.  
  3085.                     adv_Yloc=adv_Yloc+25
  3086.                     self.Label_Inside_First_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3087.                     self.Checkbutton_Inside_First_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23)
  3088.  
  3089.                     adv_Yloc = BUinit
  3090.                     self.Hide_Adv_Button.place (x=Xadvanced, y=adv_Yloc, width=wadv_use, height=30)
  3091.  
  3092.                     if self.RengData.image != None:
  3093.                         self.Label_inputCSYS_adv.configure(state="disabled")
  3094.                         self.Checkbutton_inputCSYS_adv.place_forget()              
  3095.                     else:
  3096.                         self.Label_inputCSYS_adv.configure(state="normal")
  3097.                        
  3098.                     if self.GcodeData.ecoords == []:
  3099.                         adv_Yloc = adv_Yloc-40
  3100.                         self.Label_Vcut_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3101.                         self.Entry_Vcut_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23)
  3102.                         adv_Yloc=adv_Yloc-30
  3103.                         self.Label_Veng_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3104.                         self.Entry_Veng_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23)
  3105.                         adv_Yloc=adv_Yloc-30
  3106.                         self.Label_Reng_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3107.                         self.Entry_Reng_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23)
  3108.                         self.Label_Gcde_passes.place_forget()
  3109.                         self.Entry_Gcde_passes.place_forget()
  3110.                     else:
  3111.                         adv_Yloc=adv_Yloc-40
  3112.                         self.Label_Gcde_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21)
  3113.                         self.Entry_Gcde_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23)
  3114.                         self.Label_Vcut_passes.place_forget()
  3115.                         self.Entry_Vcut_passes.place_forget()
  3116.                         self.Label_Veng_passes.place_forget()
  3117.                         self.Entry_Veng_passes.place_forget()
  3118.                         self.Label_Reng_passes.place_forget()
  3119.                         self.Entry_Reng_passes.place_forget()
  3120.  
  3121.                 else:
  3122.                     self.PreviewCanvas_frame.place_forget()
  3123.                     self.separator_vert.place_forget()
  3124.                     self.Label_Advanced_column.place_forget()
  3125.                     self.separator_adv.place_forget()
  3126.                     self.Label_Halftone_adv.place_forget()
  3127.                     self.Checkbutton_Halftone_adv.place_forget()
  3128.                     self.Label_Mirror_adv.place_forget()
  3129.                     self.Checkbutton_Mirror_adv.place_forget()
  3130.                     self.Label_Rotate_adv.place_forget()
  3131.                     self.Checkbutton_Rotate_adv.place_forget()
  3132.                     self.Label_inputCSYS_adv.place_forget()
  3133.                     self.Checkbutton_inputCSYS_adv.place_forget()
  3134.                    
  3135.                     self.Label_Inside_First_adv.place_forget()
  3136.                     self.Checkbutton_Inside_First_adv.place_forget()
  3137.  
  3138.                     self.Entry_Vcut_passes.place_forget()
  3139.                     self.Label_Vcut_passes.place_forget()
  3140.                     self.Entry_Veng_passes.place_forget()
  3141.                     self.Label_Veng_passes.place_forget()
  3142.                     self.Entry_Reng_passes.place_forget()
  3143.                     self.Label_Reng_passes.place_forget()
  3144.                     self.Label_Gcde_passes.place_forget()
  3145.                     self.Entry_Gcde_passes.place_forget()
  3146.                     self.Hide_Adv_Button.place_forget()
  3147.                    
  3148.                     self.PreviewCanvas.configure( width = self.w-240, height = self.h-50 )
  3149.                     self.PreviewCanvas_frame.place(x=Xvert_sep, y=10)
  3150.                     self.separator_vert.place_forget()
  3151.  
  3152.                 self.Set_Input_States()
  3153.                
  3154.             self.Plot_Data()
  3155.            
  3156.     def Recalculate_RQD_Click(self, event):
  3157.         self.menu_View_Refresh()
  3158.  
  3159.     def Set_Input_States(self):
  3160.         pass
  3161.            
  3162.     def Set_Input_States_Event(self,event):
  3163.         self.Set_Input_States()
  3164.  
  3165.     def Set_Input_States_RASTER(self):
  3166.         if self.halftone.get():
  3167.             self.Label_Halftone_DPI.configure(state="normal")
  3168.             self.Halftone_DPI_OptionMenu.configure(state="normal")
  3169.             self.Label_Halftone_u.configure(state="normal")
  3170.             self.Label_bezier_M1.configure(state="normal")
  3171.             self.bezier_M1_Slider.configure(state="normal")
  3172.             self.Label_bezier_M2.configure(state="normal")
  3173.             self.bezier_M2_Slider.configure(state="normal")
  3174.             self.Label_bezier_weight.configure(state="normal")
  3175.             self.bezier_weight_Slider.configure(state="normal")
  3176.         else:
  3177.             self.Label_Halftone_DPI.configure(state="disabled")
  3178.             self.Halftone_DPI_OptionMenu.configure(state="disabled")
  3179.             self.Label_Halftone_u.configure(state="disabled")
  3180.             self.Label_bezier_M1.configure(state="disabled")
  3181.             self.bezier_M1_Slider.configure(state="disabled")
  3182.             self.Label_bezier_M2.configure(state="disabled")
  3183.             self.bezier_M2_Slider.configure(state="disabled")
  3184.             self.Label_bezier_weight.configure(state="disabled")
  3185.             self.bezier_weight_Slider.configure(state="disabled")
  3186.  
  3187.            
  3188.     def Set_Input_States_RASTER_Event(self,event):
  3189.         self.Set_Input_States_RASTER()
  3190.  
  3191.     def Imaging_Free(self,image_in,bg="#ffffff"):
  3192.         image_in = image_in.convert('L')
  3193.         wim,him = image_in.size
  3194.         image_out=PhotoImage(width=wim,height=him)
  3195.         pixel=image_in.load()
  3196.         if bg!=None:
  3197.             image_out.put(bg, to=(0,0,wim,him))
  3198.         for y in range(0,him):
  3199.             for x in range(0,wim):
  3200.                 val=pixel[x,y]
  3201.                 if val!=255:
  3202.                     image_out.put("#%02x%02x%02x" %(val,val,val),(x,y))
  3203.         return image_out
  3204.  
  3205.     ##########################################
  3206.     #        CANVAS PLOTTING STUFF           #
  3207.     ##########################################
  3208.     def Plot_Data(self):
  3209.         self.PreviewCanvas.delete(ALL)
  3210.         if (self.Check_All_Variables() > 0):
  3211.             return
  3212.  
  3213.         for seg in self.segID:
  3214.             self.PreviewCanvas.delete(seg)
  3215.         self.segID = []
  3216.        
  3217.         cszw = int(self.PreviewCanvas.cget("width"))
  3218.         cszh = int(self.PreviewCanvas.cget("height"))
  3219.         buff=10
  3220.         wc = float(cszw/2)
  3221.         hc = float(cszh/2)        
  3222.        
  3223.         maxx = float(self.LaserXsize.get()) / self.units_scale
  3224.         minx = 0.0
  3225.         maxy = 0.0
  3226.         miny = -float(self.LaserYsize.get()) / self.units_scale
  3227.         midx=(maxx+minx)/2
  3228.         midy=(maxy+miny)/2
  3229.        
  3230.         self.PlotScale = max((maxx-minx)/(cszw-buff), (maxy-miny)/(cszh-buff))
  3231.        
  3232.         x_lft = cszw/2 + (minx-midx) / self.PlotScale
  3233.         x_rgt = cszw/2 + (maxx-midx) / self.PlotScale
  3234.         y_bot = cszh/2 + (maxy-midy) / self.PlotScale
  3235.         y_top = cszh/2 + (miny-midy) / self.PlotScale
  3236.         self.segID.append( self.PreviewCanvas.create_rectangle(
  3237.                     x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) )
  3238.  
  3239.         if self.inputCSYS.get() and self.RengData.image == None:
  3240.             xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0
  3241.         else:
  3242.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()          
  3243.                
  3244.         if (self.HomeUR.get()):
  3245.             XlineShift = maxx - self.laserX - (xmax-xmin)
  3246.         else:
  3247.             XlineShift = self.laserX
  3248.         YlineShift = self.laserY    
  3249.  
  3250.         ######################################
  3251.         ###       Plot Raster Image        ###
  3252.         ######################################
  3253.         if self.RengData.image != None:
  3254.             if self.include_Reng.get():  
  3255.                 try:
  3256.                     new_SCALE = (1.0/self.PlotScale)/self.input_dpi
  3257.                     if new_SCALE != self.SCALE:
  3258.                         self.SCALE = new_SCALE
  3259.                         nw=int(self.SCALE*self.wim)
  3260.                         nh=int(self.SCALE*self.him)
  3261.                         #PIL_im = PIL_im.convert("1") #"1"=1BBP, "L"=grey
  3262.                         if self.halftone.get() == False:
  3263.                             plot_im = self.RengData.image.convert("L")
  3264.                             plot_im = plot_im.point(lambda x: 0 if x<128 else 255, '1')
  3265.                         else:
  3266.                             plot_im = self.RengData.image
  3267.  
  3268.                         if self.mirror.get():
  3269.                             plot_im = ImageOps.mirror(plot_im)
  3270.  
  3271.                         if self.rotate.get():
  3272.                             plot_im = plot_im.rotate(90,expand=True)
  3273.                             nh=int(self.SCALE*self.wim)
  3274.                             nw=int(self.SCALE*self.him)
  3275.                            
  3276.                         try:
  3277.                             self.UI_image = ImageTk.PhotoImage(plot_im.resize((nw,nh), Image.ANTIALIAS))
  3278.                         except:
  3279.                             debug_message("Imaging_Free Used.")
  3280.                             self.UI_image = self.Imaging_Free(plot_im.resize((nw,nh), Image.ANTIALIAS))
  3281.                 except:
  3282.                     self.SCALE = 1
  3283.                     debug_message(traceback.format_exc())
  3284.                    
  3285.                 self.Plot_Raster(self.laserX, self.laserY, x_lft,y_top,self.PlotScale,im=self.UI_image)
  3286.         else:
  3287.             self.UI_image = None
  3288.  
  3289.  
  3290.         ######################################
  3291.         ###       Plot Reng Coords         ###
  3292.         ######################################
  3293.         if self.include_Rpth.get() and self.RengData.ecoords!=[]:
  3294.             loop_old = -1
  3295.             scale = 1
  3296.  
  3297.             for line in self.RengData.ecoords:
  3298.                 XY    = line
  3299.                 x1    = (XY[0]-xmin)*scale
  3300.                 y1    = (XY[1]-ymax)*scale
  3301.  
  3302.                 loop  = XY[2]
  3303.                 color = "black"
  3304.                 # check and see if we need to move to a new discontinuous start point
  3305.                 if (loop == loop_old):
  3306.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, color)
  3307.                 loop_old = loop
  3308.                 xold=x1
  3309.                 yold=y1
  3310.  
  3311.            
  3312.         ######################################
  3313.         ###       Plot Veng Coords         ###
  3314.         ######################################
  3315.         if self.include_Veng.get():
  3316.             loop_old = -1
  3317.             scale=1
  3318.  
  3319.             plot_coords = self.VengData.ecoords
  3320.             if self.mirror.get() or self.rotate.get():
  3321.                 plot_coords = self.mirror_rotate_vector_coords(plot_coords)
  3322.                
  3323.             for line in plot_coords:
  3324.                 XY    = line
  3325.                 x1    = (XY[0]-xmin)*scale
  3326.                 y1    = (XY[1]-ymax)*scale
  3327.                 loop  = XY[2]
  3328.                 # check and see if we need to move to a new discontinuous start point
  3329.                 if (loop == loop_old):
  3330.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "blue")
  3331.                 loop_old = loop
  3332.                 xold=x1
  3333.                 yold=y1
  3334.  
  3335.         ######################################
  3336.         ###       Plot Vcut Coords         ###
  3337.         ######################################
  3338.         if self.include_Vcut.get():
  3339.             loop_old = -1
  3340.             scale=1
  3341.  
  3342.             plot_coords = self.VcutData.ecoords
  3343.             if self.mirror.get() or self.rotate.get():
  3344.                     plot_coords = self.mirror_rotate_vector_coords(plot_coords)
  3345.                
  3346.             for line in plot_coords:
  3347.                 XY    = line
  3348.                 x1    = (XY[0]-xmin)*scale
  3349.                 y1    = (XY[1]-ymax)*scale
  3350.  
  3351.                 loop  = XY[2]
  3352.                 # check and see if we need to move to a new discontinuous start point
  3353.                 if (loop == loop_old):
  3354.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "red")
  3355.                        
  3356.                    
  3357.                 loop_old = loop
  3358.                 xold=x1
  3359.                 yold=y1
  3360.  
  3361.         ######################################
  3362.         ###       Plot Gcode Coords        ###
  3363.         ######################################
  3364.         if self.include_Gcde.get():  
  3365.             loop_old = -1
  3366.             scale=1
  3367.  
  3368.             plot_coords = self.GcodeData.ecoords
  3369.             if self.mirror.get() or self.rotate.get():
  3370.                     plot_coords = self.mirror_rotate_vector_coords(plot_coords)
  3371.                
  3372.             for line in plot_coords:
  3373.                 XY    = line
  3374.                 x1    = (XY[0]-xmin)*scale
  3375.                 y1    = (XY[1]-ymax)*scale
  3376.  
  3377.                 loop  = XY[2]
  3378.                 # check and see if we need to move to a new discontinuous start point
  3379.                 if (loop == loop_old):
  3380.                     self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "white")
  3381.                 loop_old = loop
  3382.                 xold=x1
  3383.                 yold=y1
  3384.                
  3385.  
  3386.  
  3387.         ######################################            
  3388.         self.refreshTime()
  3389.         dot_col = "grey50"
  3390.         xoff = self.pos_offset[0]/1000.0
  3391.         yoff = self.pos_offset[1]/1000.0    
  3392.         self.Plot_circle(self.laserX+xoff,self.laserY+yoff,x_lft,y_top,self.PlotScale,dot_col,radius=5)
  3393.        
  3394.     def Plot_Raster(self, XX, YY, Xleft, Ytop, PlotScale, im):
  3395.         if (self.HomeUR.get()):
  3396.             maxx = float(self.LaserXsize.get()) / self.units_scale
  3397.             xmin,xmax,ymin,ymax = self.Get_Design_Bounds()
  3398.             xplt = Xleft + ( maxx-XX-(xmax-xmin) )/PlotScale
  3399.         else:
  3400.             xplt = Xleft +  XX/PlotScale
  3401.            
  3402.         yplt = Ytop  - YY/PlotScale
  3403.         self.segID.append(
  3404.             self.PreviewCanvas.create_image(xplt, yplt, anchor=NW, image=self.UI_image,tags='LaserTag')
  3405.             )
  3406.        
  3407.     def Plot_circle(self, XX, YY, Xleft, Ytop, PlotScale, col, radius=0):
  3408.         if (self.HomeUR.get()):
  3409.             maxx = float(self.LaserXsize.get()) / self.units_scale
  3410.             xplt = Xleft + maxx/PlotScale - XX/PlotScale
  3411.         else:
  3412.             xplt = Xleft + XX/PlotScale
  3413.         yplt = Ytop  - YY/PlotScale
  3414.         self.segID.append(
  3415.             self.PreviewCanvas.create_oval(
  3416.                                             xplt-radius,
  3417.                                             yplt-radius,
  3418.                                             xplt+radius,
  3419.                                             yplt+radius,
  3420.                                             fill=col, outline=col, width = 0,tags='LaserTag') )
  3421.  
  3422.     def Plot_Line(self, XX1, YY1, XX2, YY2, Xleft, Ytop, XlineShift, YlineShift, PlotScale, col, thick=0):
  3423.         xplt1 = Xleft + (XX1 + XlineShift )/PlotScale
  3424.         xplt2 = Xleft + (XX2 + XlineShift )/PlotScale
  3425.         yplt1 = Ytop  - (YY1 + YlineShift )/PlotScale
  3426.         yplt2 = Ytop  - (YY2 + YlineShift )/PlotScale
  3427.        
  3428.         self.segID.append(
  3429.             self.PreviewCanvas.create_line( xplt1,
  3430.                                             yplt1,
  3431.                                             xplt2,
  3432.                                             yplt2,
  3433.                                             fill=col, capstyle="round", width = thick, tags='LaserTag') )
  3434.        
  3435.     ################################################################################
  3436.     #                         Temporary Move Window                                #
  3437.     ################################################################################
  3438.     def move_head_window_temporary(self,new_pos_offset):
  3439.         if self.inputCSYS.get() and self.RengData.image == None:
  3440.             new_pos_offset = [0,0]
  3441.             xdist = -self.pos_offset[0]
  3442.             ydist = -self.pos_offset[1]
  3443.         else:
  3444.             xdist = -self.pos_offset[0] + new_pos_offset[0]
  3445.             ydist = -self.pos_offset[1] + new_pos_offset[1]
  3446.  
  3447.         if self.k40 != None:
  3448.             self.Send_Rapid_Move( xdist,ydist )
  3449.  
  3450.         self.pos_offset = new_pos_offset
  3451.         self.menu_View_Refresh()
  3452.    
  3453.     ################################################################################
  3454.     #                         General Settings Window                              #
  3455.     ################################################################################
  3456.     def GEN_Settings_Window(self):
  3457.         gen_settings = Toplevel(width=560, height=460)
  3458.         gen_settings.grab_set() # Use grab_set to prevent user input in the main window during calculations
  3459.         gen_settings.resizable(0,0)
  3460.         gen_settings.title('Settings')
  3461.         gen_settings.iconname("Settings")
  3462.  
  3463.         try:
  3464.             gen_settings.iconbitmap(bitmap="@emblem64")
  3465.         except:
  3466.             debug_message(traceback.format_exc())
  3467.             pass
  3468.  
  3469.         D_Yloc  = 6
  3470.         D_dY = 26
  3471.         xd_label_L = 12
  3472.  
  3473.         w_label=150
  3474.         w_entry=40
  3475.         w_units=35
  3476.         xd_entry_L=xd_label_L+w_label+10
  3477.         xd_units_L=xd_entry_L+w_entry+5
  3478.  
  3479.         #Radio Button
  3480.         D_Yloc=D_Yloc+D_dY
  3481.         self.Label_Units = Label(gen_settings,text="Units")
  3482.         self.Label_Units.place(x=xd_label_L, y=D_Yloc, width=113, height=21)
  3483.         self.Radio_Units_IN = Radiobutton(gen_settings,text="inch", value="in",
  3484.                                          width="100", anchor=W)
  3485.         self.Radio_Units_IN.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  3486.         self.Radio_Units_IN.configure(variable=self.units, command=self.Entry_units_var_Callback )
  3487.         self.Radio_Units_MM = Radiobutton(gen_settings,text="mm", value="mm",
  3488.                                          width="100", anchor=W)
  3489.         self.Radio_Units_MM.place(x=w_label+110, y=D_Yloc, width=75, height=23)
  3490.         self.Radio_Units_MM.configure(variable=self.units, command=self.Entry_units_var_Callback )
  3491.  
  3492.         D_Yloc=D_Yloc+D_dY
  3493.         self.Label_init_home = Label(gen_settings,text="Home Upon Initialize")
  3494.         self.Label_init_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3495.         self.Checkbutton_init_home = Checkbutton(gen_settings,text="", anchor=W)
  3496.         self.Checkbutton_init_home.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  3497.         self.Checkbutton_init_home.configure(variable=self.init_home)
  3498.  
  3499.         D_Yloc=D_Yloc+D_dY
  3500.         self.Label_Preprocess_CRC = Label(gen_settings,text="Preprocess CRC Data")
  3501.         self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3502.         self.Checkbutton_Preprocess_CRC = Checkbutton(gen_settings,text="", anchor=W)
  3503.         self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  3504.         self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc)
  3505.  
  3506.  
  3507.         D_Yloc=D_Yloc+D_dY
  3508.         self.Label_Timeout = Label(gen_settings,text="USB Timeout")
  3509.         self.Label_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3510.         self.Label_Timeout_u = Label(gen_settings,text="ms", anchor=W)
  3511.         self.Label_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  3512.         self.Entry_Timeout = Entry(gen_settings,width="15")
  3513.         self.Entry_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3514.         self.Entry_Timeout.configure(textvariable=self.t_timeout)
  3515.         self.t_timeout.trace_variable("w", self.Entry_Timeout_Callback)
  3516.         self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(),2)
  3517.  
  3518.         D_Yloc=D_Yloc+D_dY
  3519.         self.Label_N_Timeouts = Label(gen_settings,text="Number of Timeouts")
  3520.         self.Label_N_Timeouts.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3521.         self.Entry_N_Timeouts = Entry(gen_settings,width="15")
  3522.         self.Entry_N_Timeouts.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3523.         self.Entry_N_Timeouts.configure(textvariable=self.n_timeouts)
  3524.         self.n_timeouts.trace_variable("w", self.Entry_N_Timeouts_Callback)
  3525.         self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(),2)
  3526.  
  3527.         D_Yloc=D_Yloc+D_dY
  3528.         font_entry_width=215
  3529.         self.Label_Inkscape_Path = Label(gen_settings,text="Inkscape Executable")
  3530.         self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3531.         self.Entry_Inkscape_Path = Entry(gen_settings,width="15")
  3532.         self.Entry_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=font_entry_width, height=23)
  3533.         self.Entry_Inkscape_Path.configure(textvariable=self.inkscape_path)
  3534.         self.Inkscape_Path = Button(gen_settings,text="Find Inkscape")
  3535.         self.Inkscape_Path.place(x=xd_entry_L+font_entry_width+10, y=D_Yloc, width=110, height=23)
  3536.         self.Inkscape_Path.bind("<ButtonRelease-1>", self.Inkscape_Path_Click)
  3537.  
  3538.         D_Yloc=D_Yloc+D_dY
  3539.         self.Label_no_com = Label(gen_settings,text="Home in Upper Right")
  3540.         self.Label_no_com.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3541.         self.Checkbutton_no_com = Checkbutton(gen_settings,text="", anchor=W)
  3542.         self.Checkbutton_no_com.place(x=xd_entry_L, y=D_Yloc, width=75, height=23)
  3543.         self.Checkbutton_no_com.configure(variable=self.HomeUR)
  3544.         self.HomeUR.trace_variable("w",self.menu_View_Refresh_Callback)        
  3545.  
  3546.         D_Yloc=D_Yloc+D_dY
  3547.         self.Label_Board_Name      = Label(gen_settings,text="Board Name", anchor=CENTER )
  3548.         self.Board_Name_OptionMenu = OptionMenu(gen_settings, self.board_name,
  3549.                                             "LASER-M2",
  3550.                                             "LASER-M1",
  3551.                                             "LASER-M",
  3552.                                             "LASER-B2",
  3553.                                             "LASER-B1",
  3554.                                             "LASER-B",
  3555.                                             "LASER-A")
  3556.         self.Label_Board_Name.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3557.         self.Board_Name_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry*3, height=23)
  3558.  
  3559.         D_Yloc=D_Yloc+D_dY
  3560.         self.Label_Laser_Area_Width = Label(gen_settings,text="Laser Area Width")
  3561.         self.Label_Laser_Area_Width.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3562.         self.Label_Laser_Area_Width_u = Label(gen_settings,textvariable=self.units, anchor=W)
  3563.         self.Label_Laser_Area_Width_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  3564.         self.Entry_Laser_Area_Width = Entry(gen_settings,width="15")
  3565.         self.Entry_Laser_Area_Width.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3566.         self.Entry_Laser_Area_Width.configure(textvariable=self.LaserXsize)
  3567.         self.LaserXsize.trace_variable("w", self.Entry_Laser_Area_Width_Callback)
  3568.         self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(),2)
  3569.  
  3570.         D_Yloc=D_Yloc+D_dY
  3571.         self.Label_Laser_Area_Height = Label(gen_settings,text="Laser Area Height")
  3572.         self.Label_Laser_Area_Height.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3573.         self.Label_Laser_Area_Height_u = Label(gen_settings,textvariable=self.units, anchor=W)
  3574.         self.Label_Laser_Area_Height_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  3575.         self.Entry_Laser_Area_Height = Entry(gen_settings,width="15")
  3576.         self.Entry_Laser_Area_Height.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3577.         self.Entry_Laser_Area_Height.configure(textvariable=self.LaserYsize)
  3578.         self.LaserYsize.trace_variable("w", self.Entry_Laser_Area_Height_Callback)
  3579.         self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(),2)
  3580.  
  3581.         D_Yloc=D_Yloc+D_dY
  3582.         self.Label_Laser_X_Scale = Label(gen_settings,text="X Scale Factor")
  3583.         self.Label_Laser_X_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3584.         self.Entry_Laser_X_Scale = Entry(gen_settings,width="15")
  3585.         self.Entry_Laser_X_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3586.         self.Entry_Laser_X_Scale.configure(textvariable=self.LaserXscale)
  3587.         self.LaserXscale.trace_variable("w", self.Entry_Laser_X_Scale_Callback)
  3588.         self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(),2)
  3589.  
  3590.         D_Yloc=D_Yloc+D_dY
  3591.         self.Label_Laser_Y_Scale = Label(gen_settings,text="Y Scale Factor")
  3592.         self.Label_Laser_Y_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3593.         self.Entry_Laser_Y_Scale = Entry(gen_settings,width="15")
  3594.         self.Entry_Laser_Y_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3595.         self.Entry_Laser_Y_Scale.configure(textvariable=self.LaserYscale)
  3596.         self.LaserYscale.trace_variable("w", self.Entry_Laser_Y_Scale_Callback)
  3597.         self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(),2)
  3598.        
  3599.  
  3600.         D_Yloc=D_Yloc+D_dY+10
  3601.         self.Label_SaveConfig = Label(gen_settings,text="Configuration File")
  3602.         self.Label_SaveConfig.place(x=xd_label_L, y=D_Yloc, width=113, height=21)
  3603.  
  3604.         self.GEN_SaveConfig = Button(gen_settings,text="Save")
  3605.         self.GEN_SaveConfig.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=21, anchor="nw")
  3606.         self.GEN_SaveConfig.bind("<ButtonRelease-1>", self.Write_Config_File)
  3607.        
  3608.         ## Buttons ##
  3609.         gen_settings.update_idletasks()
  3610.         Ybut=int(gen_settings.winfo_height())-30
  3611.         Xbut=int(gen_settings.winfo_width()/2)
  3612.  
  3613.         self.GEN_Close = Button(gen_settings,text="Close",command=self.Close_Current_Window_Click)
  3614.         self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
  3615.  
  3616.     ################################################################################
  3617.     #                          Raster Settings Window                              #
  3618.     ################################################################################
  3619.     def RASTER_Settings_Window(self):
  3620.         Wset=425+280
  3621.         Hset=330 #260
  3622.         raster_settings = Toplevel(width=Wset, height=Hset)
  3623.         raster_settings.grab_set() # Use grab_set to prevent user input in the main window during calculations
  3624.         raster_settings.resizable(0,0)
  3625.         raster_settings.title('Raster Settings')
  3626.         raster_settings.iconname("Raster Settings")
  3627.  
  3628.         try:
  3629.             raster_settings.iconbitmap(bitmap="@emblem64")
  3630.         except:
  3631.             debug_message(traceback.format_exc())
  3632.             pass
  3633.  
  3634.         D_Yloc  = 6
  3635.         D_dY = 24
  3636.         xd_label_L = 12
  3637.  
  3638.         w_label=155
  3639.         w_entry=60
  3640.         w_units=35
  3641.         xd_entry_L=xd_label_L+w_label+10
  3642.         xd_units_L=xd_entry_L+w_entry+5
  3643.  
  3644.  
  3645.  
  3646.         D_Yloc=D_Yloc+D_dY
  3647.         self.Label_Rstep   = Label(raster_settings,text="Scanline Step", anchor=CENTER )
  3648.         self.Label_Rstep.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3649.         self.Label_Rstep_u = Label(raster_settings,text="in", anchor=W)
  3650.         self.Label_Rstep_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21)
  3651.         self.Entry_Rstep   = Entry(raster_settings,width="15")
  3652.         self.Entry_Rstep.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23)
  3653.         self.Entry_Rstep.configure(textvariable=self.rast_step)
  3654.         self.rast_step.trace_variable("w", self.Entry_Rstep_Callback)
  3655.  
  3656.         D_Yloc=D_Yloc+D_dY
  3657.         self.Label_EngraveUP = Label(raster_settings,text="Engrave Bottom Up")
  3658.         self.Checkbutton_EngraveUP = Checkbutton(raster_settings,text=" ", anchor=W)
  3659.         self.Checkbutton_EngraveUP.configure(variable=self.engraveUP)
  3660.         self.Label_EngraveUP.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3661.         self.Checkbutton_EngraveUP.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  3662.        
  3663.         D_Yloc=D_Yloc+D_dY
  3664.         self.Label_Halftone = Label(raster_settings,text="Halftone (Dither)")
  3665.         self.Label_Halftone.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3666.         self.Checkbutton_Halftone = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_RASTER)
  3667.         self.Checkbutton_Halftone.place(x=w_label+22, y=D_Yloc, width=75, height=23)
  3668.         self.Checkbutton_Halftone.configure(variable=self.halftone)
  3669.         self.halftone.trace_variable("w", self.menu_View_Refresh_Callback)
  3670.  
  3671.         ############
  3672.         D_Yloc=D_Yloc+D_dY
  3673.         self.Label_Halftone_DPI      = Label(raster_settings,text="Halftone Resolution", anchor=CENTER )
  3674.         self.Halftone_DPI_OptionMenu = OptionMenu(raster_settings, self.ht_size,
  3675.                                             "1000",
  3676.                                             "500",
  3677.                                             "333",
  3678.                                             "250",
  3679.                                             "200",
  3680.                                             "167",
  3681.                                             "143",
  3682.                                             "125")
  3683.         self.Label_Halftone_DPI.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3684.         self.Halftone_DPI_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry+30, height=23)
  3685.  
  3686.  
  3687.         self.Label_Halftone_u = Label(raster_settings,text="dpi", anchor=W)
  3688.         self.Label_Halftone_u.place(x=xd_units_L+30, y=D_Yloc, width=w_units, height=21)
  3689.  
  3690.         ############
  3691.         D_Yloc=D_Yloc+D_dY+5
  3692.         self.Label_bezier_M1  = Label(raster_settings,
  3693.                                 text="Slope, Black (%.1f)"%(self.bezier_M1_default),
  3694.                                 anchor=CENTER )
  3695.         self.bezier_M1_Slider = Scale(raster_settings, from_=1, to=50, resolution=0.1, \
  3696.                                 orient=HORIZONTAL, variable=self.bezier_M1)
  3697.         self.bezier_M1_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
  3698.         D_Yloc=D_Yloc+21
  3699.         self.Label_bezier_M1.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3700.         self.bezier_M1.trace_variable("w", self.bezier_M1_Callback)
  3701.        
  3702.         D_Yloc=D_Yloc+D_dY-8
  3703.         self.Label_bezier_M2  = Label(raster_settings,
  3704.                                 text="Slope, White (%.2f)"%(self.bezier_M2_default),
  3705.                                 anchor=CENTER )
  3706.         self.bezier_M2_Slider = Scale(raster_settings, from_=0.0, to=1, \
  3707.                                 orient=HORIZONTAL,resolution=0.01, variable=self.bezier_M2)
  3708.         self.bezier_M2_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
  3709.         D_Yloc=D_Yloc+21
  3710.         self.Label_bezier_M2.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3711.         self.bezier_M2.trace_variable("w", self.bezier_M2_Callback)
  3712.  
  3713.         D_Yloc=D_Yloc+D_dY-8
  3714.         self.Label_bezier_weight   = Label(raster_settings,
  3715.                                      text="Transition (%.1f)"%(self.bezier_M1_default),
  3716.                                      anchor=CENTER )
  3717.         self.bezier_weight_Slider = Scale(raster_settings, from_=0, to=10, resolution=0.1, \
  3718.                                     orient=HORIZONTAL, variable=self.bezier_weight)
  3719.         self.bezier_weight_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 ))
  3720.         D_Yloc=D_Yloc+21
  3721.         self.Label_bezier_weight.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21)
  3722.         self.bezier_weight.trace_variable("w", self.bezier_weight_Callback)
  3723.  
  3724.  
  3725.         # Bezier Canvas
  3726.         self.Bezier_frame = Frame(raster_settings, bd=1, relief=SUNKEN)
  3727.         self.Bezier_frame.place(x=Wset-280, y=10, height=265, width=265)
  3728.         self.BezierCanvas = Canvas(self.Bezier_frame, background="white")
  3729.         self.BezierCanvas.pack(side=LEFT, fill=BOTH, expand=1)
  3730.         self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="grey", capstyle="round", width = 2, tags='perm')
  3731.  
  3732.  
  3733.         M1 = self.bezier_M1_default
  3734.         M2 = self.bezier_M2_default
  3735.         w  = self.bezier_weight_default
  3736.         num = 10
  3737.         x,y = self.generate_bezier(M1,M2,w,n=num)
  3738.         for i in range(0,num):
  3739.             self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="lightgrey", stipple='gray25',\
  3740.                                            capstyle="round", width = 2, tags='perm')
  3741.        
  3742.  
  3743.         ## Buttons ##
  3744.         raster_settings.update_idletasks()
  3745.         Ybut=int(raster_settings.winfo_height())-30
  3746.         Xbut=int(raster_settings.winfo_width()/2)
  3747.  
  3748.         self.RASTER_Close = Button(raster_settings,text="Close",command=self.Close_Current_Window_Click)
  3749.         self.RASTER_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center")
  3750.  
  3751.         self.bezier_M1_Callback()
  3752.         self.Set_Input_States_RASTER()
  3753.  
  3754.  
  3755.        
  3756. ################################################################################
  3757. #             Function for outputting messages to different locations          #
  3758. #            depending on what options are enabled                             #
  3759. ################################################################################
  3760. def fmessage(text,newline=True):
  3761.     global QUIET
  3762.     if (not QUIET):
  3763.         if newline==True:
  3764.             try:
  3765.                 sys.stdout.write(text)
  3766.                 sys.stdout.write("\n")
  3767.                 debug_message(traceback.format_exc())
  3768.             except:
  3769.                 debug_message(traceback.format_exc())
  3770.                 pass
  3771.         else:
  3772.             try:
  3773.                 sys.stdout.write(text)
  3774.                 debug_message(traceback.format_exc())
  3775.             except:
  3776.                 debug_message(traceback.format_exc())
  3777.                 pass
  3778.  
  3779. ################################################################################
  3780. #                               Message Box                                    #
  3781. ################################################################################
  3782. def message_box(title,message):
  3783.     title = "%s (K40 Whisperer V%s)" %(title,version)
  3784.     if VERSION == 3:
  3785.         tkinter.messagebox.showinfo(title,message)
  3786.     else:
  3787.         tkMessageBox.showinfo(title,message)
  3788.         pass
  3789.  
  3790. ################################################################################
  3791. #                          Message Box ask OK/Cancel                           #
  3792. ################################################################################
  3793. def message_ask_ok_cancel(title, mess):
  3794.     if VERSION == 3:
  3795.         result=tkinter.messagebox.askokcancel(title, mess)
  3796.     else:
  3797.         result=tkMessageBox.askokcancel(title, mess)
  3798.     return result
  3799.  
  3800. ################################################################################
  3801. #                         Debug Message Box                                    #
  3802. ################################################################################
  3803. def debug_message(message):
  3804.     global DEBUG
  3805.     title = "Debug Message"
  3806.     if DEBUG:
  3807.         if VERSION == 3:
  3808.             tkinter.messagebox.showinfo(title,message)
  3809.         else:
  3810.             tkMessageBox.showinfo(title,message)
  3811.             pass
  3812.  
  3813. ################################################################################
  3814. #                         Choose Units Dialog                                  #
  3815. ################################################################################
  3816. import tkSimpleDialog
  3817. class UnitsDialog(tkSimpleDialog.Dialog):
  3818.     def body(self, master):
  3819.         self.resizable(0,0)
  3820.         self.title('Units')
  3821.         self.iconname("Units")
  3822.  
  3823.         try:
  3824.             self.iconbitmap(bitmap="@emblem64")
  3825.         except:
  3826.             pass
  3827.        
  3828.         self.uom = StringVar()
  3829.         self.uom.set("Millimeters")
  3830.  
  3831.         Label(master, text="Select DXF Import Units:").grid(row=0)
  3832.         Radio_Units_IN = Radiobutton(master,text="Inches",        value="Inches")
  3833.         Radio_Units_MM = Radiobutton(master,text="Millimeters",   value="Millimeters")
  3834.         Radio_Units_CM = Radiobutton(master,text="Centimeters",   value="Centimeters")
  3835.        
  3836.         Radio_Units_IN.grid(row=1, sticky=W)
  3837.         Radio_Units_MM.grid(row=2, sticky=W)
  3838.         Radio_Units_CM.grid(row=3, sticky=W)
  3839.  
  3840.         Radio_Units_IN.configure(variable=self.uom)
  3841.         Radio_Units_MM.configure(variable=self.uom)
  3842.         Radio_Units_CM.configure(variable=self.uom)
  3843.  
  3844.     def apply(self):
  3845.         self.result = self.uom.get()
  3846.         return
  3847.  
  3848.  
  3849.  
  3850. ################################################################################
  3851. #                          Startup Application                                 #
  3852. ################################################################################
  3853.  
  3854.  
  3855. root = Tk()
  3856. app = Application(root)
  3857. app.master.title(title_text)
  3858. app.master.iconname("K40")
  3859. app.master.minsize(800,560) #800x600 min
  3860.  
  3861. try:
  3862.     app.master.iconbitmap(bitmap="@emblem64")
  3863. except:
  3864.     pass
  3865.  
  3866. if LOAD_MSG != "":
  3867.     message_box("K40 Whisperer",LOAD_MSG)
  3868. debug_message("Debuging is turned on.")
  3869.  
  3870. root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement