chiark / gitweb /
Added copy button to project planner, and cleaned up project planner code a bit.
[cura.git] / Cura / gui / projectPlanner.py
index 2095042f9029fa885d037925467895368e1baced..5d4bd80b5bc1258e314b51068347089e652c1f36 100644 (file)
@@ -24,9 +24,108 @@ from util import util3d
 from util import stl\r
 from util import sliceRun\r
 \r
-class Action():\r
+class Action(object):\r
        pass\r
 \r
+class ProjectObject(stl.stlModel):\r
+       def __init__(self, filename):\r
+               super(ProjectObject, self).__init__()\r
+\r
+               self.load(filename)\r
+\r
+               self.filename = filename\r
+               self.scale = 1.0\r
+               self.rotate = 0.0\r
+               self.flipX = False\r
+               self.flipY = False\r
+               self.flipZ = False\r
+               self.swapXZ = False\r
+               self.swapYZ = False\r
+               self.extruder = 0\r
+               \r
+               self.modelDisplayList = None\r
+               self.modelDirty = False\r
+\r
+               self.origonalVertexes = list(self.vertexes)\r
+               for i in xrange(0, len(self.origonalVertexes)):\r
+                       self.origonalVertexes[i] = self.origonalVertexes[i].copy()\r
+               self.getMinimumZ()\r
+               \r
+               self.centerX = -self.getMinimum().x + 5\r
+               self.centerY = -self.getMinimum().y + 5\r
+               \r
+               self.updateModelTransform()\r
+\r
+               self.centerX = -self.getMinimum().x + 5\r
+               self.centerY = -self.getMinimum().y + 5\r
+\r
+       def updateModelTransform(self):\r
+               rotate = self.rotate / 180.0 * math.pi\r
+               scaleX = 1.0\r
+               scaleY = 1.0\r
+               scaleZ = 1.0\r
+               if self.flipX:\r
+                       scaleX = -scaleX\r
+               if self.flipY:\r
+                       scaleY = -scaleY\r
+               if self.flipZ:\r
+                       scaleZ = -scaleZ\r
+               swapXZ = self.swapXZ\r
+               swapYZ = self.swapYZ\r
+               mat00 = math.cos(rotate) * scaleX\r
+               mat01 =-math.sin(rotate) * scaleY\r
+               mat10 = math.sin(rotate) * scaleX\r
+               mat11 = math.cos(rotate) * scaleY\r
+               \r
+               for i in xrange(0, len(self.origonalVertexes)):\r
+                       x = self.origonalVertexes[i].x\r
+                       y = self.origonalVertexes[i].y\r
+                       z = self.origonalVertexes[i].z\r
+                       if swapXZ:\r
+                               x, z = z, x\r
+                       if swapYZ:\r
+                               y, z = z, y\r
+                       self.vertexes[i].x = x * mat00 + y * mat01\r
+                       self.vertexes[i].y = x * mat10 + y * mat11\r
+                       self.vertexes[i].z = z * scaleZ\r
+\r
+               for face in self.faces:\r
+                       v1 = face.v[0]\r
+                       v2 = face.v[1]\r
+                       v3 = face.v[2]\r
+                       face.normal = (v2 - v1).cross(v3 - v1)\r
+                       face.normal.normalize()\r
+\r
+               minZ = self.getMinimumZ()\r
+               minV = self.getMinimum()\r
+               maxV = self.getMaximum()\r
+               for v in self.vertexes:\r
+                       v.z -= minZ\r
+                       v.x -= minV.x + (maxV.x - minV.x) / 2\r
+                       v.y -= minV.y + (maxV.y - minV.y) / 2\r
+               self.getMinimumZ()\r
+               self.modelDirty = True\r
+       \r
+       def clone(self):\r
+               p = ProjectObject(self.filename)\r
+\r
+               p.centerX = self.centerX + 5\r
+               p.centerY = self.centerY + 5\r
+               \r
+               p.filename = self.filename\r
+               p.scale = self.scale\r
+               p.rotate = self.rotate\r
+               p.flipX = self.flipX\r
+               p.flipY = self.flipY\r
+               p.flipZ = self.flipZ\r
+               p.swapXZ = self.swapXZ\r
+               p.swapYZ = self.swapYZ\r
+               p.extruder = self.extruder\r
+               \r
+               p.updateModelTransform()\r
+               \r
+               return p\r
+\r
 class projectPlanner(wx.Frame):\r
        "Main user interface window"\r
        def __init__(self):\r
@@ -67,6 +166,7 @@ class projectPlanner(wx.Frame):
                toolbarUtil.NormalButton(self.toolbar2, self.OnRemModel, 'object-remove.png', 'Remove model')\r
                toolbarUtil.NormalButton(self.toolbar2, self.OnMoveUp, 'move-up.png', 'Move model up in print list')\r
                toolbarUtil.NormalButton(self.toolbar2, self.OnMoveDown, 'move-down.png', 'Move model down in print list')\r
+               toolbarUtil.NormalButton(self.toolbar2, self.OnCopy, 'copy.png', 'Make a copy of the current selected object')\r
                self.toolbar2.Realize()\r
                \r
                sizer = wx.GridBagSizer(2,2)\r
@@ -163,9 +263,7 @@ class projectPlanner(wx.Frame):
                        while cp.has_section('model_%d' % (i)):\r
                                section = 'model_%d' % (i)\r
                                \r
-                               item = stl.stlModel()\r
-                               item.filename = unicode(cp.get(section, 'filename'), "utf-8")\r
-                               self.loadModelFile(item)\r
+                               item = ProjectObject(unicode(cp.get(section, 'filename'), "utf-8"))\r
                                item.centerX = float(cp.get(section, 'centerX'))\r
                                item.centerY = float(cp.get(section, 'centerY'))\r
                                item.scale = float(cp.get(section, 'scale'))\r
@@ -177,7 +275,7 @@ class projectPlanner(wx.Frame):
                                item.swapYZ = cp.get(section, 'swapYZ') == 'True'\r
                                if cp.has_option(section, 'extruder'):\r
                                        item.extuder = int(cp.get(section, 'extruder'))-1\r
-                               self.updateModelTransform(item)\r
+                               item.updateModelTransform()\r
                                i += 1\r
                                \r
                                self.list.append(item)\r
@@ -185,6 +283,7 @@ class projectPlanner(wx.Frame):
                        \r
                        self.listbox.SetSelection(len(self.list)-1)\r
                        self.OnListSelect(None)\r
+                       self.preview.Refresh()\r
 \r
                dlg.Destroy()\r
 \r
@@ -217,29 +316,19 @@ class projectPlanner(wx.Frame):
                dlg.SetWildcard("STL files (*.stl)|*.stl;*.STL")\r
                if dlg.ShowModal() == wx.ID_OK:\r
                        for filename in dlg.GetPaths():\r
-                               item = stl.stlModel()\r
-                               item.filename=filename\r
+                               item = ProjectObject(filename)\r
                                profile.putPreference('lastFile', item.filename)\r
-                               if not(os.path.exists(item.filename)):\r
-                                       return\r
-                               self.loadModelFile(item)\r
                                self.list.append(item)\r
-                               self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])\r
-                               self.listbox.SetSelection(len(self.list)-1)\r
-                               self.OnListSelect(None)\r
+                               self.selection = item\r
+                               self._updateListbox()\r
+               self.preview.Refresh()\r
                dlg.Destroy()\r
        \r
        def OnRemModel(self, e):\r
                if self.selection == None:\r
                        return\r
                self.list.remove(self.selection)\r
-               i = self.listbox.GetSelection()\r
-               self.listbox.Delete(i)\r
-               if len(self.list) > i:\r
-                       self.listbox.SetSelection(i)\r
-               elif len(self.list) > 0:\r
-                       self.listbox.SetSelection(len(self.list) - 1)\r
-               self.selection = None\r
+               self._updateListbox()\r
                self.preview.Refresh()\r
        \r
        def OnMoveUp(self, e):\r
@@ -264,11 +353,29 @@ class projectPlanner(wx.Frame):
                self._updateListbox()\r
                self.preview.Refresh()\r
        \r
+       def OnCopy(self, e):\r
+               if self.selection == None:\r
+                       return\r
+               \r
+               item = self.selection.clone()\r
+               self.list.append(item)\r
+               self.selection = item\r
+               \r
+               self._updateListbox()\r
+               self.preview.Refresh()\r
+       \r
        def _updateListbox(self):\r
                self.listbox.Clear()\r
                for item in self.list:\r
                        self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])\r
-               self.listbox.SetSelection(self.list.index(self.selection))\r
+               if self.selection in self.list:\r
+                       self.listbox.SetSelection(self.list.index(self.selection))\r
+               elif len(self.list) > 0:\r
+                       self.selection = self.list[0]\r
+                       self.listbox.SetSelection(0)\r
+               else:\r
+                       self.selection = None\r
+                       self.listbox.SetSelection(-1)\r
 \r
        def OnAutoPlace(self, e):\r
                bestAllowedSize = int(self.machineSize.y)\r
@@ -368,32 +475,6 @@ class projectPlanner(wx.Frame):
                pspw.Centre()\r
                pspw.Show(True)\r
        \r
-       def loadModelFile(self, item):\r
-               item.load(item.filename)\r
-               item.origonalVertexes = list(item.vertexes)\r
-               for i in xrange(0, len(item.origonalVertexes)):\r
-                       item.origonalVertexes[i] = item.origonalVertexes[i].copy()\r
-               item.getMinimumZ()\r
-               \r
-               item.centerX = -item.getMinimum().x + 5\r
-               item.centerY = -item.getMinimum().y + 5\r
-               item.scale = 1.0\r
-               item.rotate = 0.0\r
-               item.flipX = False\r
-               item.flipY = False\r
-               item.flipZ = False\r
-               item.swapXZ = False\r
-               item.swapYZ = False\r
-               item.extruder = 0\r
-               \r
-               item.modelDisplayList = None\r
-               item.modelDirty = False\r
-               \r
-               self.updateModelTransform(item)\r
-\r
-               item.centerX = -item.getMinimum().x + 5\r
-               item.centerY = -item.getMinimum().y + 5\r
-\r
        def OnScaleChange(self, e):\r
                if self.selection == None:\r
                        return\r
@@ -407,7 +488,8 @@ class projectPlanner(wx.Frame):
                if self.selection == None:\r
                        return\r
                self.selection.rotate = float(self.rotateCtrl.GetValue())\r
-               self.updateModelTransform(self.selection)\r
+               self.selection.updateModelTransform()\r
+               self.preview.Refresh()\r
 \r
        def OnExtruderChange(self, e):\r
                if self.selection == None:\r
@@ -415,57 +497,6 @@ class projectPlanner(wx.Frame):
                self.selection.extruder = int(self.extruderCtrl.GetValue()) - 1\r
                self.preview.Refresh()\r
 \r
-       def updateModelTransform(self, item):\r
-               rotate = item.rotate / 180.0 * math.pi\r
-               scaleX = 1.0\r
-               scaleY = 1.0\r
-               scaleZ = 1.0\r
-               if item.flipX:\r
-                       scaleX = -scaleX\r
-               if item.flipY:\r
-                       scaleY = -scaleY\r
-               if item.flipZ:\r
-                       scaleZ = -scaleZ\r
-               swapXZ = item.swapXZ\r
-               swapYZ = item.swapYZ\r
-               mat00 = math.cos(rotate) * scaleX\r
-               mat01 =-math.sin(rotate) * scaleY\r
-               mat10 = math.sin(rotate) * scaleX\r
-               mat11 = math.cos(rotate) * scaleY\r
-               \r
-               for i in xrange(0, len(item.origonalVertexes)):\r
-                       x = item.origonalVertexes[i].x\r
-                       y = item.origonalVertexes[i].y\r
-                       z = item.origonalVertexes[i].z\r
-                       if swapXZ:\r
-                               x, z = z, x\r
-                       if swapYZ:\r
-                               y, z = z, y\r
-                       item.vertexes[i].x = x * mat00 + y * mat01\r
-                       item.vertexes[i].y = x * mat10 + y * mat11\r
-                       item.vertexes[i].z = z * scaleZ\r
-\r
-               for face in item.faces:\r
-                       v1 = face.v[0]\r
-                       v2 = face.v[1]\r
-                       v3 = face.v[2]\r
-                       face.normal = (v2 - v1).cross(v3 - v1)\r
-                       face.normal.normalize()\r
-\r
-               self.moveModel(item)\r
-       \r
-       def moveModel(self, item):\r
-               minZ = item.getMinimumZ()\r
-               min = item.getMinimum()\r
-               max = item.getMaximum()\r
-               for v in item.vertexes:\r
-                       v.z -= minZ\r
-                       v.x -= min.x + (max.x - min.x) / 2\r
-                       v.y -= min.y + (max.y - min.y) / 2\r
-               item.getMinimumZ()\r
-               item.modelDirty = True\r
-               self.preview.Refresh()\r
-\r
 class PreviewGLCanvas(glcanvas.GLCanvas):\r
        def __init__(self, parent):\r
                attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)\r