chiark / gitweb /
Merge tag '15.02.1' into upstream
[cura.git] / Cura / gui / mainWindow.py
index 714fc8ea917fa226827a505ca3fefd15a476f22d..fbab3ac25ca6561221dc71b7af06c245857a7388 100644 (file)
@@ -22,11 +22,18 @@ from Cura.gui.tools import pidDebugger
 from Cura.gui.tools import minecraftImport
 from Cura.util import profile
 from Cura.util import version
+import platform
 from Cura.util import meshLoader
 
+try:
+       #MacOS release currently lacks some wx components, like the Publisher.
+       from wx.lib.pubsub import Publisher
+except:
+       Publisher = None
+
 class mainWindow(wx.Frame):
        def __init__(self):
-               super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
+               super(mainWindow, self).__init__(None, title=_('Cura - ') + version.getVersion())
 
                wx.EVT_CLOSE(self, self.OnClose)
 
@@ -35,11 +42,13 @@ class mainWindow(wx.Frame):
 
                # TODO: wxWidgets 2.9.4 has a bug when NSView does not register for dragged types when wx drop target is set. It was fixed in 2.9.5
                if sys.platform.startswith('darwin'):
-                       import Cocoa
-                       import objc
-                       nswindow = objc.objc_object(c_void_p=self.MacGetTopLevelWindowRef())
-                       view = nswindow.contentView()
-                       view.registerForDraggedTypes_([Cocoa.NSFilenamesPboardType])
+                       try:
+                               import objc
+                               nswindow = objc.objc_object(c_void_p=self.MacGetTopLevelWindowRef())
+                               view = nswindow.contentView()
+                               view.registerForDraggedTypes_([u'NSFilenamesPboardType'])
+                       except:
+                               pass
 
                self.normalModeOnlyItems = []
 
@@ -64,6 +73,8 @@ class mainWindow(wx.Frame):
                self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
                i = self.fileMenu.Append(-1, _("Save model...\tCTRL+S"))
                self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
+               i = self.fileMenu.Append(-1, _("Reload platform\tF5"))
+               self.Bind(wx.EVT_MENU, lambda e: self.scene.reloadScene(e), i)
                i = self.fileMenu.Append(-1, _("Clear platform"))
                self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
 
@@ -82,6 +93,10 @@ class mainWindow(wx.Frame):
                i = self.fileMenu.Append(-1, _("Save Profile..."))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
+               if version.isDevVersion():
+                       i = self.fileMenu.Append(-1, "Save difference from default...")
+                       self.normalModeOnlyItems.append(i)
+                       self.Bind(wx.EVT_MENU, self.OnSaveDifferences, i)
                i = self.fileMenu.Append(-1, _("Load Profile from GCode..."))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
@@ -128,9 +143,11 @@ class mainWindow(wx.Frame):
                if version.isDevVersion():
                        i = toolsMenu.Append(-1, _("PID Debugger..."))
                        self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
+                       i = toolsMenu.Append(-1, _("Auto Firmware Update..."))
+                       self.Bind(wx.EVT_MENU, self.OnAutoFirmwareUpdate, i)
 
-               i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
-               self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
+               #i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
+               #self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
 
                toolsMenu.AppendSeparator()
                self.allAtOnceItem = toolsMenu.Append(-1, _("Print all at once"), kind=wx.ITEM_RADIO)
@@ -164,8 +181,6 @@ class mainWindow(wx.Frame):
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
                expertMenu.AppendSeparator()
-               i = expertMenu.Append(-1, _("Run first run wizard..."))
-               self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
                self.bedLevelWizardMenuItem = expertMenu.Append(-1, _("Run bed leveling wizard..."))
                self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, self.bedLevelWizardMenuItem)
                self.headOffsetWizardMenuItem = expertMenu.Append(-1, _("Run head offset wizard..."))
@@ -175,13 +190,13 @@ class mainWindow(wx.Frame):
 
                helpMenu = wx.Menu()
                i = helpMenu.Append(-1, _("Online documentation..."))
-               self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
+               self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://lulzbot.com/cura'), i)
                i = helpMenu.Append(-1, _("Report a problem..."))
-               self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
-               i = helpMenu.Append(-1, _("Check for update..."))
-               self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
-               i = helpMenu.Append(-1, _("Open YouMagine website..."))
-               self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
+               self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/alephobjects/Cura/issues'), i)
+               #i = helpMenu.Append(-1, _("Check for update..."))
+               #self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
+               #i = helpMenu.Append(-1, _("Open YouMagine website..."))
+               #self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
                i = helpMenu.Append(-1, _("About Cura..."))
                self.Bind(wx.EVT_MENU, self.OnAbout, i)
                self.menubar.Append(helpMenu, _("Help"))
@@ -192,18 +207,18 @@ class mainWindow(wx.Frame):
                self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
                self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
 
+               #Preview window
+               self.scene = sceneView.SceneView(self.rightPane)
+
                ##Gui components##
-               self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
-               self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
+               self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, self.scene.sceneUpdated)
+               self.normalSettingsPanel = normalSettingsPanel(self.leftPane, self.scene.sceneUpdated)
 
                self.leftSizer = wx.BoxSizer(wx.VERTICAL)
                self.leftSizer.Add(self.simpleSettingsPanel, 1)
                self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
                self.leftPane.SetSizer(self.leftSizer)
 
-               #Preview window
-               self.scene = sceneView.SceneView(self.rightPane)
-
                #Main sizer, to position the preview window, buttons and tab control
                sizer = wx.BoxSizer()
                self.rightPane.SetSizer(sizer)
@@ -230,7 +245,7 @@ class mainWindow(wx.Frame):
                #Timer set; used to check if profile is on the clipboard
                self.timer = wx.Timer(self)
                self.Bind(wx.EVT_TIMER, self.onTimer)
-               self.timer.Start(1000)
+               #self.timer.Start(1000)
                self.lastTriedClipboard = profile.getProfileString()
 
                # Restore the window position, size & state from the preferences file
@@ -266,6 +281,43 @@ class mainWindow(wx.Frame):
 
                self.updateSliceMode()
                self.scene.SetFocus()
+               self.dialogframe = None
+               if Publisher is not None:
+                       Publisher().subscribe(self.onPluginUpdate, "pluginupdate")
+
+               pluginCount = self.normalSettingsPanel.pluginPanel.GetActivePluginCount()
+               if pluginCount == 1:
+                       self.scene.notification.message("Warning: 1 plugin from the previous session is still active.")
+
+               if pluginCount > 1:
+                       self.scene.notification.message("Warning: %i plugins from the previous session are still active." % pluginCount)
+
+       def onPluginUpdate(self,msg): #receives commands from the plugin thread
+               cmd = str(msg.data).split(";")
+               if cmd[0] == "OpenPluginProgressWindow":
+                       if len(cmd)==1: #no titel received
+                               cmd.append("Plugin")
+                       if len(cmd)<3: #no message text received
+                               cmd.append("Plugin is executed...")
+                       dialogwidth = 300
+                       dialogheight = 80
+                       self.dialogframe = wx.Frame(self, -1, cmd[1],pos = ((wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X)-dialogwidth)/2,(wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)-dialogheight)/2), size=(dialogwidth,dialogheight), style = wx.STAY_ON_TOP)
+                       self.dialogpanel = wx.Panel(self.dialogframe, -1, pos = (0,0), size = (dialogwidth,dialogheight))
+                       self.dlgtext = wx.StaticText(self.dialogpanel, label = cmd[2], pos = (10,10), size = (280,40))
+                       self.dlgbar = wx.Gauge(self.dialogpanel,-1, 100, pos = (10,50), size = (280,20), style = wx.GA_HORIZONTAL)
+                       self.dialogframe.Show()
+
+               elif cmd[0] == "Progress":
+                       number = int(cmd[1])
+                       if number <= 100 and self.dialogframe is not None:
+                               self.dlgbar.SetValue(number)
+                       else:
+                               self.dlgbar.SetValue(100)
+               elif cmd[0] == "ClosePluginProgressWindow":
+                       self.dialogframe.Destroy()
+                       self.dialogframe=None
+               else:
+                       print "Unknown Plugin update received: " + cmd[0]
 
        def onTimer(self, e):
                #Check if there is something in the clipboard
@@ -288,13 +340,13 @@ class mainWindow(wx.Frame):
                                                print profileString
                                                self.lastTriedClipboard = profileString
                                                profile.setProfileFromString(profileString)
-                                               self.scene.notification.message("Loaded new profile from clipboard.")
+                                               self.scene.notification.message(_("Loaded new profile from clipboard."))
                                                self.updateProfileToAllControls()
                except:
                        print "Unable to read from clipboard"
 
 
-       def updateSliceMode(self):
+       def updateSliceMode(self, changedMode = True):
                isSimple = profile.getPreference('startMode') == 'Simple'
 
                self.normalSettingsPanel.Show(not isSimple)
@@ -310,8 +362,10 @@ class mainWindow(wx.Frame):
 
                # Set splitter sash position & size
                if isSimple:
-                       # Save normal mode sash
-                       self.normalSashPos = self.splitter.GetSashPosition()
+                       # Save normal mode sash (only if we changed mode from normal
+                       # to simple)
+                       if changedMode:
+                               self.normalSashPos = self.splitter.GetSashPosition()
 
                        # Change location of sash to width of quick mode pane
                        (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
@@ -320,16 +374,23 @@ class mainWindow(wx.Frame):
                        # Disable sash
                        self.splitter.SetSashSize(0)
                else:
-                       self.splitter.SetSashPosition(self.normalSashPos, True)
+                       # Only change the sash position if we changed mode from simple
+                       if changedMode:
+                               self.splitter.SetSashPosition(self.normalSashPos, True)
                        # Enabled sash
                        self.splitter.SetSashSize(4)
                self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
-               if profile.getMachineSetting('machine_type') == 'ultimaker2':
+               if profile.getMachineSetting('machine_type').startswith('ultimaker2') or \
+                  profile.getMachineSetting('machine_type').startswith('lulzbot_'):
                        self.bedLevelWizardMenuItem.Enable(False)
                        self.headOffsetWizardMenuItem.Enable(False)
+               else:
+                       self.bedLevelWizardMenuItem.Enable(True)
+                       self.headOffsetWizardMenuItem.Enable(False)
                if int(profile.getMachineSetting('extruder_amount')) < 2:
                        self.headOffsetWizardMenuItem.Enable(False)
                self.scene.updateProfileToControls()
+               self.scene._scene.pushFree()
 
        def onOneAtATimeSwitch(self, e):
                profile.putPreference('oneAtATime', self.oneAtATime.IsChecked())
@@ -344,7 +405,6 @@ class mainWindow(wx.Frame):
                prefDialog.Centre()
                prefDialog.Show()
                prefDialog.Raise()
-               wx.CallAfter(prefDialog.Show)
 
        def OnMachineSettings(self, e):
                prefDialog = preferencesDialog.machineSettingsDialog(self)
@@ -353,8 +413,6 @@ class mainWindow(wx.Frame):
                prefDialog.Raise()
 
        def OnDropFiles(self, files):
-               if len(files) > 0:
-                       self.updateProfileToAllControls()
                self.scene.loadFiles(files)
 
        def OnModelMRU(self, e):
@@ -399,7 +457,7 @@ class mainWindow(wx.Frame):
                self.normalSettingsPanel.updateProfileToControls()
                self.simpleSettingsPanel.updateProfileToControls()
 
-       def reloadSettingPanels(self):
+       def reloadSettingPanels(self, changedSliceMode = False):
                self.leftSizer.Detach(self.simpleSettingsPanel)
                self.leftSizer.Detach(self.normalSettingsPanel)
                self.simpleSettingsPanel.Destroy()
@@ -408,7 +466,7 @@ class mainWindow(wx.Frame):
                self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
                self.leftSizer.Add(self.simpleSettingsPanel, 1)
                self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
-               self.updateSliceMode()
+               self.updateSliceMode(changedSliceMode)
                self.updateProfileToAllControls()
 
        def updateMachineMenu(self):
@@ -424,7 +482,8 @@ class mainWindow(wx.Frame):
                        self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
 
                self.machineMenu.AppendSeparator()
-
+               i = self.machineMenu.Append(-1, _("Add new machine..."))
+               self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
                i = self.machineMenu.Append(-1, _("Machine settings..."))
                self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
 
@@ -451,7 +510,7 @@ class mainWindow(wx.Frame):
 
        def OnLoadProfileFromGcode(self, e):
                dlg=wx.FileDialog(self, _("Select gcode file to load profile from"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
-               dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
+               dlg.SetWildcard("gcode files (*%s)|*%s;*%s" % (profile.getGCodeExtension(), profile.getGCodeExtension(), profile.getGCodeExtension()[0:2]))
                if dlg.ShowModal() == wx.ID_OK:
                        gcodeFile = dlg.GetPath()
                        f = open(gcodeFile, 'r')
@@ -459,6 +518,8 @@ class mainWindow(wx.Frame):
                        for line in f:
                                if line.startswith(';CURA_PROFILE_STRING:'):
                                        profile.setProfileFromString(line[line.find(':')+1:].strip())
+                                       if ';{profile_string}' not in profile.getAlterationFile('end.gcode'):
+                                               profile.setAlterationFile('end.gcode', profile.getAlterationFile('end.gcode') + '\n;{profile_string}')
                                        hasProfile = True
                        if hasProfile:
                                self.updateProfileToAllControls()
@@ -470,8 +531,20 @@ class mainWindow(wx.Frame):
                dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
                dlg.SetWildcard("ini files (*.ini)|*.ini")
                if dlg.ShowModal() == wx.ID_OK:
-                       profileFile = dlg.GetPath()
-                       profile.saveProfile(profileFile)
+                       profile_filename = dlg.GetPath()
+                       if not profile_filename.lower().endswith('.ini'): #hack for linux, as for some reason the .ini is not appended.
+                               profile_filename += '.ini'
+                       profile.saveProfile(profile_filename)
+               dlg.Destroy()
+
+       def OnSaveDifferences(self, e):
+               dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
+               dlg.SetWildcard("ini files (*.ini)|*.ini")
+               if dlg.ShowModal() == wx.ID_OK:
+                       profile_filename = dlg.GetPath()
+                       if not profile_filename.lower().endswith('.ini'): #hack for linux, as for some reason the .ini is not appended.
+                               profile_filename += '.ini'
+                       profile.saveProfileDifferenceFromDefault(profile_filename)
                dlg.Destroy()
 
        def OnResetProfile(self, e):
@@ -488,10 +561,18 @@ class mainWindow(wx.Frame):
 
        def OnNormalSwitch(self, e):
                profile.putPreference('startMode', 'Normal')
+               dlg = wx.MessageDialog(self, _("Copy the settings from quickprint to your full settings?\n(This will overwrite any full setting modifications you have)"), _("Profile copy"), wx.YES_NO | wx.ICON_QUESTION)
+               result = dlg.ShowModal() == wx.ID_YES
+               dlg.Destroy()
+               if result:
+                       profile.resetProfile()
+                       for k, v in self.simpleSettingsPanel.getSettingOverrides().items():
+                               profile.putProfileSetting(k, v)
+                       self.updateProfileToAllControls()
                self.updateSliceMode()
 
        def OnDefaultMarlinFirmware(self, e):
-               firmwareInstall.InstallFirmware()
+               firmwareInstall.InstallFirmware(self)
 
        def OnCustomFirmware(self, e):
                if profile.getMachineSetting('machine_type').startswith('ultimaker'):
@@ -500,20 +581,24 @@ class mainWindow(wx.Frame):
                dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
                if dlg.ShowModal() == wx.ID_OK:
                        filename = dlg.GetPath()
+                       dlg.Destroy()
                        if not(os.path.exists(filename)):
                                return
                        #For some reason my Ubuntu 10.10 crashes here.
-                       firmwareInstall.InstallFirmware(filename)
+                       firmwareInstall.InstallFirmware(self, filename)
 
-       def OnFirstRunWizard(self, e):
+       def OnAddNewMachine(self, e):
                self.Hide()
-               configWizard.configWizard()
+               wasSimple = profile.getPreference('startMode') == 'Simple'
+               configWizard.ConfigWizard(True)
+               isSimple = profile.getPreference('startMode') == 'Simple'
                self.Show()
-               self.reloadSettingPanels()
+               self.reloadSettingPanels(isSimple != wasSimple)
+               self.updateMachineMenu()
 
        def OnSelectMachine(self, index):
                profile.setActiveMachine(index)
-               self.reloadSettingPanels()
+               self.reloadSettingPanels(False)
 
        def OnBedLevelWizard(self, e):
                configWizard.bedLevelWizard()
@@ -536,6 +621,17 @@ class mainWindow(wx.Frame):
                debugger.Centre()
                debugger.Show(True)
 
+       def OnAutoFirmwareUpdate(self, e):
+               dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
+               dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
+               if dlg.ShowModal() == wx.ID_OK:
+                       filename = dlg.GetPath()
+                       dlg.Destroy()
+                       if not(os.path.exists(filename)):
+                               return
+                       #For some reason my Ubuntu 10.10 crashes here.
+                       installer = firmwareInstall.AutoUpdateFirmware(self, filename)
+
        def onCopyProfileClipboard(self, e):
                try:
                        if not wx.TheClipboard.IsOpened():
@@ -558,9 +654,10 @@ class mainWindow(wx.Frame):
                        wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
 
        def OnAbout(self, e):
-               aboutBox = aboutWindow.aboutWindow()
+               aboutBox = aboutWindow.aboutWindow(self)
                aboutBox.Centre()
                aboutBox.Show()
+               aboutBox.Raise()
 
        def OnClose(self, e):
                profile.saveProfile(profile.getDefaultProfilePath(), True)
@@ -584,7 +681,7 @@ class mainWindow(wx.Frame):
                #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
                print "Closing down"
                self.scene.OnPaint = lambda e : e
-               self.scene._engine.cleanup()
+               self.scene.cleanup()
                self.Destroy()
 
        def OnQuit(self, e):
@@ -600,11 +697,11 @@ class normalSettingsPanel(configBase.configPanelBase):
                self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
                self.GetSizer().Add(self.nb, 1, wx.EXPAND)
 
-               (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
+               (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, _('Basic'))
                self._addSettingsToPanels('basic', left, right)
                self.SizeLabelWidths(left, right)
 
-               (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
+               (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, _('Advanced'))
                self._addSettingsToPanels('advanced', left, right)
                self.SizeLabelWidths(left, right)
 
@@ -617,7 +714,7 @@ class normalSettingsPanel(configBase.configPanelBase):
                        self.alterationPanel = None
                else:
                        self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
-                       self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
+                       self.nb.AddPage(self.alterationPanel, _("Start/End-GCode"))
 
                self.Bind(wx.EVT_SIZE, self.OnSize)