chiark / gitweb /
Change how the engine is interfaced from the python code. Put the GCode viewer in...
[cura.git] / Cura / gui / printWindow.py
index 1a4818baf028d6d2bfcd3954638d852baeb0b48e..1a0e2cbe116c63a3b67bb6a8ac49c121a8a23609 100644 (file)
@@ -18,20 +18,23 @@ from Cura.gui.util import webcam
 from Cura.gui.util import taskbar
 from Cura.util import machineCom
 from Cura.util import gcodeInterpreter
 from Cura.gui.util import taskbar
 from Cura.util import machineCom
 from Cura.util import gcodeInterpreter
-from Cura.util.resources import getPathForImage
+from Cura.util import resources
+from Cura.util import profile
 
 #The printProcessMonitor is used from the main GUI python process. This monitors the printing python process.
 # This class also handles starting of the 2nd process for printing and all communications with it.
 class printProcessMonitor():
 
 #The printProcessMonitor is used from the main GUI python process. This monitors the printing python process.
 # This class also handles starting of the 2nd process for printing and all communications with it.
 class printProcessMonitor():
-       def __init__(self):
+       def __init__(self, callback = None):
                self.handle = None
                self._state = 'CLOSED'
                self._z = 0.0
                self.handle = None
                self._state = 'CLOSED'
                self._z = 0.0
+               self._callback = callback
+               self._id = -1
 
 
-       def loadFile(self, filename):
+       def loadFile(self, filename, id):
                if self.handle is None:
                        if platform.system() == "Darwin" and hasattr(sys, 'frozen'):
                if self.handle is None:
                        if platform.system() == "Darwin" and hasattr(sys, 'frozen'):
-                               cmdList = [os.path.join(os.path.dirname(sys.executable), 'Cura')] 
+                               cmdList = [os.path.join(os.path.dirname(sys.executable), 'Cura')]
                        else:
                                cmdList = [sys.executable, '-m', 'Cura.cura']
                        cmdList.append('-r')
                        else:
                                cmdList = [sys.executable, '-m', 'Cura.cura']
                        cmdList.append('-r')
@@ -40,24 +43,31 @@ class printProcessMonitor():
                                if platform.machine() == 'i386':
                                        cmdList.insert(0, 'arch')
                                        cmdList.insert(1, '-i386')
                                if platform.machine() == 'i386':
                                        cmdList.insert(0, 'arch')
                                        cmdList.insert(1, '-i386')
+                       #Save the preferences before starting the print window so we use the proper machine settings.
+                       profile.savePreferences(profile.getPreferencePath())
                        self.handle = subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                        self.thread = threading.Thread(target=self.Monitor)
                        self.thread.start()
                else:
                        self.handle.stdin.write('LOAD:%s\n' % filename)
                        self.handle = subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                        self.thread = threading.Thread(target=self.Monitor)
                        self.thread.start()
                else:
                        self.handle.stdin.write('LOAD:%s\n' % filename)
+               self._id = id
 
        def Monitor(self):
                p = self.handle
                line = p.stdout.readline()
                while len(line) > 0:
 
        def Monitor(self):
                p = self.handle
                line = p.stdout.readline()
                while len(line) > 0:
+                       line = line.rstrip()
                        try:
                                if line.startswith('Z:'):
                                        self._z = float(line[2:])
                        try:
                                if line.startswith('Z:'):
                                        self._z = float(line[2:])
+                                       self._callCallback()
                                elif line.startswith('STATE:'):
                                elif line.startswith('STATE:'):
-                                       self._state = float(line[6:])
+                                       self._state = line[6:]
+                                       self._callCallback()
+                               else:
+                                       print '>' + line.rstrip()
                        except:
                        except:
-                               pass
-                       #print '>' + line.rstrip()
+                               print sys.exc_info()
                        line = p.stdout.readline()
                line = p.stderr.readline()
                while len(line) > 0:
                        line = p.stdout.readline()
                line = p.stderr.readline()
                while len(line) > 0:
@@ -67,10 +77,27 @@ class printProcessMonitor():
                self.handle = None
                self.thread = None
 
                self.handle = None
                self.thread = None
 
+       def getID(self):
+               return self._id
+
+       def getZ(self):
+               return self._z
+
+       def getState(self):
+               return self._state
+
+       def _callCallback(self):
+               if self._callback is not None:
+                       self._callback()
+
 def startPrintInterface(filename):
        #startPrintInterface is called from the main script when we want the printer interface to run in a separate process.
        # It needs to run in a separate process, as any running python code blocks the GCode sender python code (http://wiki.python.org/moin/GlobalInterpreterLock).
 def startPrintInterface(filename):
        #startPrintInterface is called from the main script when we want the printer interface to run in a separate process.
        # It needs to run in a separate process, as any running python code blocks the GCode sender python code (http://wiki.python.org/moin/GlobalInterpreterLock).
+
+       sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
        app = wx.App(False)
        app = wx.App(False)
+       resources.setupLocalization(profile.getPreference('language'))
        printWindowHandle = printWindow()
        printWindowHandle.Show(True)
        printWindowHandle.Raise()
        printWindowHandle = printWindow()
        printWindowHandle.Show(True)
        printWindowHandle.Raise()
@@ -82,7 +109,7 @@ def startPrintInterface(filename):
 
 class PrintCommandButton(buttons.GenBitmapButton):
        def __init__(self, parent, commandList, bitmapFilename, size=(20, 20)):
 
 class PrintCommandButton(buttons.GenBitmapButton):
        def __init__(self, parent, commandList, bitmapFilename, size=(20, 20)):
-               self.bitmap = wx.Bitmap(getPathForImage(bitmapFilename))
+               self.bitmap = wx.Bitmap(resources.getPathForImage(bitmapFilename))
                super(PrintCommandButton, self).__init__(parent.directControlPanel, -1, self.bitmap, size=size)
 
                self.commandList = commandList
                super(PrintCommandButton, self).__init__(parent.directControlPanel, -1, self.bitmap, size=size)
 
                self.commandList = commandList
@@ -105,7 +132,8 @@ class printWindow(wx.Frame):
        "Main user interface window"
 
        def __init__(self):
        "Main user interface window"
 
        def __init__(self):
-               super(printWindow, self).__init__(None, -1, title='Printing')
+               super(printWindow, self).__init__(None, -1, title=_("Printing"))
+               t = time.time()
                self.machineCom = None
                self.gcode = None
                self.gcodeList = None
                self.machineCom = None
                self.gcode = None
                self.gcodeList = None
@@ -123,10 +151,6 @@ class printWindow(wx.Frame):
                self.termHistoryIdx = 0
 
                self.cam = None
                self.termHistoryIdx = 0
 
                self.cam = None
-               if webcam.hasWebcamSupport():
-                       self.cam = webcam.webcam()
-                       if not self.cam.hasCamera():
-                               self.cam = None
 
                self.SetSizer(wx.BoxSizer())
                self.panel = wx.Panel(self)
 
                self.SetSizer(wx.BoxSizer())
                self.panel = wx.Panel(self)
@@ -134,12 +158,12 @@ class printWindow(wx.Frame):
                self.sizer = wx.GridBagSizer(2, 2)
                self.panel.SetSizer(self.sizer)
 
                self.sizer = wx.GridBagSizer(2, 2)
                self.panel.SetSizer(self.sizer)
 
-               sb = wx.StaticBox(self.panel, label="Statistics")
+               sb = wx.StaticBox(self.panel, label=_("Statistics"))
                boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
 
                self.powerWarningText = wx.StaticText(parent=self.panel,
                        id=-1,
                boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
 
                self.powerWarningText = wx.StaticText(parent=self.panel,
                        id=-1,
-                       label="Your computer is running on battery power.\nConnect your computer to AC power or your print might not finish.",
+                       label=_("Your computer is running on battery power.\nConnect your computer to AC power or your print might not finish."),
                        style=wx.ALIGN_CENTER)
                self.powerWarningText.SetBackgroundColour('red')
                self.powerWarningText.SetForegroundColour('white')
                        style=wx.ALIGN_CENTER)
                self.powerWarningText.SetBackgroundColour('red')
                self.powerWarningText.SetForegroundColour('white')
@@ -150,17 +174,17 @@ class printWindow(wx.Frame):
                self.OnPowerWarningChange(None)
                self.powerWarningTimer.Start(10000)
 
                self.OnPowerWarningChange(None)
                self.powerWarningTimer.Start(10000)
 
-               self.statsText = wx.StaticText(self.panel, -1, "Filament: ####.##m #.##g\nEstimated print time: #####:##\nMachine state:\nDetecting baudrateXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
+               self.statsText = wx.StaticText(self.panel, -1, _("Filament: ####.##m #.##g\nEstimated print time: #####:##\nMachine state:\nDetecting baudrateXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"))
                boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)
 
                self.sizer.Add(boxsizer, pos=(0, 0), span=(7, 1), flag=wx.EXPAND)
 
                boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)
 
                self.sizer.Add(boxsizer, pos=(0, 0), span=(7, 1), flag=wx.EXPAND)
 
-               self.connectButton = wx.Button(self.panel, -1, 'Connect')
+               self.connectButton = wx.Button(self.panel, -1, _("Connect"))
                #self.loadButton = wx.Button(self.panel, -1, 'Load')
                #self.loadButton = wx.Button(self.panel, -1, 'Load')
-               self.printButton = wx.Button(self.panel, -1, 'Print')
-               self.pauseButton = wx.Button(self.panel, -1, 'Pause')
-               self.cancelButton = wx.Button(self.panel, -1, 'Cancel print')
-               self.machineLogButton = wx.Button(self.panel, -1, 'Error log')
+               self.printButton = wx.Button(self.panel, -1, _("Print"))
+               self.pauseButton = wx.Button(self.panel, -1, _("Pause"))
+               self.cancelButton = wx.Button(self.panel, -1, _("Cancel print"))
+               self.machineLogButton = wx.Button(self.panel, -1, _("Error log"))
                self.progress = wx.Gauge(self.panel, -1)
 
                self.sizer.Add(self.connectButton, pos=(1, 1), flag=wx.EXPAND)
                self.progress = wx.Gauge(self.panel, -1)
 
                self.sizer.Add(self.connectButton, pos=(1, 1), flag=wx.EXPAND)
@@ -172,6 +196,7 @@ class printWindow(wx.Frame):
                self.sizer.Add(self.progress, pos=(7, 0), span=(1, 7), flag=wx.EXPAND)
 
                nb = wx.Notebook(self.panel)
                self.sizer.Add(self.progress, pos=(7, 0), span=(1, 7), flag=wx.EXPAND)
 
                nb = wx.Notebook(self.panel)
+               self.tabs = nb
                self.sizer.Add(nb, pos=(0, 2), span=(7, 4), flag=wx.EXPAND)
 
                self.temperaturePanel = wx.Panel(nb)
                self.sizer.Add(nb, pos=(0, 2), span=(7, 4), flag=wx.EXPAND)
 
                self.temperaturePanel = wx.Panel(nb)
@@ -180,8 +205,8 @@ class printWindow(wx.Frame):
 
                self.temperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
                self.temperatureSelect.SetRange(0, 400)
 
                self.temperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
                self.temperatureSelect.SetRange(0, 400)
-               self.temperatureHeatUpPLA = wx.Button(self.temperaturePanel, -1, '210C')
-               self.bedTemperatureLabel = wx.StaticText(self.temperaturePanel, -1, "BedTemp:")
+               self.temperatureHeatUp = wx.Button(self.temperaturePanel, -1, str(int(profile.getProfileSettingFloat('print_temperature'))) + 'C')
+               self.bedTemperatureLabel = wx.StaticText(self.temperaturePanel, -1, _("BedTemp:"))
                self.bedTemperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
                self.bedTemperatureSelect.SetRange(0, 400)
                self.bedTemperatureLabel.Show(False)
                self.bedTemperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
                self.bedTemperatureSelect.SetRange(0, 400)
                self.bedTemperatureLabel.Show(False)
@@ -189,9 +214,9 @@ class printWindow(wx.Frame):
 
                self.temperatureGraph = temperatureGraph(self.temperaturePanel)
 
 
                self.temperatureGraph = temperatureGraph(self.temperaturePanel)
 
-               sizer.Add(wx.StaticText(self.temperaturePanel, -1, "Temp:"), pos=(0, 0))
+               sizer.Add(wx.StaticText(self.temperaturePanel, -1, _("Temp:")), pos=(0, 0))
                sizer.Add(self.temperatureSelect, pos=(0, 1))
                sizer.Add(self.temperatureSelect, pos=(0, 1))
-               sizer.Add(self.temperatureHeatUpPLA, pos=(0, 2))
+               sizer.Add(self.temperatureHeatUp, pos=(0, 2))
                sizer.Add(self.bedTemperatureLabel, pos=(1, 0))
                sizer.Add(self.bedTemperatureSelect, pos=(1, 1))
                sizer.Add(self.temperatureGraph, pos=(2, 0), span=(1, 3), flag=wx.EXPAND)
                sizer.Add(self.bedTemperatureLabel, pos=(1, 0))
                sizer.Add(self.bedTemperatureSelect, pos=(1, 1))
                sizer.Add(self.temperatureGraph, pos=(2, 0), span=(1, 3), flag=wx.EXPAND)
@@ -237,7 +262,7 @@ class printWindow(wx.Frame):
                sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E-2 F120'], 'retract.png', size=(60, 20)), pos=(2, 10),
                        span=(1, 3), flag=wx.EXPAND)
 
                sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E-2 F120'], 'retract.png', size=(60, 20)), pos=(2, 10),
                        span=(1, 3), flag=wx.EXPAND)
 
-               nb.AddPage(self.directControlPanel, 'Jog')
+               nb.AddPage(self.directControlPanel, _("Jog"))
 
                self.speedPanel = wx.Panel(nb)
                sizer = wx.GridBagSizer(2, 2)
 
                self.speedPanel = wx.Panel(nb)
                sizer = wx.GridBagSizer(2, 2)
@@ -252,20 +277,20 @@ class printWindow(wx.Frame):
                self.supportSpeedSelect = wx.SpinCtrl(self.speedPanel, -1, '100', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
                self.supportSpeedSelect.SetRange(5, 1000)
 
                self.supportSpeedSelect = wx.SpinCtrl(self.speedPanel, -1, '100', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
                self.supportSpeedSelect.SetRange(5, 1000)
 
-               sizer.Add(wx.StaticText(self.speedPanel, -1, "Outer wall:"), pos=(0, 0))
+               sizer.Add(wx.StaticText(self.speedPanel, -1, _("Outer wall:")), pos=(0, 0))
                sizer.Add(self.outerWallSpeedSelect, pos=(0, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(0, 2))
                sizer.Add(self.outerWallSpeedSelect, pos=(0, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(0, 2))
-               sizer.Add(wx.StaticText(self.speedPanel, -1, "Inner wall:"), pos=(1, 0))
+               sizer.Add(wx.StaticText(self.speedPanel, -1, _("Inner wall:")), pos=(1, 0))
                sizer.Add(self.innerWallSpeedSelect, pos=(1, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(1, 2))
                sizer.Add(self.innerWallSpeedSelect, pos=(1, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(1, 2))
-               sizer.Add(wx.StaticText(self.speedPanel, -1, "Fill:"), pos=(2, 0))
+               sizer.Add(wx.StaticText(self.speedPanel, -1, _("Fill:")), pos=(2, 0))
                sizer.Add(self.fillSpeedSelect, pos=(2, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(2, 2))
                sizer.Add(self.fillSpeedSelect, pos=(2, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(2, 2))
-               sizer.Add(wx.StaticText(self.speedPanel, -1, "Support:"), pos=(3, 0))
+               sizer.Add(wx.StaticText(self.speedPanel, -1, _("Support:")), pos=(3, 0))
                sizer.Add(self.supportSpeedSelect, pos=(3, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(3, 2))
 
                sizer.Add(self.supportSpeedSelect, pos=(3, 1))
                sizer.Add(wx.StaticText(self.speedPanel, -1, "%"), pos=(3, 2))
 
-               nb.AddPage(self.speedPanel, 'Speed')
+               nb.AddPage(self.speedPanel, _("Speed"))
 
                self.termPanel = wx.Panel(nb)
                sizer = wx.GridBagSizer(2, 2)
 
                self.termPanel = wx.Panel(nb)
                sizer = wx.GridBagSizer(2, 2)
@@ -283,38 +308,7 @@ class printWindow(wx.Frame):
                sizer.AddGrowableCol(0)
                sizer.AddGrowableRow(0)
 
                sizer.AddGrowableCol(0)
                sizer.AddGrowableRow(0)
 
-               nb.AddPage(self.termPanel, 'Term')
-
-               if self.cam is not None:
-                       self.camPage = wx.Panel(nb)
-                       sizer = wx.GridBagSizer(2, 2)
-                       self.camPage.SetSizer(sizer)
-
-                       self.timelapsEnable = wx.CheckBox(self.camPage, -1, 'Enable timelapse movie recording')
-                       self.timelapsSavePath = wx.TextCtrl(self.camPage, -1, os.path.expanduser('~/timelaps_' + datetime.datetime.now().strftime('%Y-%m-%d_%H:%M') + '.mpg'))
-                       sizer.Add(self.timelapsEnable, pos=(0, 0), span=(1, 2), flag=wx.EXPAND)
-                       sizer.Add(self.timelapsSavePath, pos=(1, 0), span=(1, 2), flag=wx.EXPAND)
-
-                       pages = self.cam.propertyPages()
-                       self.cam.buttons = [self.timelapsEnable, self.timelapsSavePath]
-                       for page in pages:
-                               button = wx.Button(self.camPage, -1, page)
-                               button.index = pages.index(page)
-                               sizer.Add(button, pos=(2, pages.index(page)))
-                               button.Bind(wx.EVT_BUTTON, self.OnPropertyPageButton)
-                               self.cam.buttons.append(button)
-
-                       self.campreviewEnable = wx.CheckBox(self.camPage, -1, 'Show preview')
-                       sizer.Add(self.campreviewEnable, pos=(3, 0), span=(1, 2), flag=wx.EXPAND)
-
-                       self.camPreview = wx.Panel(self.camPage)
-                       sizer.Add(self.camPreview, pos=(4, 0), span=(1, 2), flag=wx.EXPAND)
-
-                       nb.AddPage(self.camPage, 'Camera')
-                       self.camPreview.timer = wx.Timer(self)
-                       self.Bind(wx.EVT_TIMER, self.OnCameraTimer, self.camPreview.timer)
-                       self.camPreview.timer.Start(500)
-                       self.camPreview.Bind(wx.EVT_ERASE_BACKGROUND, self.OnCameraEraseBackground)
+               nb.AddPage(self.termPanel, _("Term"))
 
                self.sizer.AddGrowableRow(6)
                self.sizer.AddGrowableCol(3)
 
                self.sizer.AddGrowableRow(6)
                self.sizer.AddGrowableCol(3)
@@ -327,7 +321,7 @@ class printWindow(wx.Frame):
                self.cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)
                self.machineLogButton.Bind(wx.EVT_BUTTON, self.OnMachineLog)
 
                self.cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)
                self.machineLogButton.Bind(wx.EVT_BUTTON, self.OnMachineLog)
 
-               self.Bind(wx.EVT_BUTTON, lambda e: (self.temperatureSelect.SetValue(210), self.machineCom.sendCommand("M104 S210")), self.temperatureHeatUpPLA)
+               self.Bind(wx.EVT_BUTTON, lambda e: (self.temperatureSelect.SetValue(int(profile.getProfileSettingFloat('print_temperature'))), self.machineCom.sendCommand("M104 S%d" % (int(profile.getProfileSettingFloat('print_temperature'))))), self.temperatureHeatUp)
                self.Bind(wx.EVT_SPINCTRL, self.OnTempChange, self.temperatureSelect)
                self.Bind(wx.EVT_SPINCTRL, self.OnBedTempChange, self.bedTemperatureSelect)
 
                self.Bind(wx.EVT_SPINCTRL, self.OnTempChange, self.temperatureSelect)
                self.Bind(wx.EVT_SPINCTRL, self.OnBedTempChange, self.bedTemperatureSelect)
 
@@ -351,6 +345,10 @@ class printWindow(wx.Frame):
                self._thread.daemon = True
                self._thread.start()
 
                self._thread.daemon = True
                self._thread.start()
 
+               if webcam.hasWebcamSupport():
+                       #Need to call the camera class on the GUI thread, or else it won't work. Shame as it hangs the GUI for about 2 seconds.
+                       wx.CallAfter(self._webcamCheck)
+
        def _stdinMonitor(self):
                while True:
                        line = sys.stdin.readline().rstrip()
        def _stdinMonitor(self):
                while True:
                        line = sys.stdin.readline().rstrip()
@@ -358,6 +356,41 @@ class printWindow(wx.Frame):
                                if not self.LoadGCodeFile(line[5:]):
                                        print 'LOADFAILED\n'
 
                                if not self.LoadGCodeFile(line[5:]):
                                        print 'LOADFAILED\n'
 
+       def _webcamCheck(self):
+               self.cam = webcam.webcam()
+               if self.cam.hasCamera():
+                       self.camPage = wx.Panel(self.tabs)
+                       sizer = wx.GridBagSizer(2, 2)
+                       self.camPage.SetSizer(sizer)
+
+                       self.timelapsEnable = wx.CheckBox(self.camPage, -1, _("Enable timelapse movie recording"))
+                       self.timelapsSavePath = wx.TextCtrl(self.camPage, -1, os.path.expanduser('~/timelaps_' + datetime.datetime.now().strftime('%Y-%m-%d_%H-%M') + '.mpg'))
+                       sizer.Add(self.timelapsEnable, pos=(0, 0), span=(1, 2), flag=wx.EXPAND)
+                       sizer.Add(self.timelapsSavePath, pos=(1, 0), span=(1, 2), flag=wx.EXPAND)
+
+                       pages = self.cam.propertyPages()
+                       self.cam.buttons = [self.timelapsEnable, self.timelapsSavePath]
+                       for page in pages:
+                               button = wx.Button(self.camPage, -1, page)
+                               button.index = pages.index(page)
+                               sizer.Add(button, pos=(2, pages.index(page)))
+                               button.Bind(wx.EVT_BUTTON, self.OnPropertyPageButton)
+                               self.cam.buttons.append(button)
+
+                       self.campreviewEnable = wx.CheckBox(self.camPage, -1, _("Show preview"))
+                       sizer.Add(self.campreviewEnable, pos=(3, 0), span=(1, 2), flag=wx.EXPAND)
+
+                       self.camPreview = wx.Panel(self.camPage)
+                       sizer.Add(self.camPreview, pos=(4, 0), span=(1, 2), flag=wx.EXPAND)
+
+                       self.tabs.AddPage(self.camPage, _("Camera"))
+                       self.camPreview.timer = wx.Timer(self)
+                       self.Bind(wx.EVT_TIMER, self.OnCameraTimer, self.camPreview.timer)
+                       self.camPreview.timer.Start(500)
+                       self.camPreview.Bind(wx.EVT_ERASE_BACKGROUND, self.OnCameraEraseBackground)
+               else:
+                       self.cam = None
+
        def OnCameraTimer(self, e):
                if not self.campreviewEnable.GetValue():
                        return
        def OnCameraTimer(self, e):
                if not self.campreviewEnable.GetValue():
                        return
@@ -388,14 +421,14 @@ class printWindow(wx.Frame):
                #self.loadButton.Enable(self.machineCom == None or not (self.machineCom.isPrinting() or self.machineCom.isPaused()))
                self.printButton.Enable(self.machineCom is not None and self.machineCom.isOperational() and not (
                self.machineCom.isPrinting() or self.machineCom.isPaused()))
                #self.loadButton.Enable(self.machineCom == None or not (self.machineCom.isPrinting() or self.machineCom.isPaused()))
                self.printButton.Enable(self.machineCom is not None and self.machineCom.isOperational() and not (
                self.machineCom.isPrinting() or self.machineCom.isPaused()))
-               self.temperatureHeatUpPLA.Enable(self.machineCom is not None and self.machineCom.isOperational() and not (
+               self.temperatureHeatUp.Enable(self.machineCom is not None and self.machineCom.isOperational() and not (
                self.machineCom.isPrinting() or self.machineCom.isPaused()))
                self.pauseButton.Enable(
                        self.machineCom is not None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
                if self.machineCom is not None and self.machineCom.isPaused():
                self.machineCom.isPrinting() or self.machineCom.isPaused()))
                self.pauseButton.Enable(
                        self.machineCom is not None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
                if self.machineCom is not None and self.machineCom.isPaused():
-                       self.pauseButton.SetLabel('Resume')
+                       self.pauseButton.SetLabel(_("Resume"))
                else:
                else:
-                       self.pauseButton.SetLabel('Pause')
+                       self.pauseButton.SetLabel(_("Pause"))
                self.cancelButton.Enable(
                        self.machineCom is not None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
                self.temperatureSelect.Enable(self.machineCom is not None and self.machineCom.isOperational())
                self.cancelButton.Enable(
                        self.machineCom is not None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
                self.temperatureSelect.Enable(self.machineCom is not None and self.machineCom.isOperational())
@@ -403,20 +436,19 @@ class printWindow(wx.Frame):
                self.directControlPanel.Enable(
                        self.machineCom is not None and self.machineCom.isOperational() and not self.machineCom.isPrinting())
                self.machineLogButton.Show(self.machineCom is not None and self.machineCom.isClosedOrError())
                self.directControlPanel.Enable(
                        self.machineCom is not None and self.machineCom.isOperational() and not self.machineCom.isPrinting())
                self.machineLogButton.Show(self.machineCom is not None and self.machineCom.isClosedOrError())
-               if self.cam != None:
+               if self.cam is not None:
                        for button in self.cam.buttons:
                                button.Enable(self.machineCom is None or not self.machineCom.isPrinting())
 
        def UpdateProgress(self):
                status = ""
                if self.gcode is None:
                        for button in self.cam.buttons:
                                button.Enable(self.machineCom is None or not self.machineCom.isPrinting())
 
        def UpdateProgress(self):
                status = ""
                if self.gcode is None:
-                       status += "Loading gcode...\n"
+                       status += _("Loading gcode...\n")
                else:
                else:
-                       status += "Filament: %.2fm %.2fg\n" % (
-                       self.gcode.extrusionAmount / 1000, self.gcode.calculateWeight() * 1000)
+                       status += _("Filament: %(amount).2fm %(weight).2fg\n") % {'amount': self.gcode.extrusionAmount / 1000, 'weight': self.gcode.calculateWeight() * 1000}
                        cost = self.gcode.calculateCost()
                        if cost is not None:
                        cost = self.gcode.calculateCost()
                        if cost is not None:
-                               status += "Filament cost: %s\n" % (cost)
+                               status += _("Filament cost: %s\n") % (cost)
                        #status += "Estimated print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))
                if self.machineCom is None or not self.machineCom.isPrinting():
                        self.progress.SetValue(0)
                        #status += "Estimated print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))
                if self.machineCom is None or not self.machineCom.isPrinting():
                        self.progress.SetValue(0)
@@ -467,7 +499,7 @@ class printWindow(wx.Frame):
                        return
                self.currentZ = -1
                if self.cam is not None and self.timelapsEnable.GetValue():
                        return
                self.currentZ = -1
                if self.cam is not None and self.timelapsEnable.GetValue():
-                       self.cam.startTimelapse(self.timelapsSavePath)
+                       self.cam.startTimelapse(self.timelapsSavePath.GetValue())
                self.machineCom.printGCode(self.gcodeList)
                self.UpdateButtonStates()
 
                self.machineCom.printGCode(self.gcodeList)
                self.UpdateButtonStates()
 
@@ -509,9 +541,12 @@ class printWindow(wx.Frame):
                self.machineCom.setFeedrateModifier('SUPPORT', self.supportSpeedSelect.GetValue() / 100.0)
 
        def AddTermLog(self, line):
                self.machineCom.setFeedrateModifier('SUPPORT', self.supportSpeedSelect.GetValue() / 100.0)
 
        def AddTermLog(self, line):
+               if len(self.termLog.GetValue()) > 10000:
+                       self.termLog.SetValue(self.termLog.GetValue()[-10000:])
+               self.termLog.SetInsertionPointEnd()
                self.termLog.AppendText(unicode(line, 'utf-8', 'replace'))
                self.termLog.AppendText(unicode(line, 'utf-8', 'replace'))
-               l = len(self.termLog.GetValue())
-               self.termLog.SetCaret(wx.Caret(self.termLog, (l, l)))
+               #l = self.termLog.GetLastPosition()     # if needed (windows? mac?)
+               #self.termLog.ShowPosition(l)
 
        def OnTermEnterLine(self, e):
                line = self.termInput.GetValue()
 
        def OnTermEnterLine(self, e):
                line = self.termInput.GetValue()
@@ -567,7 +602,7 @@ class printWindow(wx.Frame):
                                        gcodeList.append(line)
                                prevLineType = lineType
                gcode = gcodeInterpreter.gcode()
                                        gcodeList.append(line)
                                prevLineType = lineType
                gcode = gcodeInterpreter.gcode()
-               gcode.loadList(gcodeList)
+               gcode.load(gcodeList)
                #print "Loaded: %s (%d)" % (filename, len(gcodeList))
                self.filename = filename
                self.gcode = gcode
                #print "Loaded: %s (%d)" % (filename, len(gcodeList))
                self.filename = filename
                self.gcode = gcode