示例#1
0
class GUI:

    runModeMenuItems = {
        RUN_MODE_MONITOR: 'Monitor',
    }

    def __init__(self, master, sample):
        self.master = master
        self.sample = sample
        self.master.title('Sample positioner')

        self.createWidgets(self.master)
        self.blank_parameters()
        self.putBanner()

    def callback(self, cb):
        self._callback = cb

    def do_callback(self, context, *args):
        if hasattr(self, '_callback'):
            self._callback(context, *args)

    def close(self):
        for (w, r, c) in (self.wMCStatusDisplay, ):
            w.close()

    def createWidgets(self, master):

        master.grid_columnconfigure(0, weight=0, minsize=200)
        master.grid_columnconfigure(1, weight=1, minsize=700)
        master.grid_rowconfigure(0, weight=1, minsize=575)
        master.grid_rowconfigure(1, weight=0, minsize=25)

        self.populateMenu(master)

        row = 0
        col = 0
        w = XScroll(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populateDisplayPanel(w.interior)

        col += 1
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populatePlotPanel(w)

        row += 1
        col = 0
        w = Frame(master)
        w.grid(row=row, column=col, columnspan=2, sticky=NSEW)
        self.populateStatusFrame(w)

    def populateMenu(self, master):

        ### Main Menu
        self.mainmenu = Menu(master)
        self.mainmenu.config(borderwidth=1)
        master.config(menu=self.mainmenu)

        self.filemenu = Menu(self.mainmenu)
        self.filemenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='File',
                                  menu=self.filemenu,
                                  underline=0)

        #self.settingsmenu = Menu (self.mainmenu)
        #self.settingsmenu.config (tearoff = 0)
        #self.mainmenu.add_cascade (
        #label = 'Settings', menu = self.settingsmenu, underline = 0)

        self.toolsmenu = Menu(self.mainmenu)
        self.toolsmenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='Tools',
                                  menu=self.toolsmenu,
                                  underline=0)

        # ++++ Populating file menu ++++

        menu_items = [ \
         ('Connect'     , self.wConnectDeviceCB),
         ('Hide'        ,       self.wHideCB) \
        ]

        for (l, c) in menu_items:
            self.filemenu.add_command(label=l, command=c)

        # ++++ Populating settings menu ++++

        #menu_items = [ \
        #('Pitch'     , self.wPitchSettingCB) \
        #]

        #for (l, c) in menu_items:
        #self.settingsmenu.add_command (label = l, command = c)

        # ++++ Populating tools menu ++++

        menu_items = [ \
         ('Reset'                 , self.wResetDeviceCB ),
         ('Move absolute'         , self.wMoveAbsoluteCB),
         ('Move relative'         , self.wMoveRelativeCB),
         ('Stop'                  , self.wStopDeviceCB  )  \
        ]

        for (l, c) in menu_items:
            self.toolsmenu.add_command(label=l, command=c)

    def populateDisplayPanel(self, master):

        master.grid_columnconfigure(0, weight=1, minsize=230)

        row = 0
        col = 0
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.wMCStatusDisplay = (GUI_MCStatusDisplay(w), row, col)

        row += 1
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populateControlFrame(w)

    def populateControlFrame(self, master):

        master.grid_columnconfigure(0, weight=1)

        row = 0
        col = 0
        w = LabelFrame(master, text='Control')
        w.grid(row=row, column=col, sticky=NSEW, padx=5, pady=5)
        self.populateControlFrameWidgets(w)

    def populateControlFrameWidgets(self, master):

        master.grid_columnconfigure(0, weight=1)
        master.grid_columnconfigure(1, weight=1)

        row = 0
        col = 0
        w = Label(master, text="Control mode: ")
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        var = self.runMode = StringVar()
        options = self.runModeMenuItems.values()
        w = self.wRunMode = OptionMenu(master,
                                       var,
                                       *options,
                                       command=self.wRunModeCB)
        w.config(anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        col = 0
        w = self.wStart = Button(master, text='Start', command=self.wStartCB)
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        w = self.wFinish = Button(master,
                                  text='Finish',
                                  state=DISABLED,
                                  command=self.wFinishCB)
        w.grid(row=row, column=col, sticky=NSEW)

    # ++++++++++++++++++++++++++++++++++++++++++++++++++

    def populatePlotPanel(self, master):

        master.grid_rowconfigure(0, weight=1)
        master.grid_columnconfigure(0, weight=1)

        w = self.wPlots = XTab(master)
        w.grid(row=0, column=0, sticky=NSEW)

    def newPlot(self, name):
        return Plot2D.Plot2D(self.wPlots.add(name))

    def clearPlot(self):
        self.wPlots.clear()
        self.putBanner()

    # ++++++++++++++++++++++++++++++++++++++++++++++++++

    def populateStatusFrame(self, master):

        master.grid_columnconfigure(0, weight=1)
        #master.grid_rowconfigure    (0, weight = 1)

        row = 0
        col = 0
        w = self.wStatus = Label(master, text='...', anchor=W, width=10)
        w.grid(row=row, column=col, sticky=NSEW)

    def set_status(self, text):

        lt = localtime(systime())
        time_stamp = (str('%02d' % lt.tm_hour) + ':' +
                      str('%02d' % lt.tm_min) + ':' + str('%02d' % lt.tm_sec))

        text = '<' + time_stamp + ':XMC> ' + text
        print text

        old_text = self.wStatus['text']
        new_text = text + '    .    ' + old_text
        new_text = new_text[:1024]
        self.wStatus['text'] = new_text

    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def setConnectionStatus(self, status):

        if status == DEVICE_CONNECTING:
            self.filemenu.entryconfig(0,
                                      label='Connecting',
                                      state=DISABLED,
                                      command=None)

        elif status == DEVICE_CONNECTED:
            self.filemenu.entryconfig(0,
                                      label='Disconnect',
                                      state=NORMAL,
                                      command=self.wDisconnctDeviceCB)

            self.set_status('Sample positioner connected')

        elif status == DEVICE_DISCONNECTING:
            self.filemenu.entryconfig(0,
                                      label='Disconnecting',
                                      state=DISABLED,
                                      command=None)

        elif status == DEVICE_DISCONNECTED:

            self.filemenu.entryconfig(0,
                                      label='Connect',
                                      state=NORMAL,
                                      command=self.wConnectDeviceCB)

            self.wMCStatusDisplay[0].blank_parameters()
            self.set_status('Sample positioner disconnected')

        elif status == DEVICE_NOT_FOUND:
            self.filemenu.entryconfig(0,
                                      label='Connect',
                                      state=NORMAL,
                                      command=self.wConnectDeviceCB)

            self.wMCStatusDisplay[0].blank_parameters()
            self.set_status('Sample positioner not found')

        else:
            raise ValueError(status)

    def wHideCB(self):
        self.master.withdraw()

    def wConnectDeviceCB(self):
        self.do_callback(CONNECT_DEVICE)

    def wDisconnctDeviceCB(self):
        self.do_callback(DISCONNECT_DEVICE)

    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def wStartCB(self):
        self.do_callback(START_RUN, self.getRunMode())

    def wFinishCB(self):
        self.do_callback(FINISH_RUN)

    def setRunControlStatus(self, status):

        if status == RUN_STARTING:
            self.wRunMode.config(state=DISABLED)
            self.wStart.config(text='Starting', state=DISABLED)
            self.wFinish.config(text='Finish', state=DISABLED)

        elif status == RUN_STARTED:
            self.wRunMode.config(state=DISABLED)
            self.wStart.config(text='Started', state=DISABLED)
            self.wFinish.config(text='Finish', state=NORMAL)

        elif status == RUN_FINISHING:
            self.wRunMode.config(state=DISABLED)
            self.wStart.config(text='Started', state=DISABLED)
            self.wFinish.config(text='Finishing', state=DISABLED)

        elif status == RUN_FINISHED:
            self.wRunMode.config(state=NORMAL)
            self.wStart.config(text='Start', state=NORMAL)
            self.wFinish.config(text='Finish', state=DISABLED)

    def wRunModeCB(self, *args):
        self.do_callback(RUN_MODE, self.getRunMode())

    def getRunMode(self):
        runModes = {v: k for (k, v) in self.runModeMenuItems.items()}
        return runModes.get(self.runMode.get())

    def setRunMode(self, mode):

        self.runMode.set(self.runModeMenuItems.get(mode))

        if mode == RUN_MODE_MONITOR: pass
        else: raise ValueError(mode)

    def wPitchSettingCB(self):
        self.do_callback(OPEN_DIALOG, PITCH_SETTING_DIALOG)

    def wResetDeviceCB(self):
        self.do_callback(RESET_DEVICE)

    def wMoveAbsoluteCB(self):
        self.do_callback(OPEN_DIALOG, MOVE_ABSOLUTE_DIALOG)

    def wMoveRelativeCB(self):
        self.do_callback(OPEN_DIALOG, MOVE_RELATIVE_DIALOG)

    def wStopDeviceCB(self):
        self.do_callback(STOP_DEVICE)

    def setMCStatusDisplay(self, state, position, remainingDistance):
        (w, row, col) = self.wMCStatusDisplay
        w.setValues(state, position, remainingDistance)

    def setMCProgressBarDisplay(self, position):
        (w, row, col) = self.wMCStatusDisplay
        w.setBar(position)

    def setStatusJammed(self):
        (w, row, col) = self.wMCStatusDisplay
        w.setStatusJammed()

    def setMCProgressBarMin(self, position):
        (w, row, col) = self.wMCStatusDisplay
        w.setBarMin(position)

    def setMCProgressBarMax(self, position):
        (w, row, col) = self.wMCStatusDisplay
        w.setBarMax(position)

    def blank_parameters(self):
        self.wMCStatusDisplay[0].blank_parameters()

    def putBanner(self):
        w = GUI_Banner(self.wPlots.add('Welcome'))
        w.grid(row=0, column=0, sticky=NSEW)
示例#2
0
class MainApp(object):
    """
    The MainApp based on TKinter

    Attributes
    ----------

    root             : Tk
                      The Tk object
    dbfdata          : dictionary
                      The current dbf data
    menubar          : Menu
                      The menu bar
    attibmenu        : Menu
                      The attribute menu
    """
    def __init__(self):
        self.root = Tk()
        self.root.geometry("300x250")
        self.root.title("Shape file Reader")
        self.createMenu()
        self.root.mainloop()

    def createMenu(self):       
        """
        Creates GUI components and register events
        """
        self.menubar = Menu(self.root)
        self.dbfdata = None
        
        filemenu = Menu(self.menubar, tearoff=0)
        filemenu.add_command(label="Open", command=self.__openShpfile)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.root.quit)
        self.menubar.add_cascade(label="File", menu=filemenu)
        
        self.attibmenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Attibutes", menu=self.attibmenu,state='disabled')

        #Sagar Jha
        self.menubar.add_cascade(label="Simulator",command=self.__simulate) 
        #Added Simulator 
        
        self.root.config(menu=self.menubar)

    def __simulate(self):
        """
        This function will create object of SimulatorExperimence 
        """
        self.Sim = SimulatorExperimence()
        ## Test to check object type       
        ## print(type(self.Sim))
        self.Sim.doTest()
        
        
    def __openShpfile(self):
        """
        Open a shapefile and read in the contents, pop up the attribute menu 
        with the attributes of the shapefile
        """   
        print "open shape file!"
        directory="C:/Users/sjha1/Documents/GitHub/Simulator_GUI/Python-Sample/data/states/48States.shp"
        #tkFileDialog.askopenfilename(filetypes=[("SHAPE_FILE","*.shp")])
        print directory
        
        if directory == "":
            return
        
        self.shapes, self.shp_type, self.bbox = shp_reader.read_shp(directory)
        #read corresponding dbf data
        dbfFile = dbf.DbfLoader(directory[:-3] + "dbf")
        
        t = dbfFile.table2list()
        varNames = dbfFile.get_field_names()
        variables = {}
        for variable in varNames:
            variables[variable] = [record[varNames.index(variable)] for record in t]
            
        if self.dbfdata!=None:
            self.attibmenu.delete(0, len(self.dbfdata)-1)
            
        #add attributes into menu
        for key in variables.keys():
            self.__addAttribute(key)
        
        self.dbfdata = variables
        self.menubar.entryconfig(2, state=Tkconstants.NORMAL)
        self.__updateCanvas("STATE_NAME")
    
    def __addAttribute(self,attributeName):
        """
        Add an attribute to the menu
        """
        self.attibmenu.add_command(label=attributeName, command=lambda i=attributeName:self.__updateCanvas(i))
        
    def __updateCanvas(self, attributeName):
        """
        Updates the canvas and showing statistical information
        """
        print "update Canvas "+attributeName
        data_list=self.dbfdata[attributeName]
        
        print "attribute values: ", data_list
        try:
            n, min_max, mean, var, skew, kurt = stats.describe(data_list)
            print "============================"
            print "attribute statistics\n"
            print("Number of units: {0:d}".format(n))
            print("Minimum: {0:8.6f} Maximum: {1:8.6f}".format(min_max[0], min_max[1]))
            print("Mean: {0:8.6f}".format(mean))
            print("Standard deviation: {0:8.6f}".format(math.sqrt(var)))
            print("Skew : {0:8.6f}".format(skew))
            print("Kurtosis: {0:8.6f}".format(kurt))
            print "\n============================"
            
            high=max(data_list)
            low=min(data_list)
            dif=float(high-low)
            
            for i in range(len(data_list)):
                #map colors to 0-200, 0-200, 0-200 (avoid pure white for display purpose)
                index=float(data_list[i]-low)/dif*200
                index=str(hex(200-int(index)).split('x')[1])
    
                color="#"+index+index+index    
                self.shapes[i].color=color
        except:
            print "non-numeric attribute"
            
        self.canvas=MainCanvas(self.shapes,self.bbox,self.shp_type,self.root,attributeName,data_list)
class SerialTerm(Tk):
    def __init__(self, serial_queue, serial_thread):
        Tk.__init__(self)
        self.title("Foss SerialTerminal for Multi")
        self.serial_queue = serial_queue
        self.serial_thread  = serial_thread

        menu_bar = Menu(self)

        file_menu = Menu(menu_bar, tearoff=0)
        file_menu.add_command(label="Save as...")
        file_menu.add_command(label="Exit", command=self.quit)
        menu_bar.add_cascade(label="File", menu=file_menu)

        self.parser_menu = Menu(menu_bar, tearoff=0)
        self.serial_parser_enabled = IntVar()
        self.serial_parser_enabled.set(1)
        self.parser_menu.add_checkbutton(
            label="Serial parser enabled",
            variable=self.serial_parser_enabled
        )
        self.parser_menu.add_command(label="Edit parser rules", command=self.open_conditionals_editor)
        menu_bar.add_cascade(label="Parser", menu=self.parser_menu)


        self.config(menu=menu_bar)
        main_frame = Frame(self)
        output_frame = Frame(main_frame)
        input_frame = Frame(main_frame)

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)
        main_frame.grid(column=0, row=0, padx=3, pady=3, sticky=(N, W, E, S))
        main_frame.grid_columnconfigure(0, weight=1)
        main_frame.grid_rowconfigure(0, weight=1)



        output_text_vertical_scrollbar = Scrollbar(output_frame, orient=VERTICAL)
        output_text_horizontal_scrollbar = Scrollbar(output_frame, orient=HORIZONTAL)
        self.output_text = Text(
            output_frame,
            wrap=NONE,
            xscrollcommand=output_text_horizontal_scrollbar.set,
            yscrollcommand=output_text_vertical_scrollbar.set
        )
        self.output_text.configure(bg="white", state="disabled")
        self.output_text.grid(column=0, row=0, sticky=(N, S, E, W))
        output_text_vertical_scrollbar.grid(column=1, row=0, sticky=(N, S))
        output_text_vertical_scrollbar.config(command=self.output_text.yview)
        output_text_horizontal_scrollbar.grid(column=0, row=1, sticky=(E, W))
        output_text_horizontal_scrollbar.config(command=self.output_text.xview)

        output_frame.grid(column=0, row=0, sticky=(N, S, E, W))
        output_frame.grid_columnconfigure(0, weight=1)
        output_frame.grid_rowconfigure(0, weight=1)


        self.input_string = StringVar()
        input_entry = Entry(input_frame, textvariable=self.input_string)
        input_entry.grid(column=0, row=0, sticky=(E, W))

        line_end_selection_items = ["CR&NL", "NL", "CR", "None"]
        self.line_end_selection = Combobox(
            input_frame,
            values=line_end_selection_items,
            state="readonly",
            width=len(max(line_end_selection_items, key=len))
        )
        self.line_end_selection.current(newindex=0)
        self.line_end_selection.grid(column=1, row=0)

        serial_port_names = ["Port"]
        serial_port_names.extend([s.name for s in serial.tools.list_ports.comports()])
        self.port_name_selection = Combobox(
            input_frame,
            values = serial_port_names,
            state="readonly",
            width=len(max(serial_port_names, key=len))
        )
        self.port_name_selection.current(newindex=0)
        self.port_name_selection_index = 0
        self.port_name_selection.grid(column=2, row=0)


        baudrates = [
            "300 baud",
            "1200 baud",
            "2400 baud",
            "4800 baud",
            "9600 baud",
            "19200 baud",
            "38400 baud",
            "57600 baud",
            "74880 baud",
            "115200 baud",
            "230400 baud",
            "250000 baud"
        ]

        self.baudrate_selection = Combobox(
            input_frame,
            values = baudrates,
            state="readonly",
            width=len(max(baudrates, key=len))
        )
        self.baudrate_selection.current(newindex=9)
        self.baudrate_selection.grid(column=3, row=0)

        input_frame.grid(column=0, row=1, sticky=(E, W))
        input_frame.grid_columnconfigure(0, weight=1)

        self.port_name_selection.bind("<<ComboboxSelected>>", self.port_name_selected)
        self.baudrate_selection.bind("<<ComboboxSelected>>", self.baudrate_selected)

        self.after(100, self.serial_tick)

        # TODO Load from pickle file.
        self.conditionals = [
            ["Enabled", "line.startswith(\"Hello\")", "Python", "print 'Fooobaaaaar. Jibb.'"],
            ["Enabled", "line.startswith(\"Foo\")", "Debugger", "halt\nreset"],
        ]
        self.counter = 0


    def open_conditionals_editor(self):
        self.conditionals_editor = Toplevel(master=self)
        self.parser_menu.entryconfig("Edit parser rules", state="disabled")
        ConditionalsEditor(self.conditionals_editor, self.conditionals, self.closing_conditionals_editor)

    def closing_conditionals_editor(self):
        self.parser_menu.entryconfig("Edit parser rules", state="normal")


    def update_output_text(self, line):
        self.output_text.configure(state="normal")
        self.output_text.insert(END, line)
        self.output_text.configure(state="disabled")
        self.output_text.see(END)

    def evaluate_conditionals(self, line):
        if self.serial_parser_enabled.get() == 1:
            for condition in self.conditionals:
                if condition[0] == "Enabled":
                    if eval(condition[1]):
                        if condition[2] == "Python":
                            exec(condition[3], locals())
                        elif condition[2] == "Debugger":
                            print "Send to debugger: %s"%condition[3]



    def serial_tick(self):
        while True:
            try:
                line = self.serial_queue.get_nowait()
                self.update_output_text(line)
                self.evaluate_conditionals(line)
            except Queue.Empty:
                break
        self.after(100, self.serial_tick)

    def port_name_selected(self, event):
        port_name = event.widget.selection_get()
        if port_name == "Port":
            event.widget.current(newindex=self.port_name_selection_index)
            return
        self.port_name_selection_index = event.widget.current()
        self.serial_thread.set_port(port_name)

    def baudrate_selected(self, event):
        self.serial_thread.set_baudrate(event.widget.selection_get())
示例#4
0
class App(Frame):
    def __init__(self, master=None):
        self.master = master
        Frame.__init__(self, master, relief=SUNKEN, bd=2)

        self.gcode = []
        self.slicing = False
        self.printing = False
        self.connected = False
        self.monitorTemp = False
        self.paused = False
        self.sdpresent = False
        self.sdlisting = False
        self.sdchecking = False
        self.sdprinting = False
        self.sdpaused = False
        self.sduploading = False
        self.sdbytes = 0
        self.sdmaxbytes = 0
        self.insidelisting = False
        self.readingFirmware = False
        self.sdfiles = []
        self.bedtemp = float(0)
        self.bedtarget = float(0)
        self.exttemp = float(0)
        self.exttarget = float(0)
        self.acceleration = 0
        self.m114count = 0
        self.speedcount = 0
        self.location = [0, 0, 0, 0]
        self.pausePoint = [0, 0, 0, 0]
        self.percent = 0.0
        self.ets = "??"
        self.gcodeInfo = None
        self.GCodeFile = None
        self.StlFile = None
        self.Profile = None
        self.printStartLine = 0
        self.startTime = 0
        self.endTime = 0
        self.elapsedTime = 0
        self.FanSpeed = 0
        self.FeedMultiply = 100
        self.ExtrudeMultiply = 100

        self.timingReport = None
        self.filamentReport = None
        self.measurementsReport = None

        self.macroButtons = None

        self.rpt1re = re.compile(" *T:([0-9\.]+) *E:[0-9\.]+ *B:([0-9\.]+)")
        self.rpt2re = re.compile(" *T:([0-9\.]+) *E:[0-9\.]+ *W:.*")
        self.locrptre = re.compile("^X:([0-9\.\-]+)Y:([0-9\.\-]+)Z:([0-9\.\-]+)E:([0-9\.\-]+) *Count")
        self.speedrptre = re.compile("Fan speed:([0-9]+) Feed Multiply:([0-9]+) Extrude Multiply:([0-9]+)")

        self.sdre = re.compile("SD printing byte *([0-9]+) *\/ *([0-9]+)")

        self.printer = printcore()
        self.settings = Settings()
        self.settings.cmdFolder = cmd_folder
        self.logger = Logger(self)

        if self.settings.speedcommand is not None:
            allow_while_printing.append(self.settings.speedcommand)

        self.acceleration = self.settings.acceleration

        self.dataLoggers = {}
        for d in DLLIST:
            self.dataLoggers[d] = DataLogger(self, d)

        self.skeinforge = Skeinforge(self.settings)
        self.slic3r = Slic3r(self.settings)

        self.httpServer = RepRapServer(self, self.printer, self.settings, self.logger, self.settings.port)

        self.menubar = Menu(self)
        self.filemenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="File", menu=self.filemenu)
        self.filemenu.add_command(label="Slice", command=self.openSTLFile)
        self.filemenu.add_command(label="Load GCode", command=self.openGCodeFile)
        self.slicemenuindex = self.filemenu.index("Slice")
        self.loadgcodemenuindex = self.filemenu.index("Load GCode")

        self.filemenu.add_separator()
        self.filemenu.add_command(label="Exit", command=self.quitApp)

        self.editmenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Edit", menu=self.editmenu)

        self.editmenu.add_command(label="Settings", command=self.editSettings)
        self.editmenu.add_command(label="Firmware Settings", command=self.FirmwareSettings)
        self.editmenu.add_separator()
        self.editmenu.add_command(label=GCODE_MENU_TEXT, command=self.doGEdit, state=DISABLED)

        self.slicermenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Slicer", menu=self.slicermenu)
        self.rbSlicer = StringVar()

        self.slicermenu.add_radiobutton(
            label="Skeinforge", command=self.selSlicer, value=SKEINFORGE, variable=self.rbSlicer
        )
        self.slicermenu.add_command(label="Settings", command=self.skeinforgeSettings)
        self.slicermenu.add_command(label="Choose Profile", command=self.chooseSFProfile)
        self.SFprofileindex = self.slicermenu.index("Choose Profile")
        self.setSFProfileMenuText()
        self.slicermenu.add_command(label="Alterations", command=self.doEditAlterations)

        self.slicermenu.add_separator()
        self.slicermenu.add_radiobutton(label="Slic3r", command=self.selSlicer, value=SLIC3R, variable=self.rbSlicer)
        self.slicermenu.add_command(label="Settings", command=self.slic3rSettings)
        self.slicermenu.add_command(label="Choose Profile", command=self.chooseS3Profile)
        self.S3profileindex = self.slicermenu.index("Choose Profile")
        self.setS3ProfileMenuText()

        self.rbSlicer.set(self.settings.slicer)

        self.macromenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Macros", menu=self.macromenu)
        self.macromenu.add_command(label="New", command=self.doNewMacro)
        self.macromenu.add_command(label="Edit", command=self.doEditMacro)
        self.macromenu.add_command(label="Delete", command=self.doDelMacro)
        self.macromenu.add_separator()
        self.cbShowMacroButtons = BooleanVar()
        self.cbShowMacroButtons.set(self.settings.showmacrobuttons)
        self.macromenu.add_checkbutton(
            label="Show Macro Buttons",
            command=self.doShowButtons,
            onvalue=True,
            offvalue=False,
            variable=self.cbShowMacroButtons,
        )
        self.macromenu.add_separator()
        self.runmacromenu = Menu(self.macromenu, tearoff=0)
        self.loadMacros()
        self.macromenu.add_cascade(label="Run", menu=self.runmacromenu)

        self.reportmenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="View", menu=self.reportmenu)
        self.cbShowPrevious = BooleanVar()
        self.cbShowPrevious.set(self.settings.showprevious)
        self.reportmenu.add_checkbutton(
            label="Show Previous Layer",
            command=self.toggleShowPrevious,
            onvalue=True,
            offvalue=False,
            variable=self.cbShowPrevious,
        )
        self.cbShowMoves = BooleanVar()
        self.cbShowMoves.set(self.settings.showmoves)
        self.reportmenu.add_checkbutton(
            label="Show Non-extrusion Moves",
            command=self.toggleShowMoves,
            onvalue=True,
            offvalue=False,
            variable=self.cbShowMoves,
        )
        self.reportmenu.add_separator()
        self.reportmenu.add_command(label="Show Hours of Usage", command=self.doDataLogReport)
        self.reportmenu.add_command(label="Reset Hours of Usage", command=self.doDataLogReset)
        self.reportmenu.add_separator()
        self.reportmenu.add_command(label="Layer by Layer Timing", command=self.doTimingReport)
        self.reportmenu.add_command(label="Layer by Layer Filament Usage", command=self.doFilamentReport)
        self.reportmenu.add_command(label="GCode Measurements", command=self.doMeasurementsReport)

        self.toolsmenu = Menu(self.menubar, tearoff=0)
        n = 0
        if self.settings.platercmd is not None:
            n += 1
            self.toolsmenu.add_command(label="Plater", command=self.doPlater)

        if self.settings.gcodeviewcmd is not None:
            n += 1
            self.toolsmenu.add_command(label="GCode Viewer", command=self.doGCodeView)

        if self.settings.stlviewcmd is not None:
            n += 1
            self.toolsmenu.add_command(label="STL Viewer", command=self.doSTLView)

        if self.settings.openscadcmd is not None:
            n += 1
            self.toolsmenu.add_command(label="OpenSCAD", command=self.doOpenSCAD)

        if n > 0:
            self.menubar.add_cascade(label="Tools", menu=self.toolsmenu)

        try:
            self.master.config(menu=self.menubar)
        except AttributeError:
            self.master.tk.call(master, "config", "-menu", self.menubar)

        self.toolbar = ToolBar(self, self.printer, self.settings, self.logger)
        self.toolbar.grid(row=1, column=1, columnspan=4, sticky=W)

        self.ctl = MoveControl(self, self.printer, self.settings, self.logger)
        self.ctl.grid(row=2, column=1, rowspan=3, sticky=N)

        self.extr = Extruder(self, self.printer, self.settings, self.logger)
        self.extr.grid(row=2, column=2, rowspan=1, sticky=N + E + W)

        self.temps = Temperatures(self, self.printer, self.settings, self.logger)
        self.temps.grid(row=3, column=2, rowspan=2, sticky=N + E + W)

        self.gc = GcFrame(self, None, [], self.settings, self.logger)
        self.gc.grid(row=2, column=3, rowspan=3, sticky=N)

        self.statline = Status(self, self.printer, self.settings, self.logger)
        self.statline.grid(row=5, column=1, columnspan=4, sticky=E + W)

        self.logger.grid(row=2, column=4, rowspan=2, sticky=N + E + W)

        self.sendgcode = SendGCode(self, self.printer, self.settings, self.logger)
        self.sendgcode.grid(row=4, column=4, sticky=N + E + W)

        self.printer.errorcb = self.errorcb
        self.printer.sendcb = self.sendcb
        self.printer.recvcb = self.recvcb

        self.sd = SDCard(self, self.printer, self.settings, self.logger)
        self.firmware = FirmwareParms(self, self.printer, self.settings, self.logger)
        self.bind(MWM_FIRMWARECOMPLETE, self.firmwareReportComplete)
        self.bind(MWM_SLICERCOMPLETE, self.sliceComplete)
        self.bind(MWM_GCODELOADCOMPLETE, self.loadgcodeFinished)
        self.bind(MWM_GEDITMEASURECOMPLETE, self.geditMeasureComplete)
        self.bind(MWM_REQUESTPOSITIONREPORT, self.requestPosition)

        self.doShowButtons()

    def doStopAll(self):
        self.toolbar.doPause()
        self.temps.doOffBed()
        self.temps.doOffExt()

    def requestPosition(self, *arg):
        self.m114count += 1
        self.printer.send_now("M400")  # finish all moves
        self.printer.send_now("M114")

    def doShowButtons(self):
        self.settings.showmacrobuttons = self.cbShowMacroButtons.get() == 1
        self.settings.setModified()
        if self.settings.showmacrobuttons:
            self.macroButtons = MacroButtons(self, self.printer, self.settings, self.logger)
        else:
            if self.macroButtons:
                self.macroButtons.close()
                self.macroButtons = None

    def toggleShowPrevious(self):
        self.settings.showprevious = self.cbShowPrevious.get() == 1
        self.settings.setModified()
        self.gc.drawCanvas()

    def toggleShowMoves(self):
        self.settings.showmoves = self.cbShowMoves.get() == 1
        self.settings.setModified()
        self.gc.drawCanvas()

    def selSlicer(self):
        self.settings.slicer = self.rbSlicer.get()
        self.settings.setModified()
        self.toolbar.setSliceText()

    def macroButtonClose(self):
        self.settings.showmacrobuttons = False
        self.settings.setModified()
        self.cbShowMacroButtons.set(False)

    def firmwareReportComplete(self, *arg):
        p = self.firmware.reportComplete()
        if p is not None:
            self.acceleration = p["m204_s"].getFlash()
            print "Retrieved acc value of ", self.acceleration

    def openSTLFile(self):
        if self.printing:
            self.logger.logMsg("Cannot open a new file while printing")
            return

        if self.StlFile is None:
            fn = askopenfilename(
                filetypes=[("STL files", "*.stl"), ("G Code files", "*.gcode")], initialdir=self.settings.lastdirectory
            )
        else:
            fn = askopenfilename(
                filetypes=[("STL files", "*.stl"), ("G Code files", "*.gcode")],
                initialdir=self.settings.lastdirectory,
                initialfile=os.path.basename(self.StlFile),
            )
        if fn:
            self.settings.lastdirectory = os.path.dirname(os.path.abspath(fn))
            self.settings.setModified()
            if fn.lower().endswith(".gcode"):
                self.StlFile = None
                self.loadgcode(fn)
            elif fn.lower().endswith(".stl"):
                self.StlFile = fn
                self.doSlice(fn)
            else:
                self.logger.logMsg("Invalid file type")

    def openGCodeFile(self):
        if self.printing:
            self.logger.logMsg("Cannot open a new file while printing")
            return

        fn = askopenfilename(filetypes=[("G Code files", "*.gcode")], initialdir=self.settings.lastdirectory)
        if fn:
            self.settings.lastdirectory = os.path.dirname(os.path.abspath(fn))
            self.settings.setModified()
            if fn.lower().endswith(".gcode"):
                self.StlFile = None
                self.loadgcode(fn)
            else:
                self.logger.logMsg("Invalid file type")
        else:
            self.toolbar.clearCancelMode()

    def loadgcode(self, fn):
        self.GCodeFile = fn
        self.gcodeloadSuccess = True
        self.toolbar.setLoading(True)
        self.loader = threading.Thread(target=self.loadgcodeThread)
        self.loader.daemon = True
        self.loader.start()

    def loadgcodeFinished(self, *arg):
        self.toolbar.setLoading(False)
        if self.gcodeloadSuccess:
            self.showMetrics()

    def loadgcodeThread(self):
        try:
            self.gcode = []
            l = list(open(self.GCodeFile))
            for s in l:
                self.gcode.append(s.rstrip())
            self.logger.logMsg("read %d lines from %s" % (len(self.gcode), os.path.basename(self.GCodeFile)))
        except:
            self.logger.logMsg("Problem reading gcode from %s" % self.GCodeFile)
            self.gcode = []
            self.GCodeFile = None

        if len(self.gcode) != 0:
            self.logger.logMsg("Processing...")
            self.gc.loadFile(self.GCodeFile, self.gcode)
            self.printStartLine = self.gc.getPrintStartLine()
            self.gcodeInfo = GCode(self.gcode)
            self.logger.logMsg("Measuring...")
            self.gcodeInfo.measure(self.acceleration)
            self.estEta = self.gcodeInfo.totalduration
            self.timeLayers = self.gcodeInfo.layerdurations
        else:
            self.gcodeloadSuccess = False

        self.event_generate(MWM_GCODELOADCOMPLETE)

    def replace(self, s, slicer):
        if slicer == SLIC3R:
            d = os.path.expandvars(os.path.expanduser(self.settings.s3profiledir))
            profile = os.path.join(d, self.slic3r.getProfile() + ".ini")
        else:
            profile = self.skeinforge.getProfile()

        d = {}

        d["%starttime%"] = time.strftime("%H:%M:%S", time.localtime(self.startTime))
        d["%endtime%"] = time.strftime("%H:%M:%S", time.localtime(self.endTime))
        d["%elapsed%"] = formatElapsed(self.elapsedTime)

        d["%profile%"] = profile
        d["%slicer%"] = self.settings.slicer

        if self.StlFile is not None:
            d["%stlbase%"] = os.path.basename(self.StlFile)
            d["%stl%"] = self.StlFile
        else:
            d["%stlbase%"] = ""
            d["%stl%"] = ""

        if self.GCodeFile is not None:
            d["%gcodebase%"] = os.path.basename(self.GCodeFile)
            d["%gcode%"] = self.GCodeFile
        else:
            d["%gcodebase%"] = ""
            d["%gcode%"] = ""

        for t in d.keys():
            if d[t] is not None:
                s = s.replace(t, d[t])

        s = s.replace('""', "")
        return s

    def showMetrics(self):
        if len(self.gcode) != 0:
            self.paused = False
            self.toolbar.initializeToolbar()
            self.toolbar.checkAllowPrint()
            self.allowGEdit()

            self.logger.logMsg(
                "Width: %f mm (%f -> %f)" % (self.gcodeInfo.width, self.gcodeInfo.xmin, self.gcodeInfo.xmax)
            )
            self.logger.logMsg(
                "Depth: %f mm (%f -> %f)" % (self.gcodeInfo.depth, self.gcodeInfo.ymin, self.gcodeInfo.ymax)
            )
            self.logger.logMsg(
                "Height: is %f mm (%f -> %f)" % (self.gcodeInfo.height, self.gcodeInfo.zmin, self.gcodeInfo.zmax)
            )
            self.logger.logMsg("Total extrusion length: %f mm" % self.gcodeInfo.filament_length())

            self.logger.logMsg("Estimated print time: %s" % formatElapsed(self.estEta))

    def calcEta(self, line, timeThusFar):
        foundLayer = False
        for i in range(len(self.timeLayers)):
            if self.timeLayers[i][0] > line:
                foundLayer = True
                break

        if not foundLayer:
            return 0

        currentLayer = i - 1
        if currentLayer < 0:
            return 0

        totalInLayer = self.timeLayers[i][0] - self.timeLayers[currentLayer][0]
        printedInLayer = line - self.timeLayers[currentLayer][0]
        pct = printedInLayer / float(totalInLayer)
        thisLayerTime = (self.timeLayers[currentLayer][1]) * pct
        ratio = (self.timeLayers[currentLayer][2] - self.timeLayers[currentLayer][1] + thisLayerTime) / float(
            timeThusFar
        )
        ne = self.estEta / float(ratio)
        return ne - timeThusFar

    def doTimingReport(self):
        if not self.printing:
            self.logger.logMsg("Only available while printing")
            return

        self.timingReport = TimingReport(self, self.printer, self.settings, self.logger)

    def closeTimingReport(self):
        if self.timingReport is not None:
            self.timingReport.cleanup()
            self.timingReport.destroy()

        self.timingReport = None

    def doMeasurementsReport(self):
        if not self.gcodeInfo:
            self.logger.logMsg("Only available when GCode loaded")
            return

        self.measurementsReport = MeasurementsReport(self, self.printer, self.settings, self.logger)

    def closeMeasurementsReport(self):
        if self.measurementsReport is not None:
            self.measurementsReport.destroy()

        self.measurementsReport = None

    def doFilamentReport(self):
        if not self.gcodeInfo:
            self.logger.logMsg("Only available when GCode loaded")
            return
        if len(self.gcodeInfo.filLayers) == 0:
            self.logger.logMsg("No filament usage in this gcode")
            return

        self.filamentReport = FilamentReport(self, self.printer, self.settings, self.logger)

    def closeFilamentReport(self):
        if self.filamentReport is not None:
            self.filamentReport.destroy()

        self.filamentReport = None

    def closeAllReports(self):
        self.closeTimingReport()
        self.closeFilamentReport()
        self.closeMeasurementsReport()

    def doPlater(self):
        s = self.replace(self.settings.platercmd, self.settings.slicer)
        args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
        subprocess.Popen(args, close_fds=True)

    def doGCodeView(self):
        s = self.replace(self.settings.gcodeviewcmd, self.settings.slicer)
        args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
        subprocess.Popen(args, close_fds=True)

    def doSTLView(self):
        s = self.replace(self.settings.stlviewcmd, self.settings.slicer)
        self.logger.logMsg(s)
        args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
        subprocess.Popen(args, close_fds=True)

    def doOpenSCAD(self):
        s = self.replace(self.settings.openscadcmd, self.settings.slicer)
        args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
        subprocess.Popen(args, close_fds=True)

    def doSlice(self, fn):
        self.paused = False
        self.toolbar.initializeToolbar()
        self.slicerfn = fn
        self.slicing = True
        self.slicerCancel = False
        self.toolbar.setCancelMode()
        if self.settings.slicer == SLIC3R:
            self.GCodeFile = fn.replace(".stl", ".gcode")
            cmd = self.replace(os.path.expandvars(os.path.expanduser(self.settings.s3cmd)), SLIC3R)
        else:
            self.GCodeFile = fn.replace(".stl", "_export.gcode")
            cmd = self.replace(os.path.expandvars(os.path.expanduser(self.settings.sfcmd)), SKEINFORGE)
        self.slicer = threading.Thread(target=self.slicerThread, args=(cmd,))
        self.slicer.daemon = True
        self.slicer.start()

    def slicerThread(self, cmd):
        args = shlex.split(cmd)
        p = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
        obuf = ""
        while not self.slicerCancel:
            o = p.stdout.read(1)
            if o == "":
                break
            if o == "\r" or o == "\n":
                self.logger.logMsg(obuf)
                obuf = ""
            elif ord(o) < 32:
                pass
            else:
                obuf += o

        if self.slicerCancel:
            p.kill()

        p.wait()
        self.event_generate(MWM_SLICERCOMPLETE)

    def sliceComplete(self, *arg):
        self.slicing = False
        self.toolbar.clearCancelMode()
        if self.slicerCancel:
            self.slicerCancel = False
            self.logger.logMsg("Slicing was cancelled")
            return

        self.logger.logMsg("Slicing has completed successfully")
        if os.path.exists(self.GCodeFile):
            self.loadgcode(self.GCodeFile)
        else:
            self.logger.logMsg("Unable to find slicer output file: %s" % self.GCodeFile)

    def allowGEdit(self):
        self.editmenu.entryconfig(self.editmenu.index(GCODE_MENU_TEXT), state=NORMAL)

    def allowSliceMenu(self, flag=True):
        s = NORMAL
        if not flag:
            s = DISABLED
        self.filemenu.entryconfig(self.slicemenuindex, state=s)

    def allowLoadGCodeMenu(self, flag=True):
        s = NORMAL
        if not flag:
            s = DISABLED
        self.filemenu.entryconfig(self.loadgcodemenuindex, state=s)

    def doGEdit(self):
        GEditor(self, self.gcode, None)

    def geditMeasureComplete(self, *arg):
        self.showMetrics()

    def gEditSave(self, newgcode, fn, editwindow):
        if fn == None:
            self.gcode = newgcode
            self.meas = threading.Thread(target=self.geditMeasureThread)
            self.meas.daemon = True
            self.meas.start()
            return False
        else:
            try:
                f = open(fn, "w")
                for l in newgcode:
                    f.write(l + "\n")
                f.close()
                self.logger.logMsg("Alterations %s successfully saved" % fn)
                return True
            except:
                self.logger.logMsg("Unable to open %s for output" % fn)
                return False

    def geditMeasureThread(self):
        self.logger.logMsg("Processing...")
        self.gcodeInfo = GCode(self.gcode)
        self.logger.logMsg("Measuring...")
        self.gcodeInfo.measure(self.acceleration)
        self.estEta = self.gcodeInfo.totalduration
        self.timeLayers = self.gcodeInfo.layerdurations
        self.event_generate(MWM_GEDITMEASURECOMPLETE)

    def doSD(self):
        if not self.sd.isActive():
            self.sd.start()

    def setToolbarSDPrint(self):
        self.toolbar.setSDPrint()

    def startUpload(self):
        self.sduploading = True
        self.toolbar.doPrint()

    def printerAvailable(self, silent=False, cmd="xx"):
        if not self.connected:
            if not silent:
                self.logger.logMsg("Unable to comply - printer not on-line")
            return False
        if (self.printing or self.sdprinting) and cmd.upper() not in allow_while_printing:
            if not silent:
                self.logger.logMsg("Unable to comply - currently printing")
            return False

        return True

    def printerConnected(self, flag):
        self.sendgcode.activate(flag)
        self.connected = flag
        if flag:
            self.firmware.start(True)

    def updateScreen(self):
        if self.printing:
            self.gc.updatePrintProgress(self.printer.queueindex)

    def errorcb(self, s):
        self.logger.logMsg(s.rstrip())

    def sendcb(self, s):
        # self.logger.logMsg("Sent: %s" % s)
        pass

    def recvcb(self, s):
        if self.readingFirmware:
            if "M92" in s:
                X = self.parseG(s, "X")
                Y = self.parseG(s, "Y")
                Z = self.parseG(s, "Z")
                E = self.parseG(s, "E")
                self.firmware.m92(X, Y, Z, E)
                return
            elif "M201" in s:
                X = self.parseG(s, "X")
                Y = self.parseG(s, "Y")
                Z = self.parseG(s, "Z")
                E = self.parseG(s, "E")
                self.firmware.m201(X, Y, Z, E)
                return
            elif "M203" in s:
                X = self.parseG(s, "X")
                Y = self.parseG(s, "Y")
                Z = self.parseG(s, "Z")
                E = self.parseG(s, "E")
                self.firmware.m203(X, Y, Z, E)
                return
            elif "M204" in s:
                S = self.parseG(s, "S")
                T = self.parseG(s, "T")
                self.firmware.m204(S, T)
                return
            elif "M205" in s:
                S = self.parseG(s, "S")
                T = self.parseG(s, "T")
                B = self.parseG(s, "B")
                X = self.parseG(s, "X")
                Z = self.parseG(s, "Z")
                E = self.parseG(s, "E")
                self.firmware.m205(S, T, B, X, Z, E)
                return
            elif "M206" in s:
                X = self.parseG(s, "X")
                Y = self.parseG(s, "Y")
                Z = self.parseG(s, "Z")
                self.firmware.m206(X, Y, Z)
                return
            elif "M301" in s:
                P = self.parseG(s, "P")
                I = self.parseG(s, "I")
                D = self.parseG(s, "D")
                self.firmware.m301(P, I, D)
                return
            elif (
                ("Steps per unit" in s)
                or ("Acceleration:" in s)
                or ("Maximum Acceleration" in s)
                or ("Maximum feedrates" in s)
                or ("Advanced variables" in s)
                or ("Home offset" in s)
                or ("PID settings" in s)
                or ("Stored settings retreived" in s)
            ):
                return

        if self.sdchecking:
            if "SD card ok" in s:
                self.sdchecking = False
                self.sdpresent = True
                self.sd.sdCheckComplete(True)
                return
            elif "SD init fail" in s:
                self.sdchecking = False
                self.sdpresent = False
                self.sd.sdCheckComplete(False)
                return

        if self.sdlisting:
            if "Begin file list" in s:
                self.insidelisting = True
                self.sdfiles = []
                return
            elif "End file list" in s:
                self.sdlisting = False
                self.insidelisting = False
                self.sd.sdListComplete(self.sdfiles)
                return
            else:
                if self.insidelisting:
                    self.sdfiles.append(s.strip())
                    return

        if "SD printing byte" in s:
            m = self.sdre.search(s)
            t = m.groups()
            if len(t) != 2:
                return

            self.sdbytes = int(t[0])
            self.sdmaxbytes = int(t[1])
            return

        elif "Done printing file" in s:
            if self.sdprinting:
                self.sdprinting = False
                self.toolbar.clearSDPrint()

        m = self.speedrptre.search(s)
        if m:
            t = m.groups()
            if len(t) >= 3:
                if self.settings.forcefanspeed:
                    ns = int(t[0])
                    if ns != self.FanSpeed:
                        self.logger.logMsg("Asserting fan speed of %d" % self.FanSpeed)
                        self.toolbar.forceFanSpeed(self.FanSpeed)
                else:
                    self.FanSpeed = int(t[0])

                self.FeedMultiply = int(t[1])
                self.ExtrudeMultiply = int(t[2])
                self.toolbar.syncSpeeds()
                if self.speedcount > 0:
                    self.speedcount -= 1
                    return

        m = self.locrptre.search(s)
        if m:
            t = m.groups()
            if len(t) >= 4:
                self.location[XAxis] = float(t[0])
                self.location[YAxis] = float(t[1])
                self.location[ZAxis] = float(t[2])
                self.location[EAxis] = float(t[3])
                if self.m114count != 0:
                    self.m114count -= 1
                    if self.m114count < 0:
                        self.m114count = 0
                    return

        if s.startswith("ok"):
            return

        if s.startswith("echo:"):
            s = s[5:]

        m = self.rpt1re.search(s)
        if m:
            t = m.groups()
            if len(t) >= 1:
                self.exttemp = float(t[0])
            if len(t) >= 2:
                self.bedtemp = float(t[1])
            self.temps.updateTempDisplay(self.bedtemp, self.exttemp)

        m = self.rpt2re.search(s)
        if m:
            t = m.groups()
            if len(t) >= 1:
                self.exttemp = float(t[0])
            self.temps.updateTempDisplay(self.bedtemp, self.exttemp)

        self.logger.logMsg(s.rstrip())

    def parseG(self, s, v):
        l = s.split()
        for p in l:
            if p.startswith(v):
                try:
                    return float(p[1:])
                except:
                    return None
        return None

    def editSettings(self):
        # TO DO
        pass

    def slic3rSettings(self):
        s = self.replace(self.settings.s3config, SLIC3R)
        args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
        subprocess.Popen(args, close_fds=True)

    def skeinforgeSettings(self):
        s = self.replace(self.settings.sfconfig, SKEINFORGE)
        args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
        subprocess.Popen(args, close_fds=True)

    def chooseS3Profile(self):
        pl = self.slic3r.getProfileOptions()
        if len(pl) > 0:
            l = ListBoxChoice(
                clist=pl.keys(), master=self, title="Choose Slic3r Profile", message="Choose Slic3r profile"
            )
            pn = l.returnValue()
            if pn:
                self.slic3r.setProfile(pn)
                self.setS3ProfileMenuText()
                self.toolbar.setSliceText()
        else:
            self.logger.logMsg("Unable to retrieve available slic3r profiles")

    def chooseSFProfile(self):
        pl = self.skeinforge.getProfileOptions()
        if len(pl) > 0:
            l = ListBoxChoice(
                clist=pl.keys(), master=self, title="Choose Skeinforge Profile", message="Choose Skeinforge profile"
            )
            pn = l.returnValue()
            if pn:
                self.skeinforge.setProfile(pn)
                self.setSFProfileMenuText()
                self.toolbar.setSliceText()
        else:
            self.logger.logMsg("Unable to retrieve available skeinforge profiles")

    def setS3ProfileMenuText(self):
        self.slicermenu.entryconfig(self.S3profileindex, label="Choose Profile (%s)" % self.slic3r.getProfile())

    def setSFProfileMenuText(self):
        self.slicermenu.entryconfig(self.SFprofileindex, label="Choose Profile (%s)" % self.skeinforge.getProfile())

    def quitApp(self):
        self.cleanUp()
        self.master.quit()

    def cleanUp(self):
        if self.connected:
            self.printer.disconnect()
        if self.slicing:
            self.slicerCancel = True
        self.httpServer.close()
        self.statline.cleanUp()
        self.settings.cleanUp()

    def doEditMacro(self):
        idir = os.path.join(self.settings.cmdFolder, "macros")
        try:
            l = os.listdir(idir)
        except:
            self.logger.logMsg("Unable to get listing from macros directory: " + idir)
            return
        r = []
        for f in sorted(l):
            if f.endswith(".macro"):
                r.append(f)

        l = ListBoxChoice(master=self, title="Macro Files", message="Choose a macro to edit", clist=r)
        fn = l.returnValue()
        if fn:
            try:
                fn = os.path.join(idir, fn)
                with open(fn) as f:
                    text = f.read()
                self.macroEdit = MacroEdit(self, self.printer, self.settings, self.logger, fn, text)
            except:
                self.logger.logMsg("Unable to open %s for input" % fn)

    def doEditAlterations(self):
        idir = os.path.expandvars(os.path.expanduser(self.settings.sfalterationsdir))
        try:
            l = os.listdir(idir)
        except:
            self.logger.logMsg("Unable to get listing from alterations directory: " + idir)
            return
        r = []
        for f in sorted(l):
            if f.endswith(".gcode"):
                r.append(f)

        l = ListBoxChoice(master=self, title="Alteration Files", message="Choose an alteration file to edit", clist=r)
        fn = l.returnValue()
        if fn:
            try:
                fn = os.path.join(idir, fn)
                text = [line.strip() for line in open(fn)]
                GEditor(self, text, fn)
            except:
                self.logger.logMsg("Unable to open %s for input" % fn)

    def doNewMacro(self):
        self.macroEdit = MacroEdit(self, self.printer, self.settings, self.logger, None, "")

    def doDelMacro(self):
        idir = os.path.join(self.settings.cmdFolder, "macros")
        try:
            l = os.listdir(idir)
        except:
            self.logger.logMsg("Unable to get listing from macros directory: " + idir)
            return
        r = []
        for f in sorted(l):
            if f.endswith(".macro"):
                r.append(f)

        l = ListBoxChoice(master=self, title="Macro Files", message="Choose a macro to delete", clist=r)
        fn = l.returnValue()
        if fn:
            if askyesno("Delete?", "Are you sure you want to delete this macro?", parent=self):
                try:
                    os.unlink(os.path.join(idir, fn))
                    self.adjustMacroMenu(fn, True)
                    if self.settings.getMacroList().delMacroByName(fn):
                        self.settings.setModified()
                        if self.settings.showmacrobuttons:
                            self.macroButtons.close()
                            self.macroButtons = MacroButtons(self, self.printer, self.settings, self.logger)
                except:
                    self.logger.logMsg("Unable to delete %s" % fn)

    def macroEditSave(self, fn, text, btn, editwindow):
        if fn == None:
            idir = os.path.join(self.settings.cmdFolder, "macros")

            try:
                l = os.listdir(idir)
            except:
                self.logger.logMsg("Unable to get listing from macros directory: " + idir)
                return

            r = []
            for f in sorted(l):
                if f.endswith(".macro"):
                    r.append(f)

            l = ListBoxChoice(
                master=self,
                title="Macro Files",
                message="Choose a macro to overwrite",
                clist=r,
                newmessage="or enter new file name:",
            )
            fn = l.returnValue()
            if fn:
                fn = os.path.join(idir, fn)
                if not fn.endswith(".macro"):
                    fn += ".macro"

        if fn is None:
            return False

        try:
            f = open(fn, "w")
            f.write(text)
            f.close()
            self.settings.setModified()
            if btn != None:
                if not self.settings.getMacroList().addMacro(btn[0], btn[1], os.path.basename(fn), btn[2]):
                    self.settings.getMacroList().setMacroByName(btn[0], btn[1], os.path.basename(fn), btn[2])
                self.settings.setModified()

                if self.settings.showmacrobuttons:
                    self.macroButtons.close()
                    self.macroButtons = MacroButtons(self, self.printer, self.settings, self.logger)

            self.adjustMacroMenu(fn)
            self.logger.logMsg("Macro %s successfully saved" % fn)
            return True
        except:
            self.logger.logMsg("Unable to open %s for output" % fn)
            return False

    def macroEditExit(self, fn):
        pass

    def loadMacros(self):
        p = os.path.join(".", "macros")
        if not os.path.exists(p):
            os.makedirs(p)

        self.macroList = {}
        for filename in sorted(os.listdir(p)):
            if filename.endswith(".macro"):
                n = os.path.splitext(filename)[0]
                self.macroList[n] = 1
                self.runmacromenu.add_command(label=n, command=lambda m=n: self.doMacro(m))

    def adjustMacroMenu(self, fn, delete=False):
        mn = os.path.splitext(os.path.basename(fn))[0]

        if not delete:
            if mn in self.macroList:
                # nothing to be done here
                pass
            else:
                self.macroList[mn] = 1
                self.runmacromenu.add_command(label=mn, command=lambda m=mn: self.doMacro(name=mn))
        else:
            # delete the menu entry
            if mn in self.macroList:
                self.runmacromenu.delete(self.runmacromenu.index(mn))
                del self.macroList[mn]
            else:
                # huh??
                pass

    def doMacro(self, name=None, fname=None, silent=False):
        if name:
            if not silent:
                self.logger.logMsg("Invoking macro: %s" % name)
            n = os.path.join(self.settings.cmdFolder, "macros", name + ".macro")
        elif fname:
            if not silent:
                self.logger.logMsg("Invoking macro file: %s" % fname)
            n = os.path.join(self.settings.cmdFolder, "macros", fname)
        else:
            self.logger.logMsg("Error - must provide a macro name or filename")
            return

        try:
            l = list(open(n))
            for s in l:
                sl = s.lower()
                if sl.startswith("@log "):
                    self.logger.logMsg(self.replace(s[5:].strip(), self.settings.slicer))
                elif sl.startswith("@sh "):
                    s = self.replace(sl[4:], self.settings.slicer)
                    args = shlex.split(os.path.expandvars(os.path.expanduser(s)))
                    subprocess.Popen(args, close_fds=True)
                else:
                    verb = s.split()[0]
                    if self.printerAvailable(cmd=verb):
                        self.printer.send_now(s)
                    else:
                        self.logger.logMsg("Printer not available for %s command" % verb)

            if not silent:
                self.logger.logMsg("End of macro")
        except:
            self.logger.logMsg("Error attempting to invoke macro file %s" % n)

    def FirmwareSettings(self):
        if self.connected:
            if not self.firmware.isActive():
                self.firmware.start()
        else:
            self.logger.logMsg("Unable to comply - printer not on-line")

    def doDataLogReport(self):
        for d in DLLIST:
            self.logger.logMsg("%s Usage: %s" % (DLNAMES[d], self.dataLoggers[d].getToNowStr()))

    def doDataLogReset(self):
        DataLogReset(self)
示例#5
0
menu = Menu(root)
acctMenu = Menu(menu, tearoff=0)
menu.add_command(label="Update", command=oneShotUpdate)
menu.add_command(label="Console", command=showConsole)
menu.add_command(label="Search", command=hashThreader)
menu.add_command(label="Delete last tweet", command=delThreader)
menu.add_command(label="Shorten link", command=shortThreader)
menu.add_cascade(label="Accounts", menu=acctMenu)
menu.add_separator()
menu.add_command(label="Quit", command=lambda: quit(UPDATE_THREAD))

for acct in cred_man.getScreenNames():
        acctMenu.add_command(label=acct, command=lambda: switchToAcct(acct))

acctMenu.entryconfig(0, label="*" + acctMenu.entrycget(0, "label"))

acctMenu.add_command(label="Add Account", command=addAccount)

root.config(menu=menu)

#
# END OF TK GUI STUFF
#

# tries to start a thread that will keep the character count
#  see the docs on the numbers function
try:
        NUMBER_THREAD = upThread(1, "numbers", entry)
        NUMBER_THREAD.start()
except: