diff --git a/Cura/cura.py b/Cura/cura.py index b65ac355ae..14dc53b1e5 100644 --- a/Cura/cura.py +++ b/Cura/cura.py @@ -46,10 +46,15 @@ __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agp def main(): parser = OptionParser(usage="usage: %prog [options] .stl") parser.add_option("-p", "--profile", action="store", type="string", dest="profile", help="Use these profile settings instead of loading current_profile.ini") + parser.add_option("-P", "--project", action="store_true", dest="openprojectplanner", help="Open the project planner") parser.add_option("-r", "--print", action="store", type="string", dest="printfile", help="Open the printing interface, instead of the normal cura interface.") (options, args) = parser.parse_args() if options.profile != None: profile.loadGlobalProfileFromString(options.profile) + if options.openprojectplanner != None: + from gui import projectPlanner + projectPlanner.main() + return if options.printfile != None: from gui import printWindow printWindow.startPrintInterface(options.printfile) diff --git a/Cura/cura_sf/fabmetheus_utilities/settings.py b/Cura/cura_sf/fabmetheus_utilities/settings.py index f95c2d28a4..4f53c63a62 100644 --- a/Cura/cura_sf/fabmetheus_utilities/settings.py +++ b/Cura/cura_sf/fabmetheus_utilities/settings.py @@ -139,7 +139,7 @@ def getProfileInformation(): 'Infill_Width': storedSettingFloat("nozzle_size"), 'Loop_Order_Choice': DEFSET, 'Overlap_Removal_Width_over_Perimeter_Width_ratio': DEFSET, - 'Turn_Extruder_Heater_Off_at_Shut_Down': DEFSET, + 'Turn_Extruder_Heater_Off_at_Shut_Down': "False", 'Volume_Fraction_ratio': DEFSET, },'fill': { 'Activate_Fill': "True", @@ -379,7 +379,7 @@ def getProfileInformation(): 'Retraction_Distance_millimeters': storedSettingFloat('retraction_amount'), 'Restart_Extra_Distance_millimeters': storedSettingFloat('retraction_extra'), },'alteration': { - 'Activate_Alteration': "True", + 'Activate_Alteration': storedSetting('add_start_end_gcode'), 'Name_of_End_File': "end.gcode", 'Name_of_Start_File': "start.gcode", 'Remove_Redundant_Mcode': "True", @@ -398,7 +398,7 @@ def getProfileInformation(): 'gcode_step': DEFSET, 'gcode_time_segment': DEFSET, 'gcode_small': DEFSET, - 'File_Extension': DEFSET, + 'File_Extension': storedSetting('gcode_extension'), 'Name_of_Replace_File': DEFSET, 'Save_Penultimate_Gcode': "False", } diff --git a/Cura/gui/opengl.py b/Cura/gui/opengl.py index 54d0008d28..83bbc2a4d9 100644 --- a/Cura/gui/opengl.py +++ b/Cura/gui/opengl.py @@ -77,6 +77,31 @@ def DrawMachine(machineSize): glVertex3f(0, machineSize.y, machineSize.z) glEnd() +def DrawBox(vMin, vMax): + glBegin(GL_LINE_LOOP) + glVertex3f(vMin.x, vMin.y, vMin.z) + glVertex3f(vMax.x, vMin.y, vMin.z) + glVertex3f(vMax.x, vMax.y, vMin.z) + glVertex3f(vMin.x, vMax.y, vMin.z) + glEnd() + + glBegin(GL_LINE_LOOP) + glVertex3f(vMin.x, vMin.y, vMax.z) + glVertex3f(vMax.x, vMin.y, vMax.z) + glVertex3f(vMax.x, vMax.y, vMax.z) + glVertex3f(vMin.x, vMax.y, vMax.z) + glEnd() + glBegin(GL_LINES) + glVertex3f(vMin.x, vMin.y, vMin.z) + glVertex3f(vMin.x, vMin.y, vMax.z) + glVertex3f(vMax.x, vMin.y, vMin.z) + glVertex3f(vMax.x, vMin.y, vMax.z) + glVertex3f(vMax.x, vMax.y, vMin.z) + glVertex3f(vMax.x, vMax.y, vMax.z) + glVertex3f(vMin.x, vMax.y, vMin.z) + glVertex3f(vMin.x, vMax.y, vMax.z) + glEnd() + def DrawSTL(mesh): for face in mesh.faces: glBegin(GL_TRIANGLES) diff --git a/Cura/gui/preview3d.py b/Cura/gui/preview3d.py index 14ef6b6061..92a66491a5 100644 --- a/Cura/gui/preview3d.py +++ b/Cura/gui/preview3d.py @@ -8,6 +8,7 @@ import time import os from wx import glcanvas +from wx.lib import buttons import wx try: import OpenGL @@ -26,6 +27,85 @@ from util import gcodeInterpreter from util import stl from util import util3d +class ToggleButton(buttons.GenBitmapToggleButton): + def __init__(self, parent, popupParent, profileSetting, bitmapFilenameOn, bitmapFilenameOff, + helpText='', id=-1, size=(20,20)): + self.bitmapOn = wx.Bitmap(os.path.join(os.path.split(__file__)[0], "../images", bitmapFilenameOn)) + self.bitmapOff = wx.Bitmap(os.path.join(os.path.split(__file__)[0], "../images", bitmapFilenameOff)) + + buttons.GenBitmapToggleButton.__init__(self, parent, id, self.bitmapOff, size=size) + + self.popupParent = popupParent + self.profileSetting = profileSetting + self.helpText = helpText + + self.bezelWidth = 1 + self.useFocusInd = False + + if self.profileSetting != '': + self.SetValue(profile.getProfileSetting(self.profileSetting) == 'True') + self.Bind(wx.EVT_BUTTON, self.OnButtonProfile) + else: + self.Bind(wx.EVT_BUTTON, self.OnButton) + + self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter) + self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave) + + def SetBitmap(self, bool): + if bool: + buttons.GenBitmapToggleButton.SetBitmapLabel(self, self.bitmapOn, False) + else: + buttons.GenBitmapToggleButton.SetBitmapLabel(self, self.bitmapOff, False) + + def SetValue(self, bool): + self.SetBitmap(bool) + buttons.GenBitmapToggleButton.SetValue(self, bool) + + def OnButton(self, event): + self.SetBitmap(buttons.GenBitmapToggleButton.GetValue(self)) + event.Skip() + + def OnButtonProfile(self, event): + if buttons.GenBitmapToggleButton.GetValue(self): + self.SetBitmap(True) + profile.putProfileSetting(self.profileSetting, 'True') + else: + self.SetBitmap(False) + profile.putProfileSetting(self.profileSetting, 'False') + self.popupParent.updateModelTransform() + event.Skip() + + def OnMouseEnter(self, event): + self.popupParent.OnPopupDisplay(event) + event.Skip() + + def OnMouseLeave(self, event): + self.popupParent.OnPopupHide(event) + event.Skip() + +class NormalButton(buttons.GenBitmapButton): + def __init__(self, parent, popupParent, bitmapFilename, + helpText='', id=-1, size=(20,20)): + self.bitmap = wx.Bitmap(os.path.join(os.path.split(__file__)[0], "../images", bitmapFilename)) + buttons.GenBitmapButton.__init__(self, parent, id, self.bitmap, size=size) + + self.popupParent = popupParent + self.helpText = helpText + + self.bezelWidth = 1 + self.useFocusInd = False + + self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter) + self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave) + + def OnMouseEnter(self, event): + self.popupParent.OnPopupDisplay(event) + event.Skip() + + def OnMouseLeave(self, event): + self.popupParent.OnPopupHide(event) + event.Skip() + class previewPanel(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent,-1) @@ -33,6 +113,15 @@ class previewPanel(wx.Panel): self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW)) self.SetMinSize((440,320)) + # Create popup window + self.popup = wx.PopupWindow(self, flags=wx.BORDER_SIMPLE) + self.popup.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK)) + self.popup.text = wx.StaticText(self.popup, -1, '') + self.popup.sizer = wx.BoxSizer() + self.popup.sizer.Add(self.popup.text, flag=wx.EXPAND|wx.ALL, border=1) + self.popup.SetSizer(self.popup.sizer) + self.popupOwner = None + self.glCanvas = PreviewGLCanvas(self) self.init = 0 self.triangleMesh = None @@ -62,67 +151,69 @@ class previewPanel(wx.Panel): self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS) self.toolbar.AddControl(self.layerSpin) self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin) + + self.scaleMax = NormalButton(self.toolbar, self, 'object-max-size.png', 'Scale object to fix machine size') + self.scaleMax.Bind(wx.EVT_BUTTON, self.OnScaleMax) + self.toolbar.AddControl(self.scaleMax) - self.toolbar2 = wx.ToolBar( self, -1 ) + self.toolbar2 = wx.ToolBar( self, -1, style = wx.TB_HORIZONTAL | wx.NO_BORDER ) self.toolbar2.SetToolBitmapSize( ( 21, 21 ) ) - self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Flip')) - self.flipX = wx.CheckBox(self.toolbar2, -1, "X") - self.flipX.SetValue(profile.getProfileSetting('flip_x') == 'True') - self.toolbar2.AddControl(self.flipX) - self.Bind(wx.EVT_CHECKBOX, self.OnFlipXClick, self.flipX) - self.flipY = wx.CheckBox(self.toolbar2, -1, "Y") - self.flipY.SetValue(profile.getProfileSetting('flip_y') == 'True') - self.toolbar2.AddControl(self.flipY) - self.Bind(wx.EVT_CHECKBOX, self.OnFlipYClick, self.flipY) - self.flipZ = wx.CheckBox(self.toolbar2, -1, "Z") - self.flipZ.SetValue(profile.getProfileSetting('flip_z') == 'True') - self.toolbar2.AddControl(self.flipZ) - self.Bind(wx.EVT_CHECKBOX, self.OnFlipZClick, self.flipZ) +# Mirror + self.mirrorX = ToggleButton(self.toolbar2, self, 'flip_x', 'object-mirror-x-on.png', 'object-mirror-x-off.png', 'Mirror X') + self.toolbar2.AddControl(self.mirrorX) - self.swapXZ = wx.CheckBox(self.toolbar2, -1, "XZ") - self.swapXZ.SetValue(profile.getProfileSetting('swap_xz') == 'True') + self.mirrorY = ToggleButton(self.toolbar2, self, 'flip_y', 'object-mirror-y-on.png', 'object-mirror-y-off.png', 'Mirror Y') + self.toolbar2.AddControl(self.mirrorY) + + self.mirrorZ = ToggleButton(self.toolbar2, self, 'flip_z', 'object-mirror-z-on.png', 'object-mirror-z-off.png', 'Mirror Z') + self.toolbar2.AddControl(self.mirrorZ) + + self.toolbar2.AddSeparator() + +# Swap + self.swapXZ = ToggleButton(self.toolbar2, self, 'swap_xz', 'object-swap-xz-on.png', 'object-swap-xz-off.png', 'Swap XZ') self.toolbar2.AddControl(self.swapXZ) - self.Bind(wx.EVT_CHECKBOX, self.OnSwapXZClick, self.swapXZ) - self.swapYZ = wx.CheckBox(self.toolbar2, -1, "YZ") - self.swapYZ.SetValue(profile.getProfileSetting('swap_yz') == 'True') + self.swapYZ = ToggleButton(self.toolbar2, self, 'swap_yz', 'object-swap-yz-on.png', 'object-swap-yz-off.png', 'Swap YZ') self.toolbar2.AddControl(self.swapYZ) - self.Bind(wx.EVT_CHECKBOX, self.OnSwapYZClick, self.swapYZ) - self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount()) + self.toolbar2.AddSeparator() + +# Scale self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Scale')) self.scale = wx.TextCtrl(self.toolbar2, -1, profile.getProfileSetting('model_scale'), size=(21*2,21)) self.toolbar2.AddControl(self.scale) self.Bind(wx.EVT_TEXT, self.OnScale, self.scale) - self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount()) - self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Copy')) - self.mulXsub = wx.Button(self.toolbar2, -1, '-', size=(21,21)) - self.toolbar2.AddControl(self.mulXsub) - self.Bind(wx.EVT_BUTTON, self.OnMulXSubClick, self.mulXsub) - self.mulXadd = wx.Button(self.toolbar2, -1, '+', size=(21,21)) - self.toolbar2.AddControl(self.mulXadd) - self.Bind(wx.EVT_BUTTON, self.OnMulXAddClick, self.mulXadd) + self.toolbar2.AddSeparator() - self.mulYsub = wx.Button(self.toolbar2, -1, '-', size=(21,21)) - self.toolbar2.AddControl(self.mulYsub) - self.Bind(wx.EVT_BUTTON, self.OnMulYSubClick, self.mulYsub) - self.mulYadd = wx.Button(self.toolbar2, -1, '+', size=(21,21)) +# Multiply + self.mulXadd = NormalButton(self.toolbar2, self, 'object-mul-x-add.png', 'Increase number of models on X axis') + self.mulXadd.Bind(wx.EVT_BUTTON, self.OnMulXAddClick) + self.toolbar2.AddControl(self.mulXadd) + + self.mulXsub = NormalButton(self.toolbar2, self, 'object-mul-x-sub.png', 'Decrease number of models on X axis') + self.mulXsub.Bind(wx.EVT_BUTTON, self.OnMulXSubClick) + self.toolbar2.AddControl(self.mulXsub) + + self.mulYadd = NormalButton(self.toolbar2, self, 'object-mul-y-add.png', 'Increase number of models on Y axis') + self.mulYadd.Bind(wx.EVT_BUTTON, self.OnMulYAddClick) self.toolbar2.AddControl(self.mulYadd) - self.Bind(wx.EVT_BUTTON, self.OnMulYAddClick, self.mulYadd) - - self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount()) + + self.mulYsub = NormalButton(self.toolbar2, self, 'object-mul-y-sub.png', 'Decrease number of models on Y axis') + self.mulYsub.Bind(wx.EVT_BUTTON, self.OnMulYSubClick) + self.toolbar2.AddControl(self.mulYsub) + + self.toolbar2.AddSeparator() + +# Rotate self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Rot')) self.rotate = wx.SpinCtrl(self.toolbar2, -1, profile.getProfileSetting('model_rotate_base'), size=(21*3,21), style=wx.SP_WRAP|wx.SP_ARROW_KEYS) self.rotate.SetRange(0, 360) self.toolbar2.AddControl(self.rotate) self.Bind(wx.EVT_SPINCTRL, self.OnRotate, self.rotate) - self.scaleMax = wx.Button(self.toolbar, -1, 'Max size', size=(21*3.5,21)) - self.toolbar.AddControl(self.scaleMax) - self.Bind(wx.EVT_BUTTON, self.OnScaleMax, self.scaleMax) - self.toolbar2.Realize() self.updateToolbar() @@ -132,25 +223,26 @@ class previewPanel(wx.Panel): sizer.Add(self.toolbar2, 0, flag=wx.EXPAND|wx.BOTTOM|wx.LEFT|wx.RIGHT, border=1) self.SetSizer(sizer) - def OnFlipXClick(self, e): - profile.putProfileSetting('flip_x', str(self.flipX.GetValue())) - self.updateModelTransform() - - def OnFlipYClick(self, e): - profile.putProfileSetting('flip_y', str(self.flipY.GetValue())) - self.updateModelTransform() - - def OnFlipZClick(self, e): - profile.putProfileSetting('flip_z', str(self.flipZ.GetValue())) - self.updateModelTransform() - - def OnSwapXZClick(self, e): - profile.putProfileSetting('swap_xz', str(self.swapXZ.GetValue())) - self.updateModelTransform() - - def OnSwapYZClick(self, e): - profile.putProfileSetting('swap_yz', str(self.swapYZ.GetValue())) - self.updateModelTransform() + def OnPopupDisplay(self, e): + self.UpdatePopup(e.GetEventObject()) + self.popup.Show(True) + + def OnPopupHide(self, e): + if self.popupOwner == e.GetEventObject(): + self.popup.Show(False) + + def UpdatePopup(self, control): + self.popupOwner = control + self.popup.text.SetLabel(control.helpText) + self.popup.text.Wrap(350) + self.popup.Fit(); + if os.name == 'darwin': + x, y = self.ClientToScreenXY(0, 0) + sx, sy = self.GetClientSizeTuple() + else: + x, y = control.ClientToScreenXY(0, 0) + sx, sy = control.GetSizeTuple() + self.popup.SetPosition((x, y+sy)) def OnMulXAddClick(self, e): profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))+1))) diff --git a/Cura/images/object-max-size.png b/Cura/images/object-max-size.png new file mode 100644 index 0000000000..c836294072 Binary files /dev/null and b/Cura/images/object-max-size.png differ diff --git a/Cura/images/object-mirror-x-off.png b/Cura/images/object-mirror-x-off.png new file mode 100644 index 0000000000..302b2b2ca5 Binary files /dev/null and b/Cura/images/object-mirror-x-off.png differ diff --git a/Cura/images/object-mirror-x-on.png b/Cura/images/object-mirror-x-on.png new file mode 100644 index 0000000000..4d07b34954 Binary files /dev/null and b/Cura/images/object-mirror-x-on.png differ diff --git a/Cura/images/object-mirror-y-off.png b/Cura/images/object-mirror-y-off.png new file mode 100644 index 0000000000..5f72a439db Binary files /dev/null and b/Cura/images/object-mirror-y-off.png differ diff --git a/Cura/images/object-mirror-y-on.png b/Cura/images/object-mirror-y-on.png new file mode 100644 index 0000000000..f7dfc62231 Binary files /dev/null and b/Cura/images/object-mirror-y-on.png differ diff --git a/Cura/images/object-mirror-z-off.png b/Cura/images/object-mirror-z-off.png new file mode 100644 index 0000000000..801fa983c0 Binary files /dev/null and b/Cura/images/object-mirror-z-off.png differ diff --git a/Cura/images/object-mirror-z-on.png b/Cura/images/object-mirror-z-on.png new file mode 100644 index 0000000000..c599670cd8 Binary files /dev/null and b/Cura/images/object-mirror-z-on.png differ diff --git a/Cura/images/object-mul-x-add.png b/Cura/images/object-mul-x-add.png new file mode 100644 index 0000000000..dda2ef3048 Binary files /dev/null and b/Cura/images/object-mul-x-add.png differ diff --git a/Cura/images/object-mul-x-sub.png b/Cura/images/object-mul-x-sub.png new file mode 100644 index 0000000000..dc8345d122 Binary files /dev/null and b/Cura/images/object-mul-x-sub.png differ diff --git a/Cura/images/object-mul-y-add.png b/Cura/images/object-mul-y-add.png new file mode 100644 index 0000000000..b9d4ca4bc4 Binary files /dev/null and b/Cura/images/object-mul-y-add.png differ diff --git a/Cura/images/object-mul-y-sub.png b/Cura/images/object-mul-y-sub.png new file mode 100644 index 0000000000..e5c155b0cc Binary files /dev/null and b/Cura/images/object-mul-y-sub.png differ diff --git a/Cura/images/object-swap-xz-off.png b/Cura/images/object-swap-xz-off.png new file mode 100644 index 0000000000..830570e6b5 Binary files /dev/null and b/Cura/images/object-swap-xz-off.png differ diff --git a/Cura/images/object-swap-xz-on.png b/Cura/images/object-swap-xz-on.png new file mode 100644 index 0000000000..c594954952 Binary files /dev/null and b/Cura/images/object-swap-xz-on.png differ diff --git a/Cura/images/object-swap-yz-off.png b/Cura/images/object-swap-yz-off.png new file mode 100644 index 0000000000..19abb4288e Binary files /dev/null and b/Cura/images/object-swap-yz-off.png differ diff --git a/Cura/images/object-swap-yz-on.png b/Cura/images/object-swap-yz-on.png new file mode 100644 index 0000000000..bb60079c3d Binary files /dev/null and b/Cura/images/object-swap-yz-on.png differ diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 08e617776d..dfc2afda05 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -64,8 +64,10 @@ profileDefaultSettings = { 'bridge_material_amount': '100', 'raft_margin': '5', 'raft_base_material_amount': '100', - 'raft_interface_material_amount': '100', + 'raft_interface_material_amount': '100', 'bottom_thickness': '0.3', + 'add_start_end_gcode': 'True', + 'gcode_extension': 'gcode', } preferencesDefaultSettings = { 'wizardDone': 'False',