chiark / gitweb /
Added keyboard control for the 3D window to look around with cursor keys.
[cura.git] / Cura / gui / mainWindow.py
index e432b8a81533d06ac892f797ae9c8183e52d1f09..99c0b2d85537ed406741adf8d54e49621020d407 100644 (file)
@@ -14,33 +14,31 @@ from Cura.gui import configWizard
 from Cura.gui import firmwareInstall
 from Cura.gui import simpleMode
 from Cura.gui import sceneView
+from Cura.gui import aboutWindow
 from Cura.gui.util import dropTarget
 #from Cura.gui.tools import batchRun
 from Cura.gui.tools import pidDebugger
 from Cura.gui.tools import minecraftImport
-from Cura.gui.tools import youmagineGui
 from Cura.util import profile
 from Cura.util import version
 from Cura.util import meshLoader
-from Cura.util import resources
 
 class mainWindow(wx.Frame):
        def __init__(self):
                super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
 
-               self.extruderCount = int(profile.getPreference('extruder_amount'))
-
                wx.EVT_CLOSE(self, self.OnClose)
 
-               self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.loadSupportedExtensions()))
+               # allow dropping any file, restrict later
+               self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles))
 
                self.normalModeOnlyItems = []
 
                mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
-               self.config = wx.FileConfig(appName="Cura", 
+               self.config = wx.FileConfig(appName="Cura",
                                                localFilename=mruFile,
                                                style=wx.CONFIG_USE_LOCAL_FILE)
-                                               
+
                self.ID_MRU_MODEL1, self.ID_MRU_MODEL2, self.ID_MRU_MODEL3, self.ID_MRU_MODEL4, self.ID_MRU_MODEL5, self.ID_MRU_MODEL6, self.ID_MRU_MODEL7, self.ID_MRU_MODEL8, self.ID_MRU_MODEL9, self.ID_MRU_MODEL10 = [wx.NewId() for line in xrange(10)]
                self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
                self.config.SetPath("/ModelMRU")
@@ -53,109 +51,120 @@ class mainWindow(wx.Frame):
 
                self.menubar = wx.MenuBar()
                self.fileMenu = wx.Menu()
-               i = self.fileMenu.Append(-1, 'Load model file...\tCTRL+L')
+               i = self.fileMenu.Append(-1, _("Load model file...\tCTRL+L"))
                self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
-               i = self.fileMenu.Append(-1, 'Save model...\tCTRL+S')
+               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, 'Clear platform')
+               i = self.fileMenu.Append(-1, _("Clear platform"))
                self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
 
                self.fileMenu.AppendSeparator()
-               i = self.fileMenu.Append(-1, 'Print...\tCTRL+P')
+               i = self.fileMenu.Append(-1, _("Print...\tCTRL+P"))
                self.Bind(wx.EVT_MENU, lambda e: self.scene.showPrintWindow(), i)
-               i = self.fileMenu.Append(-1, 'Save GCode...')
+               i = self.fileMenu.Append(-1, _("Save GCode..."))
                self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
-               i = self.fileMenu.Append(-1, 'Show slice engine log...')
+               i = self.fileMenu.Append(-1, _("Show slice engine log..."))
                self.Bind(wx.EVT_MENU, lambda e: self.scene._showSliceLog(), i)
 
                self.fileMenu.AppendSeparator()
-               i = self.fileMenu.Append(-1, 'Open Profile...')
+               i = self.fileMenu.Append(-1, _("Open Profile..."))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
-               i = self.fileMenu.Append(-1, 'Save Profile...')
+               i = self.fileMenu.Append(-1, _("Save Profile..."))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
-               i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
+               i = self.fileMenu.Append(-1, _("Load Profile from GCode..."))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
                self.fileMenu.AppendSeparator()
-               i = self.fileMenu.Append(-1, 'Reset Profile to default')
+               i = self.fileMenu.Append(-1, _("Reset Profile to default"))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
 
                self.fileMenu.AppendSeparator()
-               i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
+               i = self.fileMenu.Append(-1, _("Preferences...\tCTRL+,"))
                self.Bind(wx.EVT_MENU, self.OnPreferences, i)
+               i = self.fileMenu.Append(-1, _("Machine settings..."))
+               self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
                self.fileMenu.AppendSeparator()
 
                # Model MRU list
                modelHistoryMenu = wx.Menu()
-               self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
+               self.fileMenu.AppendMenu(wx.NewId(), '&' + _("Recent Model Files"), modelHistoryMenu)
                self.modelFileHistory.UseMenu(modelHistoryMenu)
                self.modelFileHistory.AddFilesToMenu()
                self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
 
                # Profle MRU list
                profileHistoryMenu = wx.Menu()
-               self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
+               self.fileMenu.AppendMenu(wx.NewId(), _("Recent Profile Files"), profileHistoryMenu)
                self.profileFileHistory.UseMenu(profileHistoryMenu)
                self.profileFileHistory.AddFilesToMenu()
                self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
-               
+
                self.fileMenu.AppendSeparator()
-               i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
+               i = self.fileMenu.Append(wx.ID_EXIT, _("Quit"))
                self.Bind(wx.EVT_MENU, self.OnQuit, i)
-               self.menubar.Append(self.fileMenu, '&File')
+               self.menubar.Append(self.fileMenu, '&' + _("File"))
 
                toolsMenu = wx.Menu()
-               i = toolsMenu.Append(-1, 'Switch to quickprint...')
-               self.switchToQuickprintMenuItem = i
-               self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
-               i = toolsMenu.Append(-1, 'Switch to full settings...')
-               self.switchToNormalMenuItem = i
-               self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
-               toolsMenu.AppendSeparator()
                #i = toolsMenu.Append(-1, 'Batch run...')
                #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
                #self.normalModeOnlyItems.append(i)
+
                if minecraftImport.hasMinecraft():
-                       i = toolsMenu.Append(-1, 'Minecraft import...')
+                       i = toolsMenu.Append(-1, _("Minecraft map import..."))
                        self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
+
                if version.isDevVersion():
-                       i = toolsMenu.Append(-1, 'PID Debugger...')
+                       i = toolsMenu.Append(-1, _("PID Debugger..."))
                        self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
-               self.menubar.Append(toolsMenu, 'Tools')
+
+               i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
+               self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
+               self.menubar.Append(toolsMenu, _("Tools"))
+
+               #Machine menu for machine configuration/tooling
+               self.machineMenu = wx.Menu()
+               self.updateMachineMenu()
+
+               self.menubar.Append(self.machineMenu, _("Machine"))
 
                expertMenu = wx.Menu()
-               i = expertMenu.Append(-1, 'Open expert settings...')
+               i = expertMenu.Append(-1, _("Switch to quickprint..."), kind=wx.ITEM_RADIO)
+               self.switchToQuickprintMenuItem = i
+               self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
+
+               i = expertMenu.Append(-1, _("Switch to full settings..."), kind=wx.ITEM_RADIO)
+               self.switchToNormalMenuItem = i
+               self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
+               expertMenu.AppendSeparator()
+
+               i = expertMenu.Append(-1, _("Open expert settings...\tCTRL+E"))
                self.normalModeOnlyItems.append(i)
                self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
                expertMenu.AppendSeparator()
-               if firmwareInstall.getDefaultFirmware() is not None:
-                       i = expertMenu.Append(-1, 'Install default Marlin firmware')
-                       self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
-               i = expertMenu.Append(-1, 'Install custom firmware')
-               self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
-               expertMenu.AppendSeparator()
-               i = expertMenu.Append(-1, 'Run first run wizard...')
+               i = expertMenu.Append(-1, _("Run first run wizard..."))
                self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
-               i = expertMenu.Append(-1, 'Run bed leveling wizard...')
-               self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
-               if self.extruderCount > 1:
-                       i = expertMenu.Append(-1, 'Run head offset wizard...')
-                       self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
-               self.menubar.Append(expertMenu, 'Expert')
+               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..."))
+               self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, self.headOffsetWizardMenuItem)
+
+               self.menubar.Append(expertMenu, _("Expert"))
 
                helpMenu = wx.Menu()
-               i = helpMenu.Append(-1, 'Online documentation...')
+               i = helpMenu.Append(-1, _("Online documentation..."))
                self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
-               i = helpMenu.Append(-1, 'Report a problem...')
+               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...')
+               i = helpMenu.Append(-1, _("Check for update..."))
                self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
-               i = helpMenu.Append(-1, 'About Cura...')
+               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')
+               self.menubar.Append(helpMenu, _("Help"))
                self.SetMenuBar(self.menubar)
 
                self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
@@ -167,16 +176,11 @@ class mainWindow(wx.Frame):
                self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
                self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
 
-               self.youmagineButton = wx.BitmapButton(self.leftPane, -1, wx.Bitmap(resources.getPathForImage('youmagine-text.png')))
-               self.youmagineButton.SetToolTipString("Share your design to YouMagine.com")
-               self.youmagineButton.Bind(wx.EVT_BUTTON, self.OnYouMagine)
-
                self.leftSizer = wx.BoxSizer(wx.VERTICAL)
                self.leftSizer.Add(self.simpleSettingsPanel, 1)
                self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
-               self.leftSizer.Add(self.youmagineButton, 0, wx.ALIGN_CENTER)
                self.leftPane.SetSizer(self.leftSizer)
-               
+
                #Preview window
                self.scene = sceneView.SceneView(self.rightPane)
 
@@ -192,7 +196,7 @@ class mainWindow(wx.Frame):
                sizer.Layout()
                self.sizer = sizer
 
-               self.updateProfileToControls()
+               self.updateProfileToAllControls()
 
                self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
 
@@ -203,6 +207,12 @@ class mainWindow(wx.Frame):
                self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
                self.Centre()
 
+               #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.lastTriedClipboard = profile.getProfileString()
+
                # Restore the window position, size & state from the preferences file
                try:
                        if profile.getPreference('window_maximized') == 'True':
@@ -216,7 +226,7 @@ class mainWindow(wx.Frame):
                                        self.SetPosition((posx,posy))
                                if width > 0 and height > 0:
                                        self.SetSize((width,height))
-                               
+
                        self.normalSashPos = int(profile.getPreference('window_normal_sash'))
                except:
                        self.normalSashPos = 0
@@ -235,6 +245,34 @@ class mainWindow(wx.Frame):
                        self.Centre()
 
                self.updateSliceMode()
+               self.scene.SetFocus()
+
+       def onTimer(self, e):
+               #Check if there is something in the clipboard
+               profileString = ""
+               try:
+                       if not wx.TheClipboard.IsOpened():
+                               if not wx.TheClipboard.Open():
+                                       return
+                               do = wx.TextDataObject()
+                               if wx.TheClipboard.GetData(do):
+                                       profileString = do.GetText()
+                               wx.TheClipboard.Close()
+
+                               startTag = "CURA_PROFILE_STRING:"
+                               if startTag in profileString:
+                                       #print "Found correct syntax on clipboard"
+                                       profileString = profileString.replace("\n","").strip()
+                                       profileString = profileString[profileString.find(startTag)+len(startTag):]
+                                       if profileString != self.lastTriedClipboard:
+                                               print profileString
+                                               self.lastTriedClipboard = profileString
+                                               profile.setProfileFromString(profileString)
+                                               self.scene.notification.message("Loaded new profile from clipboard.")
+                                               self.updateProfileToAllControls()
+               except:
+                       print "Unable to read from clipboard"
+
 
        def updateSliceMode(self):
                isSimple = profile.getPreference('startMode') == 'Simple'
@@ -245,37 +283,52 @@ class mainWindow(wx.Frame):
 
                for i in self.normalModeOnlyItems:
                        i.Enable(not isSimple)
-               self.switchToQuickprintMenuItem.Enable(not isSimple)
-               self.switchToNormalMenuItem.Enable(isSimple)
+               if isSimple:
+                       self.switchToQuickprintMenuItem.Check()
+               else:
+                       self.switchToNormalMenuItem.Check()
 
                # Set splitter sash position & size
                if isSimple:
                        # Save normal mode sash
                        self.normalSashPos = self.splitter.GetSashPosition()
-                       
-                       # Change location of sash to width of quick mode pane 
-                       (width, height) = self.simpleSettingsPanel.GetSizer().GetSize() 
-                       (width, height) = self.youmagineButton.GetSize()
+
+                       # Change location of sash to width of quick mode pane
+                       (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
                        self.splitter.SetSashPosition(width, True)
-                       
+
                        # Disable sash
                        self.splitter.SetSashSize(0)
                else:
                        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':
+                       self.bedLevelWizardMenuItem.Enable(False)
+                       self.headOffsetWizardMenuItem.Enable(False)
+               if int(profile.getMachineSetting('extruder_amount')) < 2:
+                       self.headOffsetWizardMenuItem.Enable(False)
                self.scene.updateProfileToControls()
 
        def OnPreferences(self, e):
                prefDialog = preferencesDialog.preferencesDialog(self)
                prefDialog.Centre()
                prefDialog.Show()
+               prefDialog.Raise()
+               wx.CallAfter(prefDialog.Show)
+
+       def OnMachineSettings(self, e):
+               prefDialog = preferencesDialog.machineSettingsDialog(self)
+               prefDialog.Centre()
+               prefDialog.Show()
+               prefDialog.Raise()
 
        def OnDropFiles(self, files):
                if len(files) > 0:
                        profile.setPluginConfig([])
-                       self.updateProfileToControls()
-               self.scene.loadScene(files)
+                       self.updateProfileToAllControls()
+               self.scene.loadFiles(files)
 
        def OnModelMRU(self, e):
                fileNum = e.GetId() - self.ID_MRU_MODEL1
@@ -288,14 +341,14 @@ class mainWindow(wx.Frame):
                # Load Model
                profile.putPreference('lastFile', path)
                filelist = [ path ]
-               self.scene.loadScene(filelist)
+               self.scene.loadFiles(filelist)
 
        def addToModelMRU(self, file):
                self.modelFileHistory.AddFileToHistory(file)
                self.config.SetPath("/ModelMRU")
                self.modelFileHistory.Save(self.config)
                self.config.Flush()
-       
+
        def OnProfileMRU(self, e):
                fileNum = e.GetId() - self.ID_MRU_PROFILE1
                path = self.profileFileHistory.GetHistoryFile(fileNum)
@@ -304,35 +357,73 @@ class mainWindow(wx.Frame):
                self.config.SetPath("/ProfileMRU")
                self.profileFileHistory.Save(self.config)
                self.config.Flush()
-               # Load Profile  
+               # Load Profile
                profile.loadProfile(path)
-               self.updateProfileToControls()
+               self.updateProfileToAllControls()
 
        def addToProfileMRU(self, file):
                self.profileFileHistory.AddFileToHistory(file)
                self.config.SetPath("/ProfileMRU")
                self.profileFileHistory.Save(self.config)
-               self.config.Flush()                     
+               self.config.Flush()
 
-       def updateProfileToControls(self):
+       def updateProfileToAllControls(self):
                self.scene.updateProfileToControls()
                self.normalSettingsPanel.updateProfileToControls()
                self.simpleSettingsPanel.updateProfileToControls()
 
+       def reloadSettingPanels(self):
+               self.leftSizer.Detach(self.simpleSettingsPanel)
+               self.leftSizer.Detach(self.normalSettingsPanel)
+               self.simpleSettingsPanel.Destroy()
+               self.normalSettingsPanel.Destroy()
+               self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
+               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.updateProfileToAllControls()
+
+       def updateMachineMenu(self):
+               #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
+               for item in self.machineMenu.GetMenuItems():
+                       self.machineMenu.RemoveItem(item)
+
+               #Add a menu item for each machine configuration.
+               for n in xrange(0, profile.getMachineCount()):
+                       i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
+                       if n == int(profile.getPreferenceFloat('active_machine')):
+                               i.Check(True)
+                       self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
+
+               self.machineMenu.AppendSeparator()
+
+               i = self.machineMenu.Append(-1, _("Machine settings..."))
+               self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
+
+               #Add tools for machines.
+               self.machineMenu.AppendSeparator()
+
+               self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
+               self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
+
+               i = self.machineMenu.Append(-1, _("Install custom firmware..."))
+               self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
+
        def OnLoadProfile(self, e):
-               dlg=wx.FileDialog(self, "Select profile file to load", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
+               dlg=wx.FileDialog(self, _("Select profile file to load"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
                dlg.SetWildcard("ini files (*.ini)|*.ini")
                if dlg.ShowModal() == wx.ID_OK:
                        profileFile = dlg.GetPath()
                        profile.loadProfile(profileFile)
-                       self.updateProfileToControls()
+                       self.updateProfileToAllControls()
 
                        # Update the Profile MRU
                        self.addToProfileMRU(profileFile)
                dlg.Destroy()
 
        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=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")
                if dlg.ShowModal() == wx.ID_OK:
                        gcodeFile = dlg.GetPath()
@@ -340,16 +431,16 @@ class mainWindow(wx.Frame):
                        hasProfile = False
                        for line in f:
                                if line.startswith(';CURA_PROFILE_STRING:'):
-                                       profile.loadProfileFromString(line[line.find(':')+1:].strip())
+                                       profile.setProfileFromString(line[line.find(':')+1:].strip())
                                        hasProfile = True
                        if hasProfile:
-                               self.updateProfileToControls()
+                               self.updateProfileToAllControls()
                        else:
-                               wx.MessageBox('No profile found in GCode file.\nThis feature only works with GCode files made by Cura 12.07 or newer.', 'Profile load error', wx.OK | wx.ICON_INFORMATION)
+                               wx.MessageBox(_("No profile found in GCode file.\nThis feature only works with GCode files made by Cura 12.07 or newer."), _("Profile load error"), wx.OK | wx.ICON_INFORMATION)
                dlg.Destroy()
 
        def OnSaveProfile(self, e):
-               dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
+               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()
@@ -357,12 +448,12 @@ class mainWindow(wx.Frame):
                dlg.Destroy()
 
        def OnResetProfile(self, e):
-               dlg = wx.MessageDialog(self, 'This will reset all profile settings to defaults.\nUnless you have saved your current profile, all settings will be lost!\nDo you really want to reset?', 'Profile reset', wx.YES_NO | wx.ICON_QUESTION)
+               dlg = wx.MessageDialog(self, _("This will reset all profile settings to defaults.\nUnless you have saved your current profile, all settings will be lost!\nDo you really want to reset?"), _("Profile reset"), wx.YES_NO | wx.ICON_QUESTION)
                result = dlg.ShowModal() == wx.ID_YES
                dlg.Destroy()
                if result:
                        profile.resetProfile()
-                       self.updateProfileToControls()
+                       self.updateProfileToAllControls()
 
        def OnSimpleSwitch(self, e):
                profile.putPreference('startMode', 'Simple')
@@ -376,9 +467,9 @@ class mainWindow(wx.Frame):
                firmwareInstall.InstallFirmware()
 
        def OnCustomFirmware(self, e):
-               if profile.getPreference('machine_type') == 'ultimaker':
-                       wx.MessageBox('Warning: Installing a custom firmware does not guarantee that you machine will function correctly, and could damage your machine.', 'Firmware update', wx.OK | wx.ICON_EXCLAMATION)
-               dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
+               if profile.getMachineSetting('machine_type').startswith('ultimaker'):
+                       wx.MessageBox(_("Warning: Installing a custom firmware does not guarantee that you machine will function correctly, and could damage your machine."), _("Firmware update"), wx.OK | wx.ICON_EXCLAMATION)
+               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()
@@ -388,8 +479,14 @@ class mainWindow(wx.Frame):
                        firmwareInstall.InstallFirmware(filename)
 
        def OnFirstRunWizard(self, e):
+               self.Hide()
                configWizard.configWizard()
-               self.updateProfileToControls()
+               self.Show()
+               self.reloadSettingPanels()
+
+       def OnSelectMachine(self, index):
+               profile.setActiveMachine(index)
+               self.reloadSettingPanels()
 
        def OnBedLevelWizard(self, e):
                configWizard.bedLevelWizard()
@@ -412,41 +509,31 @@ class mainWindow(wx.Frame):
                debugger.Centre()
                debugger.Show(True)
 
-       def OnYouMagine(self, e):
-               if len(self.scene._scene.objects()) < 1:
-                       wx.MessageBox('You cannot upload to YouMagine without have a file loaded.', 'Cura', wx.OK | wx.ICON_ERROR)
-                       return
-               youmagineGui.youmagineManager(self, self.scene._scene)
+       def onCopyProfileClipboard(self, e):
+               try:
+                       if not wx.TheClipboard.IsOpened():
+                               wx.TheClipboard.Open()
+                               clipData = wx.TextDataObject()
+                               self.lastTriedClipboard = profile.getProfileString()
+                               profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
+                               clipData.SetText(profileString)
+                               wx.TheClipboard.SetData(clipData)
+                               wx.TheClipboard.Close()
+               except:
+                       print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
 
        def OnCheckForUpdate(self, e):
                newVersion = version.checkForNewerVersion()
                if newVersion is not None:
-                       if wx.MessageBox('A new version of Cura is available, would you like to download?', 'New version available', wx.YES_NO | wx.ICON_INFORMATION) == wx.YES:
+                       if wx.MessageBox(_("A new version of Cura is available, would you like to download?"), _("New version available"), wx.YES_NO | wx.ICON_INFORMATION) == wx.YES:
                                webbrowser.open(newVersion)
                else:
-                       wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
+                       wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
 
        def OnAbout(self, e):
-               info = wx.AboutDialogInfo()
-               info.SetName('Cura')
-               info.SetDescription('End solution for Open Source Fused Filament Fabrication 3D printing.')
-               info.SetWebSite('http://software.ultimaker.com/')
-               info.SetCopyright('Copyright (C) David Braam')
-               info.SetLicence("""
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Affero General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Affero General Public License for more details.
-
-    You should have received a copy of the GNU Affero General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-""")
-               wx.AboutBox(info)
+               aboutBox = aboutWindow.aboutWindow()
+               aboutBox.Centre()
+               aboutBox.Show()
 
        def OnClose(self, e):
                profile.saveProfile(profile.getDefaultProfilePath())
@@ -459,15 +546,15 @@ class mainWindow(wx.Frame):
                        profile.putPreference('window_pos_y', posy)
                        (width, height) = self.GetSize()
                        profile.putPreference('window_width', width)
-                       profile.putPreference('window_height', height)                  
-                       
+                       profile.putPreference('window_height', height)
+
                        # Save normal sash position.  If in normal mode (!simple mode), get last position of sash before saving it...
                        isSimple = profile.getPreference('startMode') == 'Simple'
                        if not isSimple:
                                self.normalSashPos = self.splitter.GetSashPosition()
                        profile.putPreference('window_normal_sash', self.normalSashPos)
 
-               #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
+               #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._slicer.cleanup()
@@ -489,21 +576,21 @@ class normalSettingsPanel(configBase.configPanelBase):
                (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')
                self._addSettingsToPanels('advanced', left, right)
                self.SizeLabelWidths(left, right)
 
                #Plugin page
                self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
-               if len(self.pluginPanel.pluginList) > 0:
-                       self.nb.AddPage(self.pluginPanel, "Plugins")
-               else:
-                       self.pluginPanel.Show(False)
+               self.nb.AddPage(self.pluginPanel, _("Plugins"))
 
                #Alteration page
-               self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
-               self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
+               if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
+                       self.alterationPanel = None
+               else:
+                       self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
+                       self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
 
                self.Bind(wx.EVT_SIZE, self.OnSize)
 
@@ -520,10 +607,9 @@ class normalSettingsPanel(configBase.configPanelBase):
                        n += 1 + len(profile.getSettingsForCategory(category, title))
                        if n > count / 2:
                                p = right
-                       configBase.TitleRow(p, title)
+                       configBase.TitleRow(p, _(title))
                        for s in profile.getSettingsForCategory(category, title):
-                               if s.checkConditions():
-                                       configBase.SettingRow(p, s.getName())
+                               configBase.SettingRow(p, s.getName())
 
        def SizeLabelWidths(self, left, right):
                leftWidth = self.getLabelColumnWidth(left)
@@ -535,17 +621,17 @@ class normalSettingsPanel(configBase.configPanelBase):
        def OnSize(self, e):
                # Make the size of the Notebook control the same size as this control
                self.nb.SetSize(self.GetSize())
-               
+
                # Propegate the OnSize() event (just in case)
                e.Skip()
-               
+
                # Perform out resize magic
                self.UpdateSize(self.printPanel)
                self.UpdateSize(self.advancedPanel)
-       
+
        def UpdateSize(self, configPanel):
                sizer = configPanel.GetSizer()
-               
+
                # Pseudocde
                # if horizontal:
                #     if width(col1) < best_width(col1) || width(col2) < best_width(col2):
@@ -554,7 +640,7 @@ class normalSettingsPanel(configBase.configPanelBase):
                #     if width(col1) > (best_width(col1) + best_width(col1)):
                #         switch to horizontal
                #
-                               
+
                col1 = configPanel.leftPanel
                colSize1 = col1.GetSize()
                colBestSize1 = col1.GetBestSize()
@@ -563,7 +649,7 @@ class normalSettingsPanel(configBase.configPanelBase):
                colBestSize2 = col2.GetBestSize()
 
                orientation = sizer.GetOrientation()
-               
+
                if orientation == wx.HORIZONTAL:
                        if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
                                configPanel.Freeze()
@@ -589,5 +675,6 @@ class normalSettingsPanel(configBase.configPanelBase):
 
        def updateProfileToControls(self):
                super(normalSettingsPanel, self).updateProfileToControls()
-               self.alterationPanel.updateProfileToControls()
+               if self.alterationPanel is not None:
+                       self.alterationPanel.updateProfileToControls()
                self.pluginPanel.updateProfileToControls()