Merge pull request #280 from GreatFruitOmsk/macosx
Better support for Mac OS X
This commit is contained in:
commit
c4b3c26be1
24 changed files with 1628 additions and 1411 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,7 +3,7 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
*.zip
|
*.zip
|
||||||
*.exe
|
*.exe
|
||||||
osx64-Cura-*
|
darwin-Cura-*
|
||||||
win32-Cura-*
|
win32-Cura-*
|
||||||
linux-Cura-*
|
linux-Cura-*
|
||||||
Printrun
|
Printrun
|
||||||
|
@ -18,3 +18,4 @@ printrun.bat
|
||||||
cura.bat
|
cura.bat
|
||||||
object-mirror.png
|
object-mirror.png
|
||||||
object.png
|
object.png
|
||||||
|
*darwin.dmg
|
||||||
|
|
65
Cura/cura.py
65
Cura/cura.py
|
@ -9,12 +9,13 @@ The slicing code is the same as Skeinforge. But the UI has been revamped to be..
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import __init__
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import platform
|
import warnings
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import wx._core
|
||||||
|
|
||||||
from util import profile
|
from util import profile
|
||||||
|
|
||||||
__author__ = 'Daid'
|
__author__ = 'Daid'
|
||||||
|
@ -36,6 +37,7 @@ Reece.Arnott <http://forums.reprap.org/profile.php?12,152>
|
||||||
Wade <http://forums.reprap.org/profile.php?12,489>
|
Wade <http://forums.reprap.org/profile.php?12,489>
|
||||||
Xsainnz <http://forums.reprap.org/profile.php?12,563>
|
Xsainnz <http://forums.reprap.org/profile.php?12,563>
|
||||||
Zach Hoeken <http://blog.zachhoeken.com/>
|
Zach Hoeken <http://blog.zachhoeken.com/>
|
||||||
|
Ilya Kulakov (kulakov.ilya@gmail.com)
|
||||||
|
|
||||||
Organizations:
|
Organizations:
|
||||||
Ultimaker <http://www.ultimaker.com>
|
Ultimaker <http://www.ultimaker.com>
|
||||||
|
@ -43,45 +45,66 @@ Art of Illusion <http://www.artofillusion.org/>"""
|
||||||
|
|
||||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||||
|
|
||||||
|
|
||||||
|
class CuraApp(wx.App):
|
||||||
|
def MacOpenFile(self, path):
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
warnings.warn("File at {p} cannot be read: {e}".format(p=path, e=str(e)))
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = OptionParser(usage="usage: %prog [options] <filename>.stl")
|
parser = OptionParser(usage="usage: %prog [options] <filename>.stl")
|
||||||
parser.add_option("-i", "--ini", action="store", type="string", dest="profileini", help="Load settings from a profile ini file")
|
parser.add_option("-i", "--ini", action="store", type="string", dest="profileini",
|
||||||
parser.add_option("-P", "--project", action="store_true", dest="openprojectplanner", help="Open the project planner")
|
help="Load settings from a profile ini file")
|
||||||
parser.add_option("-F", "--flat", action="store_true", dest="openflatslicer", help="Open the 2D SVG slicer (unfinished)")
|
parser.add_option("-P", "--project", action="store_true", dest="openprojectplanner",
|
||||||
parser.add_option("-r", "--print", action="store", type="string", dest="printfile", help="Open the printing interface, instead of the normal cura interface.")
|
help="Open the project planner")
|
||||||
parser.add_option("-p", "--profile", action="store", type="string", dest="profile", help="Internal option, do not use!")
|
parser.add_option("-F", "--flat", action="store_true", dest="openflatslicer",
|
||||||
parser.add_option("-s", "--slice", action="store_true", dest="slice", help="Slice the given files instead of opening them in Cura")
|
help="Open the 2D SVG slicer (unfinished)")
|
||||||
|
parser.add_option("-r", "--print", action="store", type="string", dest="printfile",
|
||||||
|
help="Open the printing interface, instead of the normal cura interface.")
|
||||||
|
parser.add_option("-p", "--profile", action="store", type="string", dest="profile",
|
||||||
|
help="Internal option, do not use!")
|
||||||
|
parser.add_option("-s", "--slice", action="store_true", dest="slice",
|
||||||
|
help="Slice the given files instead of opening them in Cura")
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
if options.profile != None:
|
|
||||||
|
if options.profile is not None:
|
||||||
profile.loadGlobalProfileFromString(options.profile)
|
profile.loadGlobalProfileFromString(options.profile)
|
||||||
if options.profileini != None:
|
if options.profileini is not None:
|
||||||
profile.loadGlobalProfile(options.profileini)
|
profile.loadGlobalProfile(options.profileini)
|
||||||
if options.openprojectplanner != None:
|
|
||||||
|
if options.openprojectplanner is not None:
|
||||||
from gui import projectPlanner
|
from gui import projectPlanner
|
||||||
projectPlanner.main()
|
projectPlanner.main()
|
||||||
return
|
elif options.openflatslicer is not None:
|
||||||
if options.openflatslicer != None:
|
|
||||||
from gui import flatSlicerWindow
|
from gui import flatSlicerWindow
|
||||||
flatSlicerWindow.main()
|
flatSlicerWindow.main()
|
||||||
return
|
elif options.printfile is not None:
|
||||||
if options.printfile != None:
|
|
||||||
from gui import printWindow
|
from gui import printWindow
|
||||||
printWindow.startPrintInterface(options.printfile)
|
printWindow.startPrintInterface(options.printfile)
|
||||||
return
|
elif options.slice is not None:
|
||||||
|
|
||||||
if options.slice != None:
|
|
||||||
from util import sliceRun
|
from util import sliceRun
|
||||||
sliceRun.runSlice(args)
|
sliceRun.runSlice(args)
|
||||||
else:
|
else:
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
profile.putPreference('lastFile', ';'.join(args))
|
profile.putPreference('lastFile', ';'.join(args))
|
||||||
|
|
||||||
from gui import splashScreen
|
from gui import splashScreen
|
||||||
splashScreen.showSplash(mainWindowRunCallback)
|
|
||||||
|
|
||||||
def mainWindowRunCallback(splash):
|
def mainWindowRunCallback(splash):
|
||||||
from gui import mainWindow
|
from gui import mainWindow
|
||||||
mainWindow.main(splash)
|
if splash is not None:
|
||||||
|
splash.Show(False)
|
||||||
|
mainWindow.main()
|
||||||
|
|
||||||
|
app = CuraApp(False)
|
||||||
|
# Apple discurage usage of splash screens on a mac.
|
||||||
|
if sys.platform.startswith('darwin'):
|
||||||
|
mainWindowRunCallback(None)
|
||||||
|
else:
|
||||||
|
splashScreen.splashScreen(mainWindowRunCallback)
|
||||||
|
app.MainLoop()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
# coding=utf-8
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import __init__
|
|
||||||
|
|
||||||
import wx, os, platform, types, webbrowser, threading, time, re
|
import webbrowser
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
import wx
|
||||||
import wx.wizard
|
import wx.wizard
|
||||||
|
|
||||||
from gui import firmwareInstall
|
from gui import firmwareInstall
|
||||||
|
@ -9,6 +13,7 @@ from gui import toolbarUtil
|
||||||
from gui import printWindow
|
from gui import printWindow
|
||||||
from util import machineCom
|
from util import machineCom
|
||||||
from util import profile
|
from util import profile
|
||||||
|
from util.resources import getPathForImage
|
||||||
|
|
||||||
class InfoBox(wx.Panel):
|
class InfoBox(wx.Panel):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
|
@ -18,10 +23,15 @@ class InfoBox(wx.Panel):
|
||||||
self.sizer = wx.GridBagSizer(5, 5)
|
self.sizer = wx.GridBagSizer(5, 5)
|
||||||
self.SetSizer(self.sizer)
|
self.SetSizer(self.sizer)
|
||||||
|
|
||||||
self.attentionBitmap = toolbarUtil.getBitmapImage('attention.png')
|
self.attentionBitmap = wx.Bitmap(getPathForImage('attention.png'))
|
||||||
self.errorBitmap = toolbarUtil.getBitmapImage('error.png')
|
self.errorBitmap = wx.Bitmap(getPathForImage('error.png'))
|
||||||
self.readyBitmap = toolbarUtil.getBitmapImage('ready.png')
|
self.readyBitmap = wx.Bitmap(getPathForImage('ready.png'))
|
||||||
self.busyBitmap = [toolbarUtil.getBitmapImage('busy-0.png'), toolbarUtil.getBitmapImage('busy-1.png'), toolbarUtil.getBitmapImage('busy-2.png'), toolbarUtil.getBitmapImage('busy-3.png')]
|
self.busyBitmap = [
|
||||||
|
wx.Bitmap(getPathForImage('busy-0.png')),
|
||||||
|
wx.Bitmap(getPathForImage('busy-1.png')),
|
||||||
|
wx.Bitmap(getPathForImage('busy-2.png')),
|
||||||
|
wx.Bitmap(getPathForImage('busy-3.png'))
|
||||||
|
]
|
||||||
|
|
||||||
self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
|
self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
|
||||||
self.text = wx.StaticText(self, -1, '')
|
self.text = wx.StaticText(self, -1, '')
|
||||||
|
@ -66,6 +76,9 @@ class InfoBox(wx.Panel):
|
||||||
self.busyState = 0
|
self.busyState = 0
|
||||||
self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
|
self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
|
||||||
|
|
||||||
|
def doExtraInfo(self, e):
|
||||||
|
webbrowser.open(self.extraInfoUrl)
|
||||||
|
|
||||||
def doBusyUpdate(self, e):
|
def doBusyUpdate(self, e):
|
||||||
if self.busyState == None:
|
if self.busyState == None:
|
||||||
return
|
return
|
||||||
|
@ -74,9 +87,6 @@ class InfoBox(wx.Panel):
|
||||||
self.busyState = 0
|
self.busyState = 0
|
||||||
self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
|
self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
|
||||||
|
|
||||||
def doExtraInfo(self, e):
|
|
||||||
webbrowser.open(self.extraInfoUrl)
|
|
||||||
|
|
||||||
def SetReadyIndicator(self):
|
def SetReadyIndicator(self):
|
||||||
self.busyState = None
|
self.busyState = None
|
||||||
self.bitmap.SetBitmap(self.readyBitmap)
|
self.bitmap.SetBitmap(self.readyBitmap)
|
||||||
|
@ -89,6 +99,7 @@ class InfoBox(wx.Panel):
|
||||||
self.busyState = None
|
self.busyState = None
|
||||||
self.bitmap.SetBitmap(self.attentionBitmap)
|
self.bitmap.SetBitmap(self.attentionBitmap)
|
||||||
|
|
||||||
|
|
||||||
class InfoPage(wx.wizard.WizardPageSimple):
|
class InfoPage(wx.wizard.WizardPageSimple):
|
||||||
def __init__(self, parent, title):
|
def __init__(self, parent, title):
|
||||||
wx.wizard.WizardPageSimple.__init__(self, parent)
|
wx.wizard.WizardPageSimple.__init__(self, parent)
|
||||||
|
@ -195,6 +206,7 @@ class InfoPage(wx.wizard.WizardPageSimple):
|
||||||
def StoreData(self):
|
def StoreData(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FirstInfoPage(InfoPage):
|
class FirstInfoPage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(FirstInfoPage, self).__init__(parent, "First time run wizard")
|
super(FirstInfoPage, self).__init__(parent, "First time run wizard")
|
||||||
|
@ -204,13 +216,16 @@ class FirstInfoPage(InfoPage):
|
||||||
self.AddText('* Configure Cura for your machine')
|
self.AddText('* Configure Cura for your machine')
|
||||||
self.AddText('* Upgrade your firmware')
|
self.AddText('* Upgrade your firmware')
|
||||||
self.AddText('* Check if your machine is working safely')
|
self.AddText('* Check if your machine is working safely')
|
||||||
|
|
||||||
#self.AddText('* Calibrate your machine')
|
#self.AddText('* Calibrate your machine')
|
||||||
#self.AddText('* Do your first print')
|
#self.AddText('* Do your first print')
|
||||||
|
|
||||||
|
|
||||||
class RepRapInfoPage(InfoPage):
|
class RepRapInfoPage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(RepRapInfoPage, self).__init__(parent, "RepRap information")
|
super(RepRapInfoPage, self).__init__(parent, "RepRap information")
|
||||||
self.AddText('RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them.')
|
self.AddText(
|
||||||
|
'RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them.')
|
||||||
self.AddText('If you like a default profile for your machine added,\nthen make an issue on github.')
|
self.AddText('If you like a default profile for your machine added,\nthen make an issue on github.')
|
||||||
self.AddSeperator()
|
self.AddSeperator()
|
||||||
self.AddText('You will have to manually install Marlin or Sprinter firmware.')
|
self.AddText('You will have to manually install Marlin or Sprinter firmware.')
|
||||||
|
@ -229,6 +244,7 @@ class RepRapInfoPage(InfoPage):
|
||||||
profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
|
profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
|
||||||
profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
|
profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
|
||||||
|
|
||||||
|
|
||||||
class MachineSelectPage(InfoPage):
|
class MachineSelectPage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(MachineSelectPage, self).__init__(parent, "Select your machine")
|
super(MachineSelectPage, self).__init__(parent, "Select your machine")
|
||||||
|
@ -262,6 +278,7 @@ class MachineSelectPage(InfoPage):
|
||||||
profile.putProfileSetting('nozzle_size', '0.5')
|
profile.putProfileSetting('nozzle_size', '0.5')
|
||||||
profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
|
profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
|
||||||
|
|
||||||
|
|
||||||
class SelectParts(InfoPage):
|
class SelectParts(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(SelectParts, self).__init__(parent, "Select upgraded parts you have")
|
super(SelectParts, self).__init__(parent, "Select upgraded parts you have")
|
||||||
|
@ -283,14 +300,18 @@ class SelectParts(InfoPage):
|
||||||
if getPreference('ultimaker_extruder_upgrade') == 'True':
|
if getPreference('ultimaker_extruder_upgrade') == 'True':
|
||||||
putProfileSetting('retraction_enable', 'True')
|
putProfileSetting('retraction_enable', 'True')
|
||||||
|
|
||||||
|
|
||||||
class FirmwareUpgradePage(InfoPage):
|
class FirmwareUpgradePage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
|
super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
|
||||||
self.AddText('Firmware is the piece of software running directly on your 3D printer.\nThis firmware controls the step motors, regulates the temperature\nand ultimately makes your printer work.')
|
self.AddText(
|
||||||
|
'Firmware is the piece of software running directly on your 3D printer.\nThis firmware controls the step motors, regulates the temperature\nand ultimately makes your printer work.')
|
||||||
self.AddHiddenSeperator()
|
self.AddHiddenSeperator()
|
||||||
self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')
|
self.AddText(
|
||||||
|
'The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')
|
||||||
self.AddHiddenSeperator()
|
self.AddHiddenSeperator()
|
||||||
self.AddText('Cura requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now.')
|
self.AddText(
|
||||||
|
'Cura requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now.')
|
||||||
upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
|
upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
|
||||||
upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
|
upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
|
||||||
skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
|
skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
|
||||||
|
@ -314,22 +335,24 @@ class FirmwareUpgradePage(InfoPage):
|
||||||
def OnUrlClick(self, e):
|
def OnUrlClick(self, e):
|
||||||
webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')
|
webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')
|
||||||
|
|
||||||
|
|
||||||
class UltimakerCheckupPage(InfoPage):
|
class UltimakerCheckupPage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
|
super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
|
||||||
|
|
||||||
self.checkBitmap = toolbarUtil.getBitmapImage('checkmark.png')
|
self.checkBitmap = wx.Bitmap(getPathForImage('checkmark.png'))
|
||||||
self.crossBitmap = toolbarUtil.getBitmapImage('cross.png')
|
self.crossBitmap = wx.Bitmap(getPathForImage('cross.png'))
|
||||||
self.unknownBitmap = toolbarUtil.getBitmapImage('question.png')
|
self.unknownBitmap = wx.Bitmap(getPathForImage('question.png'))
|
||||||
self.endStopNoneBitmap = toolbarUtil.getBitmapImage('endstop_none.png')
|
self.endStopNoneBitmap = wx.Bitmap(getPathForImage('endstop_none.png'))
|
||||||
self.endStopXMinBitmap = toolbarUtil.getBitmapImage('endstop_xmin.png')
|
self.endStopXMinBitmap = wx.Bitmap(getPathForImage('endstop_xmin.png'))
|
||||||
self.endStopXMaxBitmap = toolbarUtil.getBitmapImage('endstop_xmax.png')
|
self.endStopXMaxBitmap = wx.Bitmap(getPathForImage('endstop_xmax.png'))
|
||||||
self.endStopYMinBitmap = toolbarUtil.getBitmapImage('endstop_ymin.png')
|
self.endStopYMinBitmap = wx.Bitmap(getPathForImage('endstop_ymin.png'))
|
||||||
self.endStopYMaxBitmap = toolbarUtil.getBitmapImage('endstop_ymax.png')
|
self.endStopYMaxBitmap = wx.Bitmap(getPathForImage('endstop_ymax.png'))
|
||||||
self.endStopZMinBitmap = toolbarUtil.getBitmapImage('endstop_zmin.png')
|
self.endStopZMinBitmap = wx.Bitmap(getPathForImage('endstop_zmin.png'))
|
||||||
self.endStopZMaxBitmap = toolbarUtil.getBitmapImage('endstop_zmax.png')
|
self.endStopZMaxBitmap = wx.Bitmap(getPathForImage('endstop_zmax.png'))
|
||||||
|
|
||||||
self.AddText('It is a good idea to do a few sanity checks now on your Ultimaker.\nYou can skip these if you know your machine is functional.')
|
self.AddText(
|
||||||
|
'It is a good idea to do a few sanity checks now on your Ultimaker.\nYou can skip these if you know your machine is functional.')
|
||||||
b1, b2 = self.AddDualButton('Run checks', 'Skip checks')
|
b1, b2 = self.AddDualButton('Run checks', 'Skip checks')
|
||||||
b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
|
b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
|
||||||
b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
|
b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
|
||||||
|
@ -513,6 +536,7 @@ class UltimakerCheckupPage(InfoPage):
|
||||||
def mcZChange(self, newZ):
|
def mcZChange(self, newZ):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UltimakerCalibrationPage(InfoPage):
|
class UltimakerCalibrationPage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
|
super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
|
||||||
|
@ -528,12 +552,14 @@ class UltimakerCalibrationPage(InfoPage):
|
||||||
self.AddSeperator()
|
self.AddSeperator()
|
||||||
self.AddText("First we need the diameter of your filament:")
|
self.AddText("First we need the diameter of your filament:")
|
||||||
self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
|
self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
|
||||||
self.AddText("If you do not own digital Calipers that can measure\nat least 2 digits then use 2.89mm.\nWhich is the average diameter of most filament.")
|
self.AddText(
|
||||||
|
"If you do not own digital Calipers that can measure\nat least 2 digits then use 2.89mm.\nWhich is the average diameter of most filament.")
|
||||||
self.AddText("Note: This value can be changed later at any time.")
|
self.AddText("Note: This value can be changed later at any time.")
|
||||||
|
|
||||||
def StoreData(self):
|
def StoreData(self):
|
||||||
profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
|
profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
|
||||||
|
|
||||||
|
|
||||||
class UltimakerCalibrateStepsPerEPage(InfoPage):
|
class UltimakerCalibrateStepsPerEPage(InfoPage):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
|
super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
|
||||||
|
@ -552,7 +578,8 @@ class UltimakerCalibrateStepsPerEPage(InfoPage):
|
||||||
self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))
|
self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))
|
||||||
self.AddText("You can repeat these steps to get better calibration.")
|
self.AddText("You can repeat these steps to get better calibration.")
|
||||||
self.AddSeperator()
|
self.AddSeperator()
|
||||||
self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")
|
self.AddText(
|
||||||
|
"If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")
|
||||||
self.heatButton = self.AddButton("Heatup for filament removal")
|
self.heatButton = self.AddButton("Heatup for filament removal")
|
||||||
|
|
||||||
self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
|
self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
|
||||||
|
@ -575,7 +602,9 @@ class UltimakerCalibrateStepsPerEPage(InfoPage):
|
||||||
currentEValue = float(self.stepsPerEInput.GetValue())
|
currentEValue = float(self.stepsPerEInput.GetValue())
|
||||||
self.comm = machineCom.MachineCom()
|
self.comm = machineCom.MachineCom()
|
||||||
if not self.comm.isOpen():
|
if not self.comm.isOpen():
|
||||||
wx.MessageBox("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable", 'Printer error', wx.OK | wx.ICON_INFORMATION)
|
wx.MessageBox(
|
||||||
|
"Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable",
|
||||||
|
'Printer error', wx.OK | wx.ICON_INFORMATION)
|
||||||
self.heatButton.Enable(True)
|
self.heatButton.Enable(True)
|
||||||
self.extrudeButton.Enable(True)
|
self.extrudeButton.Enable(True)
|
||||||
return
|
return
|
||||||
|
@ -605,7 +634,9 @@ class UltimakerCalibrateStepsPerEPage(InfoPage):
|
||||||
self.extrudeButton.Enable(False)
|
self.extrudeButton.Enable(False)
|
||||||
self.comm = machineCom.MachineCom()
|
self.comm = machineCom.MachineCom()
|
||||||
if not self.comm.isOpen():
|
if not self.comm.isOpen():
|
||||||
wx.MessageBox("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable", 'Printer error', wx.OK | wx.ICON_INFORMATION)
|
wx.MessageBox(
|
||||||
|
"Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable",
|
||||||
|
'Printer error', wx.OK | wx.ICON_INFORMATION)
|
||||||
self.heatButton.Enable(True)
|
self.heatButton.Enable(True)
|
||||||
self.extrudeButton.Enable(True)
|
self.extrudeButton.Enable(True)
|
||||||
return
|
return
|
||||||
|
@ -621,7 +652,9 @@ class UltimakerCalibrateStepsPerEPage(InfoPage):
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
|
self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
|
||||||
wx.MessageBox('Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)', 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
|
wx.MessageBox(
|
||||||
|
'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
|
||||||
|
'Machine heatup', wx.OK | wx.ICON_INFORMATION)
|
||||||
self.sendGCommand('M104 S0')
|
self.sendGCommand('M104 S0')
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.comm.close()
|
self.comm.close()
|
||||||
|
@ -640,6 +673,7 @@ class UltimakerCalibrateStepsPerEPage(InfoPage):
|
||||||
def StoreData(self):
|
def StoreData(self):
|
||||||
profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
|
profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
|
||||||
|
|
||||||
|
|
||||||
class configWizard(wx.wizard.Wizard):
|
class configWizard(wx.wizard.Wizard):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(configWizard, self).__init__(None, -1, "Configuration Wizard")
|
super(configWizard, self).__init__(None, -1, "Configuration Wizard")
|
||||||
|
|
|
@ -25,7 +25,7 @@ from util import version
|
||||||
from util import sliceRun
|
from util import sliceRun
|
||||||
from util import meshLoader
|
from util import meshLoader
|
||||||
|
|
||||||
def main(splash):
|
def main():
|
||||||
#app = wx.App(False)
|
#app = wx.App(False)
|
||||||
if profile.getPreference('machine_type') == 'unknown':
|
if profile.getPreference('machine_type') == 'unknown':
|
||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
|
@ -39,7 +39,6 @@ def main(splash):
|
||||||
for filename in glob.glob(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'example', '*.*'))):
|
for filename in glob.glob(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'example', '*.*'))):
|
||||||
shutil.copy(filename, os.path.join(os.path.dirname(exampleFile), os.path.basename(filename)))
|
shutil.copy(filename, os.path.join(os.path.dirname(exampleFile), os.path.basename(filename)))
|
||||||
profile.putPreference('lastFile', exampleFile)
|
profile.putPreference('lastFile', exampleFile)
|
||||||
splash.Show(False)
|
|
||||||
configWizard.configWizard()
|
configWizard.configWizard()
|
||||||
if profile.getPreference('startMode') == 'Simple':
|
if profile.getPreference('startMode') == 'Simple':
|
||||||
simpleMode.simpleModeWindow()
|
simpleMode.simpleModeWindow()
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
import math, time, os
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
from util import meshLoader
|
from util import meshLoader
|
||||||
from util import util3d
|
from util import util3d
|
||||||
from util import profile
|
from util import profile
|
||||||
|
from util.resources import getPathForMesh
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import OpenGL
|
import OpenGL
|
||||||
|
|
||||||
OpenGL.ERROR_CHECKING = False
|
OpenGL.ERROR_CHECKING = False
|
||||||
from OpenGL.GLU import *
|
from OpenGL.GLU import *
|
||||||
from OpenGL.GL import *
|
from OpenGL.GL import *
|
||||||
|
|
||||||
hasOpenGLlibs = True
|
hasOpenGLlibs = True
|
||||||
except:
|
except:
|
||||||
print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
|
print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
|
||||||
|
@ -61,7 +67,7 @@ def DrawMachine(machineSize):
|
||||||
|
|
||||||
global platformMesh
|
global platformMesh
|
||||||
if platformMesh == None:
|
if platformMesh == None:
|
||||||
platformMesh = meshLoader.loadMesh(os.path.normpath(os.path.join(os.path.split(__file__)[0], "../images", 'ultimaker_platform.stl')))
|
platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
|
||||||
platformMesh.setRotateMirror(0, False, False, False, False, False)
|
platformMesh.setRotateMirror(0, False, False, False, False, False)
|
||||||
|
|
||||||
DrawMesh(platformMesh)
|
DrawMesh(platformMesh)
|
||||||
|
@ -248,6 +254,7 @@ def DrawMachine(machineSize):
|
||||||
glPopMatrix()
|
glPopMatrix()
|
||||||
glEnable(GL_DEPTH_TEST)
|
glEnable(GL_DEPTH_TEST)
|
||||||
|
|
||||||
|
|
||||||
def ResetMatrixRotationAndScale():
|
def ResetMatrixRotationAndScale():
|
||||||
matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
|
matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
|
||||||
noZ = False
|
noZ = False
|
||||||
|
@ -278,6 +285,7 @@ def ResetMatrixRotationAndScale():
|
||||||
glLoadMatrixf(matrix)
|
glLoadMatrixf(matrix)
|
||||||
return noZ
|
return noZ
|
||||||
|
|
||||||
|
|
||||||
def DrawBox(vMin, vMax):
|
def DrawBox(vMin, vMax):
|
||||||
glBegin(GL_LINE_LOOP)
|
glBegin(GL_LINE_LOOP)
|
||||||
glVertex3f(vMin[0], vMin[1], vMin[2])
|
glVertex3f(vMin[0], vMin[1], vMin[2])
|
||||||
|
@ -303,6 +311,7 @@ def DrawBox(vMin, vMax):
|
||||||
glVertex3f(vMin[0], vMax[1], vMax[2])
|
glVertex3f(vMin[0], vMax[1], vMax[2])
|
||||||
glEnd()
|
glEnd()
|
||||||
|
|
||||||
|
|
||||||
def DrawMeshOutline(mesh):
|
def DrawMeshOutline(mesh):
|
||||||
glEnable(GL_CULL_FACE)
|
glEnable(GL_CULL_FACE)
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
@ -317,6 +326,7 @@ def DrawMeshOutline(mesh):
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY)
|
glDisableClientState(GL_VERTEX_ARRAY)
|
||||||
|
|
||||||
|
|
||||||
def DrawMesh(mesh):
|
def DrawMesh(mesh):
|
||||||
glEnable(GL_CULL_FACE)
|
glEnable(GL_CULL_FACE)
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
@ -346,6 +356,7 @@ def DrawMesh(mesh):
|
||||||
glDisableClientState(GL_VERTEX_ARRAY)
|
glDisableClientState(GL_VERTEX_ARRAY)
|
||||||
glDisableClientState(GL_NORMAL_ARRAY);
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
|
||||||
def DrawMeshSteep(mesh, angle):
|
def DrawMeshSteep(mesh, angle):
|
||||||
cosAngle = math.sin(angle / 180.0 * math.pi)
|
cosAngle = math.sin(angle / 180.0 * math.pi)
|
||||||
glDisable(GL_LIGHTING)
|
glDisable(GL_LIGHTING)
|
||||||
|
@ -383,6 +394,7 @@ def DrawMeshSteep(mesh, angle):
|
||||||
glEnd()
|
glEnd()
|
||||||
glDepthFunc(GL_LESS)
|
glDepthFunc(GL_LESS)
|
||||||
|
|
||||||
|
|
||||||
def DrawGCodeLayer(layer):
|
def DrawGCodeLayer(layer):
|
||||||
filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
|
filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
|
||||||
filamentArea = math.pi * filamentRadius * filamentRadius
|
filamentArea = math.pi * filamentRadius * filamentRadius
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
|
# coding=utf-8
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import __init__
|
|
||||||
|
|
||||||
import wx, threading, re, subprocess, sys, os, time, platform
|
import threading
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import platform
|
||||||
|
|
||||||
|
import wx
|
||||||
from wx.lib import buttons
|
from wx.lib import buttons
|
||||||
|
|
||||||
from gui import icon
|
from gui import icon
|
||||||
|
@ -12,6 +19,7 @@ from util import machineCom
|
||||||
from util import profile
|
from util import profile
|
||||||
from util import gcodeInterpreter
|
from util import gcodeInterpreter
|
||||||
from util import power
|
from util import power
|
||||||
|
from util.resources import getPathForImage
|
||||||
|
|
||||||
printWindowMonitorHandle = None
|
printWindowMonitorHandle = None
|
||||||
|
|
||||||
|
@ -21,6 +29,7 @@ def printFile(filename):
|
||||||
printWindowMonitorHandle = printProcessMonitor()
|
printWindowMonitorHandle = printProcessMonitor()
|
||||||
printWindowMonitorHandle.loadFile(filename)
|
printWindowMonitorHandle.loadFile(filename)
|
||||||
|
|
||||||
|
|
||||||
def startPrintInterface(filename):
|
def startPrintInterface(filename):
|
||||||
#startPrintInterface is called from the main script when we want the printer interface to run in a seperate process.
|
#startPrintInterface is called from the main script when we want the printer interface to run in a seperate process.
|
||||||
# It needs to run in a seperate process, as any running python code blocks the GCode sender pyton code (http://wiki.python.org/moin/GlobalInterpreterLock).
|
# It needs to run in a seperate process, as any running python code blocks the GCode sender pyton code (http://wiki.python.org/moin/GlobalInterpreterLock).
|
||||||
|
@ -34,6 +43,7 @@ def startPrintInterface(filename):
|
||||||
t.start()
|
t.start()
|
||||||
app.MainLoop()
|
app.MainLoop()
|
||||||
|
|
||||||
|
|
||||||
class printProcessMonitor():
|
class printProcessMonitor():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.handle = None
|
self.handle = None
|
||||||
|
@ -45,7 +55,8 @@ class printProcessMonitor():
|
||||||
if platform.machine() == 'i386':
|
if platform.machine() == 'i386':
|
||||||
cmdList.insert(0, 'arch')
|
cmdList.insert(0, 'arch')
|
||||||
cmdList.insert(1, '-i386')
|
cmdList.insert(1, '-i386')
|
||||||
self.handle = subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
self.handle = subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
self.thread = threading.Thread(target=self.Monitor)
|
self.thread = threading.Thread(target=self.Monitor)
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
else:
|
else:
|
||||||
|
@ -61,9 +72,10 @@ class printProcessMonitor():
|
||||||
self.handle = None
|
self.handle = None
|
||||||
self.thread = None
|
self.thread = None
|
||||||
|
|
||||||
|
|
||||||
class PrintCommandButton(buttons.GenBitmapButton):
|
class PrintCommandButton(buttons.GenBitmapButton):
|
||||||
def __init__(self, parent, commandList, bitmapFilename, size=(20, 20)):
|
def __init__(self, parent, commandList, bitmapFilename, size=(20, 20)):
|
||||||
self.bitmap = toolbarUtil.getBitmapImage(bitmapFilename)
|
self.bitmap = wx.Bitmap(getPathForImage(bitmapFilename))
|
||||||
super(PrintCommandButton, self).__init__(parent.directControlPanel, -1, self.bitmap, size=size)
|
super(PrintCommandButton, self).__init__(parent.directControlPanel, -1, self.bitmap, size=size)
|
||||||
|
|
||||||
self.commandList = commandList
|
self.commandList = commandList
|
||||||
|
@ -81,8 +93,10 @@ class PrintCommandButton(buttons.GenBitmapButton):
|
||||||
self.parent.machineCom.sendCommand(cmd)
|
self.parent.machineCom.sendCommand(cmd)
|
||||||
e.Skip()
|
e.Skip()
|
||||||
|
|
||||||
|
|
||||||
class printWindow(wx.Frame):
|
class printWindow(wx.Frame):
|
||||||
"Main user interface window"
|
"Main user interface window"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(printWindow, self).__init__(None, -1, title='Printing')
|
super(printWindow, self).__init__(None, -1, title='Printing')
|
||||||
self.machineCom = None
|
self.machineCom = None
|
||||||
|
@ -131,7 +145,8 @@ class printWindow(wx.Frame):
|
||||||
self.OnPowerWarningChange(None)
|
self.OnPowerWarningChange(None)
|
||||||
self.powerWarningTimer.Start(10000)
|
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)
|
boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)
|
||||||
|
|
||||||
self.sizer.Add(boxsizer, pos=(0, 0), span=(7, 1), flag=wx.EXPAND)
|
self.sizer.Add(boxsizer, pos=(0, 0), span=(7, 1), flag=wx.EXPAND)
|
||||||
|
@ -162,7 +177,8 @@ class printWindow(wx.Frame):
|
||||||
self.temperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
|
self.temperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
|
||||||
self.temperatureSelect.SetRange(0, 400)
|
self.temperatureSelect.SetRange(0, 400)
|
||||||
self.bedTemperatureLabel = wx.StaticText(self.temperaturePanel, -1, "BedTemp:")
|
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 = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21),
|
||||||
|
style=wx.SP_ARROW_KEYS)
|
||||||
self.bedTemperatureSelect.SetRange(0, 400)
|
self.bedTemperatureSelect.SetRange(0, 400)
|
||||||
self.bedTemperatureLabel.Show(False)
|
self.bedTemperatureLabel.Show(False)
|
||||||
self.bedTemperatureSelect.Show(False)
|
self.bedTemperatureSelect.Show(False)
|
||||||
|
@ -211,8 +227,10 @@ class printWindow(wx.Frame):
|
||||||
sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-1 F200', 'G90'], 'print-move-z-1.png'), pos=(5, 8))
|
sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-1 F200', 'G90'], 'print-move-z-1.png'), pos=(5, 8))
|
||||||
sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-10 F200', 'G90'], 'print-move-z-10.png'), pos=(6, 8))
|
sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-10 F200', 'G90'], 'print-move-z-10.png'), pos=(6, 8))
|
||||||
|
|
||||||
sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E2 F120'], 'extrude.png', size=(60,20)), pos=(1,10), span=(1,3), flag=wx.EXPAND)
|
sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E2 F120'], 'extrude.png', size=(60, 20)), pos=(1, 10),
|
||||||
sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E-2 F120'], 'retract.png', size=(60,20)), pos=(2,10), span=(1,3), flag=wx.EXPAND)
|
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')
|
||||||
|
|
||||||
|
@ -319,6 +337,7 @@ class printWindow(wx.Frame):
|
||||||
self.statsText.SetMinSize(self.statsText.GetSize())
|
self.statsText.SetMinSize(self.statsText.GetSize())
|
||||||
|
|
||||||
self.UpdateButtonStates()
|
self.UpdateButtonStates()
|
||||||
|
|
||||||
#self.UpdateProgress()
|
#self.UpdateProgress()
|
||||||
|
|
||||||
def OnCameraTimer(self, e):
|
def OnCameraTimer(self, e):
|
||||||
|
@ -349,16 +368,20 @@ class printWindow(wx.Frame):
|
||||||
def UpdateButtonStates(self):
|
def UpdateButtonStates(self):
|
||||||
self.connectButton.Enable(self.machineCom == None or self.machineCom.isClosedOrError())
|
self.connectButton.Enable(self.machineCom == None or self.machineCom.isClosedOrError())
|
||||||
#self.loadButton.Enable(self.machineCom == None or 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 != None and self.machineCom.isOperational() and not (self.machineCom.isPrinting() or self.machineCom.isPaused()))
|
self.printButton.Enable(self.machineCom != None and self.machineCom.isOperational() and not (
|
||||||
self.pauseButton.Enable(self.machineCom != None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
|
self.machineCom.isPrinting() or self.machineCom.isPaused()))
|
||||||
|
self.pauseButton.Enable(
|
||||||
|
self.machineCom != None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
|
||||||
if self.machineCom != None and self.machineCom.isPaused():
|
if self.machineCom != 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 != None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
|
self.cancelButton.Enable(
|
||||||
|
self.machineCom != None and (self.machineCom.isPrinting() or self.machineCom.isPaused()))
|
||||||
self.temperatureSelect.Enable(self.machineCom != None and self.machineCom.isOperational())
|
self.temperatureSelect.Enable(self.machineCom != None and self.machineCom.isOperational())
|
||||||
self.bedTemperatureSelect.Enable(self.machineCom != None and self.machineCom.isOperational())
|
self.bedTemperatureSelect.Enable(self.machineCom != None and self.machineCom.isOperational())
|
||||||
self.directControlPanel.Enable(self.machineCom != None and self.machineCom.isOperational() and not self.machineCom.isPrinting())
|
self.directControlPanel.Enable(
|
||||||
|
self.machineCom != None and self.machineCom.isOperational() and not self.machineCom.isPrinting())
|
||||||
self.machineLogButton.Show(self.machineCom != None and self.machineCom.isClosedOrError())
|
self.machineLogButton.Show(self.machineCom != None and self.machineCom.isClosedOrError())
|
||||||
if self.cam != None:
|
if self.cam != None:
|
||||||
for button in self.cam.buttons:
|
for button in self.cam.buttons:
|
||||||
|
@ -369,11 +392,13 @@ class printWindow(wx.Frame):
|
||||||
if self.gcode == None:
|
if self.gcode == 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: %.2fm %.2fg\n" % (
|
||||||
|
self.gcode.extrusionAmount / 1000, self.gcode.calculateWeight() * 1000)
|
||||||
cost = self.gcode.calculateCost()
|
cost = self.gcode.calculateCost()
|
||||||
if cost != False:
|
if cost != False:
|
||||||
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))
|
status += "Estimated print time: %02d:%02d\n" % (
|
||||||
|
int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))
|
||||||
if self.machineCom == None or not self.machineCom.isPrinting():
|
if self.machineCom == None or not self.machineCom.isPrinting():
|
||||||
self.progress.SetValue(0)
|
self.progress.SetValue(0)
|
||||||
if self.gcodeList != None:
|
if self.gcodeList != None:
|
||||||
|
@ -381,7 +406,8 @@ class printWindow(wx.Frame):
|
||||||
else:
|
else:
|
||||||
printTime = self.machineCom.getPrintTime() / 60
|
printTime = self.machineCom.getPrintTime() / 60
|
||||||
printTimeLeft = self.machineCom.getPrintTimeRemainingEstimate()
|
printTimeLeft = self.machineCom.getPrintTimeRemainingEstimate()
|
||||||
status += 'Line: %d/%d %d%%\n' % (self.machineCom.getPrintPos(), len(self.gcodeList), self.machineCom.getPrintPos() * 100 / len(self.gcodeList))
|
status += 'Line: %d/%d %d%%\n' % (self.machineCom.getPrintPos(), len(self.gcodeList),
|
||||||
|
self.machineCom.getPrintPos() * 100 / len(self.gcodeList))
|
||||||
if self.currentZ > 0:
|
if self.currentZ > 0:
|
||||||
status += 'Height: %0.1f\n' % (self.currentZ)
|
status += 'Height: %0.1f\n' % (self.currentZ)
|
||||||
status += 'Print time: %02d:%02d\n' % (int(printTime / 60), int(printTime % 60))
|
status += 'Print time: %02d:%02d\n' % (int(printTime / 60), int(printTime % 60))
|
||||||
|
@ -586,6 +612,7 @@ class printWindow(wx.Frame):
|
||||||
wx.CallAfter(self.cam.takeNewImage)
|
wx.CallAfter(self.cam.takeNewImage)
|
||||||
wx.CallAfter(self.camPreview.Refresh)
|
wx.CallAfter(self.camPreview.Refresh)
|
||||||
|
|
||||||
|
|
||||||
class temperatureGraph(wx.Panel):
|
class temperatureGraph(wx.Panel):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(temperatureGraph, self).__init__(parent)
|
super(temperatureGraph, self).__init__(parent)
|
||||||
|
@ -705,6 +732,7 @@ class temperatureGraph(wx.Panel):
|
||||||
self.points.append((temp, tempSP, bedTemp, bedTempSP, time.time()))
|
self.points.append((temp, tempSP, bedTemp, bedTempSP, time.time()))
|
||||||
wx.CallAfter(self.UpdateDrawing)
|
wx.CallAfter(self.UpdateDrawing)
|
||||||
|
|
||||||
|
|
||||||
class LogWindow(wx.Frame):
|
class LogWindow(wx.Frame):
|
||||||
def __init__(self, logText):
|
def __init__(self, logText):
|
||||||
super(LogWindow, self).__init__(None, title="Machine log")
|
super(LogWindow, self).__init__(None, title="Machine log")
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
import sys, os
|
# coding=utf-8
|
||||||
#We only need the core here, which speeds up the import. As we want to show the splashscreen ASAP.
|
from __future__ import absolute_import
|
||||||
import wx._core
|
|
||||||
|
import wx._core #We only need the core here, which speeds up the import. As we want to show the splashscreen ASAP.
|
||||||
|
|
||||||
|
from util.resources import getPathForImage
|
||||||
|
|
||||||
def getBitmapImage(filename):
|
|
||||||
#The frozen executable has the script files in a zip, so we need to exit another level to get to our images.
|
|
||||||
if hasattr(sys, 'frozen'):
|
|
||||||
return wx.Bitmap(os.path.normpath(os.path.join(os.path.split(__file__)[0], "../../images", filename)))
|
|
||||||
else:
|
|
||||||
return wx.Bitmap(os.path.normpath(os.path.join(os.path.split(__file__)[0], "../images", filename)))
|
|
||||||
|
|
||||||
class splashScreen(wx.SplashScreen):
|
class splashScreen(wx.SplashScreen):
|
||||||
def __init__(self, callback):
|
def __init__(self, callback):
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
bitmap = getBitmapImage("splash.png")
|
bitmap = wx.Bitmap(getPathForImage('splash.png'))
|
||||||
super(splashScreen, self).__init__(bitmap, wx.SPLASH_CENTRE_ON_SCREEN, 0, None)
|
super(splashScreen, self).__init__(bitmap, wx.SPLASH_CENTRE_ON_SCREEN, 0, None)
|
||||||
wx.CallAfter(self.DoCallback)
|
wx.CallAfter(self.DoCallback)
|
||||||
|
|
||||||
|
@ -20,20 +17,24 @@ class splashScreen(wx.SplashScreen):
|
||||||
self.callback(self)
|
self.callback(self)
|
||||||
self.Destroy()
|
self.Destroy()
|
||||||
|
|
||||||
|
|
||||||
def showSplash(callback):
|
def showSplash(callback):
|
||||||
app = wx.App(False)
|
from Cura.cura import CuraApp
|
||||||
|
app = CuraApp(False)
|
||||||
splashScreen(callback)
|
splashScreen(callback)
|
||||||
app.MainLoop()
|
app.MainLoop()
|
||||||
|
|
||||||
|
|
||||||
def testCallback(splashscreen):
|
def testCallback(splashscreen):
|
||||||
print "Callback!"
|
print "Callback!"
|
||||||
import time
|
import time
|
||||||
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
print "!Callback"
|
print "!Callback"
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
showSplash(testCallback)
|
showSplash(testCallback)
|
||||||
|
|
||||||
if __name__ == u'__main__':
|
if __name__ == u'__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
import os, sys
|
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
from wx.lib import buttons
|
from wx.lib import buttons
|
||||||
|
|
||||||
from util import profile
|
from util import profile
|
||||||
|
from util.resources import getPathForImage
|
||||||
|
|
||||||
|
|
||||||
#######################################################
|
#######################################################
|
||||||
# toolbarUtil contains help classes and functions for
|
# toolbarUtil contains help classes and functions for
|
||||||
# toolbar buttons.
|
# toolbar buttons.
|
||||||
#######################################################
|
#######################################################
|
||||||
|
|
||||||
def getBitmapImage(filename):
|
|
||||||
#The frozen executable has the script files in a zip, so we need to exit another level to get to our images.
|
|
||||||
if hasattr(sys, 'frozen'):
|
|
||||||
return wx.Bitmap(os.path.normpath(os.path.join(os.path.split(__file__)[0], "../../images", filename)))
|
|
||||||
else:
|
|
||||||
return wx.Bitmap(os.path.normpath(os.path.join(os.path.split(__file__)[0], "../images", filename)))
|
|
||||||
|
|
||||||
class Toolbar(wx.ToolBar):
|
class Toolbar(wx.ToolBar):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(Toolbar, self).__init__(parent, -1, style=wx.TB_HORIZONTAL | wx.NO_BORDER)
|
super(Toolbar, self).__init__(parent, -1, style=wx.TB_HORIZONTAL | wx.NO_BORDER)
|
||||||
|
@ -52,11 +47,12 @@ class Toolbar(wx.ToolBar):
|
||||||
sx, sy = control.GetSizeTuple()
|
sx, sy = control.GetSizeTuple()
|
||||||
popup.SetPosition((x, y + sy))
|
popup.SetPosition((x, y + sy))
|
||||||
|
|
||||||
|
|
||||||
class ToggleButton(buttons.GenBitmapToggleButton):
|
class ToggleButton(buttons.GenBitmapToggleButton):
|
||||||
def __init__(self, parent, profileSetting, bitmapFilenameOn, bitmapFilenameOff,
|
def __init__(self, parent, profileSetting, bitmapFilenameOn, bitmapFilenameOff,
|
||||||
helpText='', id=-1, callback=None, size=(20, 20)):
|
helpText='', id=-1, callback=None, size=(20, 20)):
|
||||||
self.bitmapOn = getBitmapImage(bitmapFilenameOn)
|
self.bitmapOn = wx.Bitmap(getPathForImage(bitmapFilenameOn))
|
||||||
self.bitmapOff = getBitmapImage(bitmapFilenameOff)
|
self.bitmapOff = wx.Bitmap(getPathForImage(bitmapFilenameOff))
|
||||||
|
|
||||||
super(ToggleButton, self).__init__(parent, id, self.bitmapOff, size=size)
|
super(ToggleButton, self).__init__(parent, id, self.bitmapOff, size=size)
|
||||||
|
|
||||||
|
@ -117,11 +113,12 @@ class ToggleButton(buttons.GenBitmapToggleButton):
|
||||||
self.Refresh()
|
self.Refresh()
|
||||||
event.Skip()
|
event.Skip()
|
||||||
|
|
||||||
|
|
||||||
class RadioButton(buttons.GenBitmapButton):
|
class RadioButton(buttons.GenBitmapButton):
|
||||||
def __init__(self, parent, group, bitmapFilenameOn, bitmapFilenameOff,
|
def __init__(self, parent, group, bitmapFilenameOn, bitmapFilenameOff,
|
||||||
helpText='', id=-1, callback=None, size=(20, 20)):
|
helpText='', id=-1, callback=None, size=(20, 20)):
|
||||||
self.bitmapOn = getBitmapImage(bitmapFilenameOn)
|
self.bitmapOn = wx.Bitmap(getPathForImage(bitmapFilenameOn))
|
||||||
self.bitmapOff = getBitmapImage(bitmapFilenameOff)
|
self.bitmapOff = wx.Bitmap(getPathForImage(bitmapFilenameOff))
|
||||||
|
|
||||||
super(RadioButton, self).__init__(parent, id, self.bitmapOff, size=size)
|
super(RadioButton, self).__init__(parent, id, self.bitmapOff, size=size)
|
||||||
|
|
||||||
|
@ -179,10 +176,11 @@ class RadioButton(buttons.GenBitmapButton):
|
||||||
self.Refresh()
|
self.Refresh()
|
||||||
event.Skip()
|
event.Skip()
|
||||||
|
|
||||||
|
|
||||||
class NormalButton(buttons.GenBitmapButton):
|
class NormalButton(buttons.GenBitmapButton):
|
||||||
def __init__(self, parent, callback, bitmapFilename,
|
def __init__(self, parent, callback, bitmapFilename,
|
||||||
helpText='', id=-1, size=(20, 20)):
|
helpText='', id=-1, size=(20, 20)):
|
||||||
self.bitmap = getBitmapImage(bitmapFilename)
|
self.bitmap = wx.Bitmap(getPathForImage(bitmapFilename))
|
||||||
super(NormalButton, self).__init__(parent, id, self.bitmap, size=size)
|
super(NormalButton, self).__init__(parent, id, self.bitmap, size=size)
|
||||||
|
|
||||||
self.helpText = helpText
|
self.helpText = helpText
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import os, glob, subprocess, platform
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import subprocess
|
||||||
|
import platform
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
|
|
||||||
from util import profile
|
from util import profile
|
||||||
|
from util.resources import getPathForImage
|
||||||
from gui import toolbarUtil
|
from gui import toolbarUtil
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -26,6 +34,7 @@ def hasWebcamSupport():
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def getFFMPEGpath():
|
def getFFMPEGpath():
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
return os.path.normpath(os.path.join(os.path.split(__file__)[0], "../ffmpeg.exe"))
|
return os.path.normpath(os.path.join(os.path.split(__file__)[0], "../ffmpeg.exe"))
|
||||||
|
@ -33,11 +42,12 @@ def getFFMPEGpath():
|
||||||
return '/usr/bin/ffmpeg'
|
return '/usr/bin/ffmpeg'
|
||||||
return os.path.normpath(os.path.join(os.path.split(__file__)[0], "../ffmpeg"))
|
return os.path.normpath(os.path.join(os.path.split(__file__)[0], "../ffmpeg"))
|
||||||
|
|
||||||
|
|
||||||
class webcam(object):
|
class webcam(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._cam = None
|
self._cam = None
|
||||||
self._overlayImage = toolbarUtil.getBitmapImage("cura-overlay.png")
|
self._overlayImage = wx.Bitmap(getPathForImage('cura-overlay.png'))
|
||||||
self._overlayUltimaker = toolbarUtil.getBitmapImage("ultimaker-overlay.png")
|
self._overlayUltimaker = wx.Bitmap(getPathForImage('ultimaker-overlay.png'))
|
||||||
if cv != None:
|
if cv != None:
|
||||||
self._cam = highgui.cvCreateCameraCapture(-1)
|
self._cam = highgui.cvCreateCameraCapture(-1)
|
||||||
elif win32vidcap != None:
|
elif win32vidcap != None:
|
||||||
|
@ -100,13 +110,15 @@ class webcam(object):
|
||||||
dc.SelectObject(bitmap)
|
dc.SelectObject(bitmap)
|
||||||
dc.DrawBitmap(self._overlayImage, bitmap.GetWidth() - self._overlayImage.GetWidth() - 5, 5, True)
|
dc.DrawBitmap(self._overlayImage, bitmap.GetWidth() - self._overlayImage.GetWidth() - 5, 5, True)
|
||||||
if profile.getPreference('machine_type') == 'ultimaker':
|
if profile.getPreference('machine_type') == 'ultimaker':
|
||||||
dc.DrawBitmap(self._overlayUltimaker, (bitmap.GetWidth() - self._overlayUltimaker.GetWidth()) / 2, bitmap.GetHeight() - self._overlayUltimaker.GetHeight() - 5, True)
|
dc.DrawBitmap(self._overlayUltimaker, (bitmap.GetWidth() - self._overlayUltimaker.GetWidth()) / 2,
|
||||||
|
bitmap.GetHeight() - self._overlayUltimaker.GetHeight() - 5, True)
|
||||||
dc.SelectObject(wx.NullBitmap)
|
dc.SelectObject(wx.NullBitmap)
|
||||||
|
|
||||||
self._bitmap = bitmap
|
self._bitmap = bitmap
|
||||||
|
|
||||||
if self._doTimelaps:
|
if self._doTimelaps:
|
||||||
filename = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../__tmp_snap", "__tmp_snap_%04d.jpg" % (self._snapshotCount)))
|
filename = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../__tmp_snap",
|
||||||
|
"__tmp_snap_%04d.jpg" % (self._snapshotCount)))
|
||||||
self._snapshotCount += 1
|
self._snapshotCount += 1
|
||||||
bitmap.SaveFile(filename, wx.BITMAP_TYPE_JPEG)
|
bitmap.SaveFile(filename, wx.BITMAP_TYPE_JPEG)
|
||||||
|
|
||||||
|
@ -127,8 +139,11 @@ class webcam(object):
|
||||||
def endTimelaps(self):
|
def endTimelaps(self):
|
||||||
if self._doTimelaps:
|
if self._doTimelaps:
|
||||||
ffmpeg = getFFMPEGpath()
|
ffmpeg = getFFMPEGpath()
|
||||||
basePath = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../__tmp_snap", "__tmp_snap_%04d.jpg"))
|
basePath = os.path.normpath(
|
||||||
subprocess.call([ffmpeg, '-r', '12.5', '-i', basePath, '-vcodec', 'mpeg2video', '-pix_fmt', 'yuv420p', '-r', '25', '-y', '-b:v', '1500k', '-f', 'vob', self._timelapsFilename])
|
os.path.join(os.path.split(__file__)[0], "../__tmp_snap", "__tmp_snap_%04d.jpg"))
|
||||||
|
subprocess.call(
|
||||||
|
[ffmpeg, '-r', '12.5', '-i', basePath, '-vcodec', 'mpeg2video', '-pix_fmt', 'yuv420p', '-r', '25', '-y',
|
||||||
|
'-b:v', '1500k', '-f', 'vob', self._timelapsFilename])
|
||||||
self._doTimelaps = False
|
self._doTimelaps = False
|
||||||
|
|
||||||
def _cleanTempDir(self):
|
def _cleanTempDir(self):
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import sys, os, zipfile
|
|
||||||
try:
|
|
||||||
import cx_Freeze
|
|
||||||
except:
|
|
||||||
print "ERROR: You need cx-Freeze installed to build this package"
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
freezeVersion = map(int, cx_Freeze.version.split('.'))
|
|
||||||
if freezeVersion[0] < 4 or freezeVersion[0] == 4 and freezeVersion[1] < 2:
|
|
||||||
print "ERROR: Your cx-Freeze version is too old to use with Cura."
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
sys.path.append(os.path.abspath('cura_sf'))
|
|
||||||
|
|
||||||
# Dependencies are automatically detected, but it might need fine tuning.
|
|
||||||
build_exe_options = {
|
|
||||||
"silent": True,
|
|
||||||
"packages": [
|
|
||||||
'encodings.utf_8',
|
|
||||||
"OpenGL", "OpenGL.arrays", "OpenGL.platform", "OpenGL.GLU",
|
|
||||||
], "excludes": [
|
|
||||||
'Tkinter', 'tcl', 'cura_sf', 'fabmetheus_utilities', 'skeinforge_application', 'numpy',
|
|
||||||
], "include_files": [
|
|
||||||
('images', 'images'),
|
|
||||||
], "build_exe": 'freeze_build'}
|
|
||||||
|
|
||||||
# GUI applications require a different base on Windows (the default is for a
|
|
||||||
# console application).
|
|
||||||
base = None
|
|
||||||
if sys.platform == "win32":
|
|
||||||
base = "Win32GUI"
|
|
||||||
|
|
||||||
cx_Freeze.setup( name = "Cura",
|
|
||||||
version = "RC5",
|
|
||||||
description = "Cura",
|
|
||||||
options = {"build_exe": build_exe_options},
|
|
||||||
executables = [cx_Freeze.Executable("cura.py", base=base)])
|
|
||||||
|
|
||||||
m = cx_Freeze.ModuleFinder(excludes=["gui"])
|
|
||||||
m.IncludeFile(os.path.abspath("cura.py"))
|
|
||||||
m.IncludeFile(os.path.abspath("cura_sf/skeinforge_application/skeinforge_plugins/profile_plugins/extrusion.py"))
|
|
||||||
m.IncludeFile(os.path.abspath("cura_sf/fabmetheus_utilities/fabmetheus_tools/interpret_plugins/stl.py"))
|
|
||||||
m.IncludeFile(os.path.abspath("cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py"))
|
|
||||||
for name in os.listdir("cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins"):
|
|
||||||
if name.endswith('.py'):
|
|
||||||
m.IncludeFile(os.path.abspath("cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/" + name))
|
|
||||||
m.ReportMissingModules()
|
|
||||||
cwd = os.path.abspath(".")
|
|
||||||
|
|
||||||
z = zipfile.ZipFile("freeze_build/cura_sf.zip", "w", zipfile.ZIP_DEFLATED)
|
|
||||||
for mod in m.modules:
|
|
||||||
if mod.file != None and mod.file.startswith(cwd):
|
|
||||||
if mod.file[len(cwd)+1:] == "cura.py":
|
|
||||||
z.write(mod.file[len(cwd)+1:], "__main__.py")
|
|
||||||
else:
|
|
||||||
z.write(mod.file[len(cwd)+1:])
|
|
||||||
z.write('cura_sf/fabmetheus_utilities/templates/layer_template.svg')
|
|
||||||
z.write('cura_sf/fabmetheus_utilities/version.txt')
|
|
||||||
z.write('__init__.py')
|
|
||||||
z.close()
|
|
||||||
|
|
36
Cura/util/resources.py
Normal file
36
Cura/util/resources.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
__all__ = ['getPathForResource', 'getPathForImage', 'getPathForMesh']
|
||||||
|
|
||||||
|
|
||||||
|
if sys.platform.startswith('darwin'):
|
||||||
|
if hasattr(sys, 'frozen'):
|
||||||
|
from Foundation import *
|
||||||
|
imagesPath = os.path.join(NSBundle.mainBundle().resourcePath(), 'images')
|
||||||
|
meshesPath = os.path.join(NSBundle.mainBundle().resourcePath(), 'images')
|
||||||
|
else:
|
||||||
|
imagesPath = os.path.join(os.path.dirname(__file__), "../images")
|
||||||
|
meshesPath = os.path.join(os.path.dirname(__file__), "../images")
|
||||||
|
else:
|
||||||
|
if hasattr(sys, 'frozen'):
|
||||||
|
imagesPath = os.path.join(os.path.dirname(__file__), "../../images")
|
||||||
|
meshesPath = os.path.join(os.path.dirname(__file__), "../../images")
|
||||||
|
else:
|
||||||
|
imagesPath = os.path.join(os.path.dirname(__file__), "../images")
|
||||||
|
meshesPath = os.path.join(os.path.dirname(__file__), "../images")
|
||||||
|
|
||||||
|
|
||||||
|
def getPathForResource(dir, resource_name):
|
||||||
|
assert os.path.isdir(dir), "{p} is not a directory".format(p=dir)
|
||||||
|
path = os.path.normpath(os.path.join(dir, resource_name))
|
||||||
|
assert os.path.isfile(path), "{p} is not a file.".format(p=path)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def getPathForImage(name):
|
||||||
|
return getPathForResource(imagesPath, name)
|
||||||
|
|
||||||
|
def getPathForMesh(name):
|
||||||
|
return getPathForResource(meshesPath, name)
|
68
README.md
68
README.md
|
@ -9,9 +9,77 @@ Development
|
||||||
Cura is developed in Python. Getting Cura up and running for development is not very difficult. If you copy the python and pypy from a release into your Cura development checkout then you can use Cura right away, just like you would with a release.
|
Cura is developed in Python. Getting Cura up and running for development is not very difficult. If you copy the python and pypy from a release into your Cura development checkout then you can use Cura right away, just like you would with a release.
|
||||||
For development with git, check the help on github. Pull requests is the fastest way to get changes into Cura.
|
For development with git, check the help on github. Pull requests is the fastest way to get changes into Cura.
|
||||||
|
|
||||||
|
|
||||||
Packaging
|
Packaging
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Cura development comes with a script "package.sh", this script has been designed to run under unix like OSes (Linux, MacOS). Running it from sygwin is not a priority.
|
Cura development comes with a script "package.sh", this script has been designed to run under unix like OSes (Linux, MacOS). Running it from sygwin is not a priority.
|
||||||
The "package.sh" script generates a final release package. You should not need it during development, unless you are changing the release process. If you want to distribute your own version of Cura, then the package.sh script will allow you to do that.
|
The "package.sh" script generates a final release package. You should not need it during development, unless you are changing the release process. If you want to distribute your own version of Cura, then the package.sh script will allow you to do that.
|
||||||
|
|
||||||
|
|
||||||
|
Mac OS X
|
||||||
|
--------
|
||||||
|
The following section describes how to prepare environment for developing and packaing for Mac OS X.
|
||||||
|
|
||||||
|
###Python
|
||||||
|
You'll need non-system, framework-based, universal with min deployment target set to 10.6 build of Python 2.7
|
||||||
|
|
||||||
|
**non-system**: it was not bundeled with distribution of Mac OS X. You can check this by `python -c "import sys; print sys.prefix"`. Output should *not* start with *"/System/Library/Frameworks/Python.framework/"*
|
||||||
|
|
||||||
|
**framework-based**: Output of `python -c "import distutils.sysconfig as c; print(c.get_config_var('PYTHONFRAMEWORK'))"` should be non-empty string
|
||||||
|
|
||||||
|
**universal**: output of ``lipo -info `which python` `` include both i386 and x86_64. E.g *"Architectures in the fat file: /usr/local/bin/python are: i386 x86_64"*
|
||||||
|
|
||||||
|
**deployment target set to 10.6**: Output of ``otool -l `which python` `` should contain *"cmd LC_VERSION_MIN_MACOSX ... version 10.6"*
|
||||||
|
|
||||||
|
The easiest way to install it is via [Homebrew](http://mxcl.github.com/homebrew/): `brew install --fresh osx_python_cura.rb --universal` (TODO: upload the formula). Note you'll need to uninstall Python if you already have it installed via Homebrew.
|
||||||
|
|
||||||
|
###Virtualenv
|
||||||
|
You may skip this step if you don't bother to use [virtualenv](http://pypi.python.org/pypi/virtualenv). It's not a requirement.
|
||||||
|
|
||||||
|
The main problem with virtualenv is that wxWidgets cannot be installed via pip. We'll have to build it manually from source by specifing prefix to our virtualenv.
|
||||||
|
|
||||||
|
Assuming you have virtualenv at *~/.virtualenvs/Cura*:
|
||||||
|
|
||||||
|
1. Download [wxPython sources](http://sourceforge.net/projects/wxpython/files/wxPython/2.9.4.0/wxPython-src-2.9.4.0.tar.bz2)
|
||||||
|
2. Configure project with the following flags: `./configure --prefix=$HOME/.virtualenvs/Cura/ --enable-optimise --with-libjpeg=builtin --with-libpng=builtin --with-libtiff=builtin --with-zlib=builtin --enable-monolithic --with-macosx-version-min=10.6 --disable-debug --enable-unicode --enable-std_string --enable-display --with-opengl --with-osx_cocoa --enable-dnd --enable-clipboard --enable-webkit --enable-svg --with-expat --enable-universal_binary=i386,x86_64`
|
||||||
|
3. `make install`
|
||||||
|
4. cd into the *wxPython* directory
|
||||||
|
5. Build wxPython modules: `python setup.py build_ext WXPORT=osx_cocoa WX_CONFIG=$HOME/.virtualenvs/Cura/bin/wx-config UNICODE=1 INSTALL_MULTIVERSION=0 BUILD_GLCANVAS=1 BUILD_GIZMOS=1 BUILD_STC=1` (Note that python is the python of your virtualenv)
|
||||||
|
6. Install wxPython and modules: `python setup.py install --prefix=$HOME/.virtualenvs/Cura/ WXPORT=osx_cocoa WX_CONFIG=$HOME/.virtualenvs/Cura/bin/wx-config UNICODE=1 INSTALL_MULTIVERSION=0 BUILD_GLCANVAS=1 BUILD_GIZMOS=1 BUILD_STC=1` (Note that python is the python of your virtualenv)
|
||||||
|
|
||||||
|
Another problem is that python in virtualenv is not suitable for running GUI code. Mac OS X requires python to be inside the bundle. To workaround this issue, we will add the following script to the ~/.virtualenvs/Cura/bin:
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
ENV=`python -c "import sys; print sys.prefix"`
|
||||||
|
PYTHON=`python -c "import sys; print sys.real_prefix"`/bin/python
|
||||||
|
export PYTHONHOME=$ENV
|
||||||
|
exec $PYTHON "$@"
|
||||||
|
|
||||||
|
I typically name this script `pythonw`.
|
||||||
|
|
||||||
|
At this point virtualenv is configured for wxPython development. Remember to use `python` to pacakge the app and `pythonw` to run app without packaging (e.g. for debugging).
|
||||||
|
|
||||||
|
###Requirements
|
||||||
|
Following packages are required for development:
|
||||||
|
|
||||||
|
PyOpenGL>=3.0.2
|
||||||
|
numpy>=1.6.2
|
||||||
|
pyserial>=2.6
|
||||||
|
pyobjc>=2.5
|
||||||
|
|
||||||
|
Following packages are required for packaging Cura into app:
|
||||||
|
|
||||||
|
py2app>=0.7.2
|
||||||
|
|
||||||
|
The easiest way to install all this packages is to use virtualenv's pip: `pip install requirements_darwin.txt`
|
||||||
|
|
||||||
|
####PyObjC
|
||||||
|
At time of writing, pyobjc 2.5 is not available at pypi. You have to clone repo and install it manually:
|
||||||
|
|
||||||
|
hg clone https://bitbucket.org/ronaldoussoren/pyobjc
|
||||||
|
hg checkout c42c98d6e941 # last tested commit
|
||||||
|
python install.py
|
||||||
|
|
||||||
|
###Packaging
|
||||||
|
To package Cura into application bundle simply do `python setup.py py2app`. Resulting bundle is self-contained -- it includes Python and all needed packages.
|
||||||
|
|
79
package.sh
79
package.sh
|
@ -1,17 +1,17 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# This script is to package the Cura package for Windows/Linux and OSx
|
# This script is to package the Cura package for Windows/Linux and Mac OS X
|
||||||
# This script should run under Linux and OSx, as well as Windows with Cygwin.
|
# This script should run under Linux and Mac OS X, as well as Windows with Cygwin.
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
#############################
|
#############################
|
||||||
|
|
||||||
##Select the build target
|
##Select the build target
|
||||||
BUILD_TARGET=${1:-all}
|
# BUILD_TARGET=${1:-all}
|
||||||
#BUILD_TARGET=win32
|
#BUILD_TARGET=win32
|
||||||
#BUILD_TARGET=linux
|
#BUILD_TARGET=linux
|
||||||
#BUILD_TARGET=osx64
|
BUILD_TARGET=darwin
|
||||||
|
|
||||||
##Do we need to create the final archive
|
##Do we need to create the final archive
|
||||||
ARCHIVE_FOR_DISTRIBUTION=1
|
ARCHIVE_FOR_DISTRIBUTION=1
|
||||||
|
@ -62,10 +62,50 @@ function extract
|
||||||
if [ "$BUILD_TARGET" = "all" ]; then
|
if [ "$BUILD_TARGET" = "all" ]; then
|
||||||
$0 win32
|
$0 win32
|
||||||
$0 linux
|
$0 linux
|
||||||
$0 osx64
|
$0 darwin
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# Darwin
|
||||||
|
#############################
|
||||||
|
|
||||||
|
if [ "$BUILD_TARGET" = "darwin" ]; then
|
||||||
|
rm -rf scripts/darwin/build
|
||||||
|
rm -rf scripts/darwin/dist
|
||||||
|
|
||||||
|
python setup.py py2app
|
||||||
|
rc=$?
|
||||||
|
if [[ $rc != 0 ]]; then
|
||||||
|
echo "Cannot build app."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd scripts/darwin
|
||||||
|
|
||||||
|
# Install QuickLook plugin
|
||||||
|
mkdir -p dist/Cura.app/Contents/Library/QuickLook
|
||||||
|
cp STLQuickLook.qlgenerator dist/Cura.app/Contents/Library/QuickLook/
|
||||||
|
|
||||||
|
# Archive app
|
||||||
|
$TAR cfp - dist/Cura.app | gzip --best -c > ../../${TARGET_DIR}.tar.gz
|
||||||
|
|
||||||
|
# Create sparse image for distribution
|
||||||
|
hdiutil detach /Volumes/Cura\ -\ Ultimaker/
|
||||||
|
rm -rf Cura.dmg.sparseimage
|
||||||
|
hdiutil convert DmgTemplateCompressed.dmg -format UDSP -o Cura.dmg
|
||||||
|
hdiutil resize -size 500m Cura.dmg.sparseimage
|
||||||
|
hdiutil attach Cura.dmg.sparseimage
|
||||||
|
cp -a dist/Cura.app /Volumes/Cura\ -\ Ultimaker/Cura/
|
||||||
|
hdiutil detach /Volumes/Cura\ -\ Ultimaker
|
||||||
|
hdiutil convert Cura.dmg.sparseimage -format UDZO -imagekey zlib-level=9 -ov -o ../../${TARGET_DIR}.dmg
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# Rest
|
||||||
|
#############################
|
||||||
|
|
||||||
# Change working directory to the directory the script is in
|
# Change working directory to the directory the script is in
|
||||||
# http://stackoverflow.com/a/246128
|
# http://stackoverflow.com/a/246128
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
@ -100,13 +140,6 @@ if [ $BUILD_TARGET = "win32" ]; then
|
||||||
downloadURL http://www.uwe-sieber.de/files/ejectmedia.zip
|
downloadURL http://www.uwe-sieber.de/files/ejectmedia.zip
|
||||||
#Get pypy
|
#Get pypy
|
||||||
downloadURL https://bitbucket.org/pypy/pypy/downloads/pypy-${PYPY_VERSION}-win32.zip
|
downloadURL https://bitbucket.org/pypy/pypy/downloads/pypy-${PYPY_VERSION}-win32.zip
|
||||||
elif [ $BUILD_TARGET = "osx64" ]; then
|
|
||||||
downloadURL https://bitbucket.org/pypy/pypy/downloads/pypy-${PYPY_VERSION}-${BUILD_TARGET}.tar.bz2
|
|
||||||
downloadURL http://python.org/ftp/python/2.7.3/python-2.7.3-macosx10.6.dmg
|
|
||||||
downloadURL http://sourceforge.net/projects/numpy/files/NumPy/1.6.2/numpy-1.6.2-py2.7-python.org-macosx10.3.dmg
|
|
||||||
downloadURL http://pypi.python.org/packages/source/p/pyserial/pyserial-2.6.tar.gz
|
|
||||||
downloadURL http://pypi.python.org/packages/source/P/PyOpenGL/PyOpenGL-3.0.2.tar.gz
|
|
||||||
downloadURL http://downloads.sourceforge.net/wxpython/wxPython2.9-osx-2.9.4.0-cocoa-py2.7.dmg
|
|
||||||
else
|
else
|
||||||
downloadURL https://bitbucket.org/pypy/pypy/downloads/pypy-${PYPY_VERSION}-${BUILD_TARGET}.tar.bz2
|
downloadURL https://bitbucket.org/pypy/pypy/downloads/pypy-${PYPY_VERSION}-${BUILD_TARGET}.tar.bz2
|
||||||
fi
|
fi
|
||||||
|
@ -208,28 +241,6 @@ if (( ${ARCHIVE_FOR_DISTRIBUTION} )); then
|
||||||
'/c/Program Files (x86)/NSIS/makensis.exe' -DVERSION=${BUILD_NAME} 'scripts/win32/installer.nsi' >> log.txt
|
'/c/Program Files (x86)/NSIS/makensis.exe' -DVERSION=${BUILD_NAME} 'scripts/win32/installer.nsi' >> log.txt
|
||||||
mv scripts/win32/Cura_${BUILD_NAME}.exe ./
|
mv scripts/win32/Cura_${BUILD_NAME}.exe ./
|
||||||
fi
|
fi
|
||||||
elif [ $BUILD_TARGET = "osx64" ]; then
|
|
||||||
echo "Building osx app"
|
|
||||||
mkdir -p scripts/osx64/Cura.app/Contents/Resources
|
|
||||||
mkdir -p scripts/osx64/Cura.app/Contents/Pkgs
|
|
||||||
rm -rf scripts/osx64/Cura.app/Contents/Resources/Cura
|
|
||||||
rm -rf scripts/osx64/Cura.app/Contents/Resources/pypy
|
|
||||||
cp -a ${TARGET_DIR}/* scripts/osx64/Cura.app/Contents/Resources
|
|
||||||
cp python-2.7.3-macosx10.6.dmg scripts/osx64/Cura.app/Contents/Pkgs
|
|
||||||
cp numpy-1.6.2-py2.7-python.org-macosx10.3.dmg scripts/osx64/Cura.app/Contents/Pkgs
|
|
||||||
cp pyserial-2.6.tar.gz scripts/osx64/Cura.app/Contents/Pkgs
|
|
||||||
cp PyOpenGL-3.0.2.tar.gz scripts/osx64/Cura.app/Contents/Pkgs
|
|
||||||
cp wxPython2.9-osx-2.9.4.0-cocoa-py2.7.dmg scripts/osx64/Cura.app/Contents/Pkgs
|
|
||||||
cd scripts/osx64
|
|
||||||
$TAR cfp - Cura.app | gzip --best -c > ../../${TARGET_DIR}.tar.gz
|
|
||||||
hdiutil detach /Volumes/Cura\ -\ Ultimaker/
|
|
||||||
rm -rf Cura.dmg.sparseimage
|
|
||||||
hdiutil convert DmgTemplateCompressed.dmg -format UDSP -o Cura.dmg
|
|
||||||
hdiutil resize -size 500m Cura.dmg.sparseimage
|
|
||||||
hdiutil attach Cura.dmg.sparseimage
|
|
||||||
cp -a Cura.app /Volumes/Cura\ -\ Ultimaker/Cura/
|
|
||||||
hdiutil detach /Volumes/Cura\ -\ Ultimaker
|
|
||||||
hdiutil convert Cura.dmg.sparseimage -format UDZO -imagekey zlib-level=9 -ov -o ../../${TARGET_DIR}.dmg
|
|
||||||
else
|
else
|
||||||
echo "Archiving to ${TARGET_DIR}.tar.gz"
|
echo "Archiving to ${TARGET_DIR}.tar.gz"
|
||||||
$TAR cfp - ${TARGET_DIR} | gzip --best -c > ${TARGET_DIR}.tar.gz
|
$TAR cfp - ${TARGET_DIR} | gzip --best -c > ${TARGET_DIR}.tar.gz
|
||||||
|
|
4
requirements_darwin.txt
Normal file
4
requirements_darwin.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
PyOpenGL>=3.0.2
|
||||||
|
numpy>=1.6.2
|
||||||
|
pyserial>=2.6
|
||||||
|
py2app>=0.7.2
|
75
scripts/darwin/STLQuickLook.qlgenerator/Contents/Info.plist
Normal file
75
scripts/darwin/STLQuickLook.qlgenerator/Contents/Info.plist
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>12C60</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleDocumentTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>QLGenerator</string>
|
||||||
|
<key>LSItemContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>com.pleasantsoftware.uti.stl</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>STLQuickLook</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.pleasantsoftware.qlgenerator.STLQuickLook</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>STLQuickLook</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.1</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>2</string>
|
||||||
|
<key>CFPlugInDynamicRegisterFunction</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFPlugInDynamicRegistration</key>
|
||||||
|
<string>YES</string>
|
||||||
|
<key>CFPlugInFactories</key>
|
||||||
|
<dict>
|
||||||
|
<key>C02E94A7-9A81-43CB-9663-4C4F30F4D259</key>
|
||||||
|
<string>QuickLookGeneratorPluginFactory</string>
|
||||||
|
</dict>
|
||||||
|
<key>CFPlugInTypes</key>
|
||||||
|
<dict>
|
||||||
|
<key>5E2D9680-5022-40FA-B806-43349622E5B9</key>
|
||||||
|
<array>
|
||||||
|
<string>C02E94A7-9A81-43CB-9663-4C4F30F4D259</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<key>CFPlugInUnloadFunction</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>4G2008a</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>GM</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>12C37</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx10.8</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>0452</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>4G2008a</string>
|
||||||
|
<key>QLNeedsToBeRunInMainThread</key>
|
||||||
|
<false/>
|
||||||
|
<key>QLPreviewHeight</key>
|
||||||
|
<real>600</real>
|
||||||
|
<key>QLPreviewWidth</key>
|
||||||
|
<real>800</real>
|
||||||
|
<key>QLSupportsConcurrentRequests</key>
|
||||||
|
<false/>
|
||||||
|
<key>QLThumbnailMinimumSize</key>
|
||||||
|
<real>48</real>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
BIN
scripts/darwin/STLQuickLook.qlgenerator/Contents/MacOS/STLQuickLook
Executable file
BIN
scripts/darwin/STLQuickLook.qlgenerator/Contents/MacOS/STLQuickLook
Executable file
Binary file not shown.
Binary file not shown.
BIN
scripts/darwin/STLQuickLook.qlgenerator/Contents/Resources/stlTagImage.png
Executable file
BIN
scripts/darwin/STLQuickLook.qlgenerator/Contents/Resources/stlTagImage.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 933 B |
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>Cura</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Cura 12.10</string>
|
|
||||||
<key>CFBundleIdentifer</key>
|
|
||||||
<string>daid.cura</string>
|
|
||||||
<key>CFBundleIconFile></key>
|
|
||||||
<string>Resources/Cura.icns</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>12.10</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>Cura</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,134 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
SCRIPTDIR=`dirname "$0"`
|
|
||||||
RESDIR=${SCRIPTDIR}/../Resources/
|
|
||||||
PKGDIR=${SCRIPTDIR}/../Pkgs/
|
|
||||||
|
|
||||||
#run the path_helper to set the $PATH for accessing python
|
|
||||||
if [ -x /usr/libexec/path_helper ]; then
|
|
||||||
eval `/usr/libexec/path_helper -s`
|
|
||||||
fi
|
|
||||||
|
|
||||||
displayMessage()
|
|
||||||
{
|
|
||||||
/usr/bin/osascript > /dev/null << EOF
|
|
||||||
tell application "System Events"
|
|
||||||
activate
|
|
||||||
set question to display dialog "$@"
|
|
||||||
end tell
|
|
||||||
return button returned of question
|
|
||||||
EOF
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
/usr/bin/osascript > /dev/null << EOF
|
|
||||||
tell application "System Events"
|
|
||||||
activate
|
|
||||||
display dialog "User Cancelled Install" buttons {"Ok"}
|
|
||||||
end tell
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#Testing for python2.7, which we need and is not always installed on MacOS 1.6
|
|
||||||
PY="python2.7"
|
|
||||||
$PY -c ''
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Python 2.7 is missing from your system. Cura requires Python2.7.\nStarting the installer" $PATH
|
|
||||||
# Install python2.7
|
|
||||||
hdiutil attach $PKGDIR/python-2.7.3-macosx10.6.dmg
|
|
||||||
open -W /Volumes/Python\ 2.7.3/Python.mpkg
|
|
||||||
hdiutil detach /Volumes/Python\ 2.7.3
|
|
||||||
# Check the installation
|
|
||||||
$PY -c ''
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Failed to install python2.7"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Next check for numpy, numpy does not always run under 64bit, so we need to check if we need to use "arch -i386"
|
|
||||||
$PY -c 'import numpy' 2> /dev/null
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
PY="arch -i386 python2.7"
|
|
||||||
$PY -c 'import numpy'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Numpy is missing from your system, this is required.\nStarting the installer"
|
|
||||||
# Install numpy
|
|
||||||
hdiutil attach $PKGDIR/numpy-1.6.2-py2.7-python.org-macosx10.3.dmg
|
|
||||||
open -W /Volumes/numpy/numpy-1.6.2-py2.7.mpkg
|
|
||||||
hdiutil detach /Volumes/numpy
|
|
||||||
#After installing numpy, we need to check if we need to use arch -386 again
|
|
||||||
PY="python2.7"
|
|
||||||
$PY -c 'import numpy'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
PY="arch -i386 python2.7"
|
|
||||||
$PY -c 'import numpy'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Failed to install numpy."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Check for wxPython
|
|
||||||
$PY -c 'import wx'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "wxPython is missing from your system. Cura requires wxPython.\nStarting the installer"
|
|
||||||
# Start wxPython installer
|
|
||||||
hdiutil attach $PKGDIR/wxPython2.9-osx-2.9.4.0-cocoa-py2.7.dmg
|
|
||||||
open -W /Volumes/wxPython2.9-osx-2.9.4.0-cocoa-py2.7/wxPython2.9-osx-cocoa-py2.7.pkg
|
|
||||||
hdiutil detach /Volumes/wxPython2.9-osx-2.9.4.0-cocoa-py2.7
|
|
||||||
#Check if wxPython is installed correctly
|
|
||||||
$PY -c 'import wx'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Failed to properly install wxPython."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Check for PyOpenGL
|
|
||||||
$PY -c 'import OpenGL'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
# Unpackage PyOpenGL
|
|
||||||
if [ ! -d "$PKGDIR/PyOpenGL-3.0.2/build/lib" ]; then
|
|
||||||
cd $PKGDIR
|
|
||||||
tar -xzf PyOpenGL-3.0.2.tar.gz
|
|
||||||
cd PyOpenGL-3.0.2
|
|
||||||
$PY setup.py build
|
|
||||||
fi
|
|
||||||
export PYTHONPATH="$PYTHONPATH:$PKGDIR/PyOpenGL-3.0.2/build/lib"
|
|
||||||
# Test if the installation was succesful
|
|
||||||
echo $PYTHONPATH
|
|
||||||
$PY -c 'import OpenGL'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Failed to properly use PyOpenGL."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Check for pyserial
|
|
||||||
$PY -c 'import serial'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
#Unpackage PySerial
|
|
||||||
if [ ! -d "$PKGDIR/pyserial-2.6/build/lib" ]; then
|
|
||||||
cd $PKGDIR
|
|
||||||
tar -xzf pyserial-2.6.tar.gz
|
|
||||||
cd pyserial-2.6
|
|
||||||
$PY setup.py build
|
|
||||||
fi
|
|
||||||
export PYTHONPATH="$PYTHONPATH:$PKGDIR/pyserial-2.6/build/lib"
|
|
||||||
|
|
||||||
#Test if we have pyserial now
|
|
||||||
$PY -c 'import serial'
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
displayMessage "Failed to properly use PySerial."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#All checks passed, start Cura
|
|
||||||
$PY "${RESDIR}Cura/cura.py" &
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
exit 0
|
|
|
@ -1 +0,0 @@
|
||||||
APPL????
|
|
130
setup.py
Normal file
130
setup.py
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
# coding=utf-8
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
if sys.platform.startswith('darwin'):
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
APP = ['Cura/cura.py']
|
||||||
|
DATA_FILES = ['Cura/images', 'Cura/LICENSE', 'Cura/stl.ico']
|
||||||
|
PLIST = {
|
||||||
|
u'CFBundleName': u'Cura',
|
||||||
|
u'CFBundleShortVersionString': u'12.11',
|
||||||
|
u'CFBundleVersion': u'12.11',
|
||||||
|
u'CFBundleIdentifier': u'com.ultimaker.Cura',
|
||||||
|
u'LSMinimumSystemVersion': u'10.6',
|
||||||
|
u'LSApplicationCategoryType': u'public.app-category.graphics-design',
|
||||||
|
u'CFBundleDocumentTypes': [
|
||||||
|
{
|
||||||
|
u'CFBundleTypeRole': u'Viewer',
|
||||||
|
u'LSItemContentTypes': [u'com.pleasantsoftware.uti.stl'],
|
||||||
|
u'LSHandlerRank': u'Alternate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u'CFBundleTypeRole': u'Viewer',
|
||||||
|
u'LSItemContentTypes': [u'org.khronos.collada.digital-asset-exchange'],
|
||||||
|
u'LSHandlerRank': u'Alternate'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u'CFBundleTypeName': u'Wavefront 3D Object',
|
||||||
|
u'CFBundleTypeExtensions': [u'obj'],
|
||||||
|
u'CFBundleTypeMIMETypes': [u'application/obj-3d'],
|
||||||
|
u'CFBundleTypeRole': u'Viewer',
|
||||||
|
u'LSHandlerRank': u'Alternate'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
u'UTImportedTypeDeclarations': [
|
||||||
|
{
|
||||||
|
u'UTTypeIdentifier': u'com.pleasantsoftware.uti.stl',
|
||||||
|
u'UTTypeConformsTo': [u'public.data'],
|
||||||
|
u'UTTypeDescription': u'Stereo Lithography 3D object',
|
||||||
|
u'UTTypeReferenceURL': u'http://en.wikipedia.org/wiki/STL_(file_format)',
|
||||||
|
u'UTTypeTagSpecification': {u'public.filename-extension': [u'stl'], u'public.mime-type': [u'text/plain']}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u'UTTypeIdentifier': u'org.khronos.collada.digital-asset-exchange',
|
||||||
|
u'UTTypeConformsTo': [u'public.xml', u'public.audiovisual-content'],
|
||||||
|
u'UTTypeDescription': u'Digital Asset Exchange (DAE)',
|
||||||
|
u'UTTypeTagSpecification': {u'public.filename-extension': [u'dae'], u'public.mime-type': [u'model/vnd.collada+xml']}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
OPTIONS = {
|
||||||
|
'argv_emulation': True,
|
||||||
|
'iconfile': 'Cura/Cura.icns',
|
||||||
|
'includes': ['objc', 'Foundation'],
|
||||||
|
'resources': DATA_FILES,
|
||||||
|
'optimize': '2',
|
||||||
|
'plist': PLIST,
|
||||||
|
'bdist_base': 'scripts/darwin/build',
|
||||||
|
'dist_dir': 'scripts/darwin/dist'
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="Cura",
|
||||||
|
app=APP,
|
||||||
|
data_files=DATA_FILES,
|
||||||
|
options={'py2app': OPTIONS},
|
||||||
|
setup_requires=['py2app']
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
import zipfile
|
||||||
|
try:
|
||||||
|
import cx_Freeze
|
||||||
|
except:
|
||||||
|
print "ERROR: You need cx-Freeze installed to build this package"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
freezeVersion = map(int, cx_Freeze.version.split('.'))
|
||||||
|
if freezeVersion[0] < 4 or freezeVersion[0] == 4 and freezeVersion[1] < 2:
|
||||||
|
print "ERROR: Your cx-Freeze version is too old to use with Cura."
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
sys.path.append(os.path.abspath('cura_sf'))
|
||||||
|
|
||||||
|
# Dependencies are automatically detected, but it might need fine tuning.
|
||||||
|
build_exe_options = {
|
||||||
|
"silent": True,
|
||||||
|
"packages": [
|
||||||
|
'encodings.utf_8',
|
||||||
|
"OpenGL", "OpenGL.arrays", "OpenGL.platform", "OpenGL.GLU",
|
||||||
|
], "excludes": [
|
||||||
|
'Tkinter', 'tcl', 'cura_sf', 'fabmetheus_utilities', 'skeinforge_application', 'numpy',
|
||||||
|
], "include_files": [
|
||||||
|
('images', 'images'),
|
||||||
|
], "build_exe": 'freeze_build'}
|
||||||
|
|
||||||
|
# GUI applications require a different base on Windows (the default is for a
|
||||||
|
# console application).
|
||||||
|
base = None
|
||||||
|
if sys.platform == "win32":
|
||||||
|
base = "Win32GUI"
|
||||||
|
|
||||||
|
cx_Freeze.setup( name = "Cura",
|
||||||
|
version = "RC5",
|
||||||
|
description = "Cura",
|
||||||
|
options = {"build_exe": build_exe_options},
|
||||||
|
executables = [cx_Freeze.Executable("cura.py", base=base)])
|
||||||
|
|
||||||
|
m = cx_Freeze.ModuleFinder(excludes=["gui"])
|
||||||
|
m.IncludeFile(os.path.abspath("cura.py"))
|
||||||
|
m.IncludeFile(os.path.abspath("cura_sf/skeinforge_application/skeinforge_plugins/profile_plugins/extrusion.py"))
|
||||||
|
m.IncludeFile(os.path.abspath("cura_sf/fabmetheus_utilities/fabmetheus_tools/interpret_plugins/stl.py"))
|
||||||
|
m.IncludeFile(os.path.abspath("cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py"))
|
||||||
|
for name in os.listdir("cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins"):
|
||||||
|
if name.endswith('.py'):
|
||||||
|
m.IncludeFile(os.path.abspath("cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/" + name))
|
||||||
|
m.ReportMissingModules()
|
||||||
|
cwd = os.path.abspath(".")
|
||||||
|
|
||||||
|
z = zipfile.ZipFile("freeze_build/cura_sf.zip", "w", zipfile.ZIP_DEFLATED)
|
||||||
|
for mod in m.modules:
|
||||||
|
if mod.file != None and mod.file.startswith(cwd):
|
||||||
|
if mod.file[len(cwd)+1:] == "cura.py":
|
||||||
|
z.write(mod.file[len(cwd)+1:], "__main__.py")
|
||||||
|
else:
|
||||||
|
z.write(mod.file[len(cwd)+1:])
|
||||||
|
z.write('cura_sf/fabmetheus_utilities/templates/layer_template.svg')
|
||||||
|
z.write('cura_sf/fabmetheus_utilities/version.txt')
|
||||||
|
z.write('__init__.py')
|
||||||
|
z.close()
|
Loading…
Reference in a new issue