1 from __future__ import absolute_import
2 from __future__ import division
7 from wx import glcanvas
9 OpenGL.ERROR_CHECKING = False
10 from OpenGL.GL import *
12 from Cura.gui.util import opengl
14 class glGuiControl(object):
15 def __init__(self, parent, pos):
17 self._base = parent._base
19 self._size = (0,0, 1, 1)
20 self._parent.add(self)
22 def setSize(self, x, y, w, h):
23 self._size = (x, y, w, h)
31 def updateLayout(self):
35 for n in xrange(self._parent._glGuiControlList.index(self) + 1, len(self._parent._glGuiControlList)):
36 if self._parent._glGuiControlList[n].setFocus():
38 for n in xrange(0, self._parent._glGuiControlList.index(self)):
39 if self._parent._glGuiControlList[n].setFocus():
42 def focusPrevious(self):
43 for n in xrange(self._parent._glGuiControlList.index(self) -1, -1, -1):
44 if self._parent._glGuiControlList[n].setFocus():
46 for n in xrange(len(self._parent._glGuiControlList) - 1, self._parent._glGuiControlList.index(self), -1):
47 if self._parent._glGuiControlList[n].setFocus():
54 return self._base._focus == self
56 def OnMouseUp(self, x, y):
59 def OnKeyChar(self, key):
62 class glGuiContainer(glGuiControl):
63 def __init__(self, parent, pos):
64 self._glGuiControlList = []
65 glGuiLayoutButtons(self)
66 super(glGuiContainer, self).__init__(parent, pos)
69 self._glGuiControlList.append(ctrl)
72 def OnMouseDown(self, x, y):
73 for ctrl in self._glGuiControlList:
74 if ctrl.OnMouseDown(x, y):
78 def OnMouseUp(self, x, y):
79 for ctrl in self._glGuiControlList:
80 if ctrl.OnMouseUp(x, y):
84 def OnMouseMotion(self, x, y):
86 for ctrl in self._glGuiControlList:
87 if ctrl.OnMouseMotion(x, y):
92 for ctrl in self._glGuiControlList:
95 def updateLayout(self):
97 for ctrl in self._glGuiControlList:
100 class glGuiPanel(glcanvas.GLCanvas):
101 def __init__(self, parent):
102 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
103 glcanvas.GLCanvas.__init__(self, parent, style=wx.WANTS_CHARS, attribList = attribList)
106 self._container = None
107 self._container = glGuiContainer(self, (0,0))
109 self._context = glcanvas.GLContext(self)
110 self._glButtonsTexture = None
111 self._glRobotTexture = None
112 self._buttonSize = 64
114 wx.EVT_PAINT(self, self._OnGuiPaint)
115 wx.EVT_SIZE(self, self._OnSize)
116 wx.EVT_ERASE_BACKGROUND(self, self._OnEraseBackground)
117 wx.EVT_LEFT_DOWN(self, self._OnGuiMouseLeftDown)
118 wx.EVT_LEFT_UP(self, self._OnGuiMouseLeftUp)
119 wx.EVT_MOTION(self, self._OnGuiMouseMotion)
120 wx.EVT_CHAR(self, self.OnKeyChar)
121 wx.EVT_KILL_FOCUS(self, self.OnFocusLost)
123 def OnKeyChar(self, e):
124 if self._focus is not None:
125 self._focus.OnKeyChar(e.GetKeyCode())
128 def OnFocusLost(self, e):
132 def _OnGuiMouseLeftDown(self,e):
134 if self._container.OnMouseDown(e.GetX(), e.GetY()):
137 self.OnMouseLeftDown(e)
138 def _OnGuiMouseLeftUp(self, e):
139 if self._container.OnMouseUp(e.GetX(), e.GetY()):
142 self.OnMouseLeftUp(e)
144 def _OnGuiMouseMotion(self,e):
146 if not self._container.OnMouseMotion(e.GetX(), e.GetY()):
147 self.OnMouseMotion(e)
149 def _OnGuiPaint(self, e):
150 h = self.GetSize().GetHeight()
151 w = self.GetSize().GetWidth()
152 oldButtonSize = self._buttonSize
156 self._buttonSize = 32
158 self._buttonSize = 48
160 self._buttonSize = 64
162 self._buttonSize = 80
164 self._buttonSize = 96
165 if self._buttonSize != oldButtonSize:
166 self._container.updateLayout()
168 dc = wx.PaintDC(self)
169 self.SetCurrent(self._context)
176 if self._glButtonsTexture is None:
177 self._glButtonsTexture = opengl.loadGLTexture('glButtons.png')
178 self._glRobotTexture = opengl.loadGLTexture('UltimakerRobot.png')
180 glDisable(GL_DEPTH_TEST)
182 glDisable(GL_LIGHTING)
183 glColor4ub(255,255,255,255)
185 glMatrixMode(GL_PROJECTION)
187 size = self.GetSize()
188 glOrtho(0, size.GetWidth()-1, size.GetHeight()-1, 0, -1000.0, 1000.0)
189 glMatrixMode(GL_MODELVIEW)
192 self._container.draw()
193 glBindTexture(GL_TEXTURE_2D, self._glRobotTexture)
194 glEnable(GL_TEXTURE_2D)
197 glTranslate(size.GetWidth() - 8,size.GetHeight() - 16,0)
198 s = self._buttonSize * 1.4
210 glDisable(GL_TEXTURE_2D)
213 def _OnEraseBackground(self,event):
214 #Workaround for windows background redraw flicker.
218 self._container.setSize(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
219 self._container.updateLayout()
222 def OnMouseLeftDown(self,e):
224 def OnMouseLeftUp(self,e):
226 def OnMouseMotion(self, e):
228 def OnPaint(self, e):
232 if self._container is not None:
233 self._container.add(ctrl)
235 class glGuiLayoutButtons(object):
236 def __init__(self, parent):
237 self._parent = parent
238 self._parent._layout = self
241 bs = self._parent._base._buttonSize
242 x0, y0, w, h = self._parent.getSize()
244 for ctrl in self._parent._glGuiControlList:
247 x = w + pos[0] * gridSize - bs * 0.2
249 x = pos[0] * gridSize + bs * 0.2
251 y = h + pos[1] * gridSize - bs * 0.2
253 y = pos[1] * gridSize + bs * 0.2
254 ctrl.setSize(x, y, gridSize, gridSize)
256 def getLayoutSize(self):
257 _, _, w, h = self._parent.getSize()
260 class glGuiLayoutGrid(object):
261 def __init__(self, parent):
262 self._parent = parent
263 self._parent._layout = self
267 borderSize = self._parent._base._buttonSize * 0.2
268 x0, y0, w, h = self._parent.getSize()
273 for ctrl in self._parent._glGuiControlList:
275 w, h = ctrl.getMinSize()
279 widths[x] = max(widths[x], w)
283 heights[y] = max(heights[y], h)
284 for ctrl in self._parent._glGuiControlList:
288 for n in xrange(0, x):
292 for n in xrange(0, y):
296 ctrl.setSize(x1, y1, widths[x], heights[y])
297 self._size = sum(widths.values()) + borderSize * 2, sum(heights.values()) + borderSize * 2
299 def getLayoutSize(self):
302 class glButton(glGuiControl):
303 def __init__(self, parent, imageID, tooltip, pos, callback):
304 super(glButton, self).__init__(parent, pos)
305 self._tooltip = tooltip
306 self._parent = parent
307 self._imageID = imageID
308 self._callback = callback
309 self._selected = False
312 self._disabled = False
314 def setSelected(self, value):
315 self._selected = value
317 def setHidden(self, value):
320 def setDisabled(self, value):
321 self._disabled = value
323 def getSelected(self):
324 return self._selected
326 def getMinSize(self):
327 return self._base._buttonSize, self._base._buttonSize
329 def _getPixelPos(self):
330 x0, y0, w, h = self.getSize()
331 return x0 + w / 2, y0 + h / 2
337 cx = (self._imageID % 4) / 4
338 cy = int(self._imageID / 4) / 4
339 bs = self._base._buttonSize
340 pos = self._getPixelPos()
343 glTranslatef(pos[0], pos[1], 0)
344 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
345 glEnable(GL_TEXTURE_2D)
351 glScalef(bs * scale, bs * scale, bs * scale)
353 glColor4ub(128,128,128,128)
355 glColor4ub(255,255,255,255)
357 glTexCoord2f(cx+0.25, cy)
358 glVertex2f( 0.5,-0.5)
360 glVertex2f(-0.5,-0.5)
361 glTexCoord2f(cx, cy+0.25)
362 glVertex2f(-0.5, 0.5)
363 glTexCoord2f(cx+0.25, cy+0.25)
364 glVertex2f( 0.5, 0.5)
366 glDisable(GL_TEXTURE_2D)
368 glColor4ub(0,0,0,255)
369 glTranslatef(0, -0.55, 0)
370 opengl.glDrawStringCenter(self._tooltip)
373 def _checkHit(self, x, y):
374 if self._hidden or self._disabled:
376 bs = self.getMinSize()[0]
377 pos = self._getPixelPos()
378 return -bs * 0.5 <= x - pos[0] <= bs * 0.5 and -bs * 0.5 <= y - pos[1] <= bs * 0.5
380 def OnMouseMotion(self, x, y):
381 if self._checkHit(x, y):
387 def OnMouseDown(self, x, y):
388 if self._checkHit(x, y):
393 class glRadioButton(glButton):
394 def __init__(self, parent, imageID, tooltip, pos, group, callback):
395 super(glRadioButton, self).__init__(parent, imageID, tooltip, pos, self._onRadioSelect)
397 self._radioCallback = callback
398 self._group.append(self)
400 def setSelected(self, value):
401 self._selected = value
403 def _onRadioSelect(self):
404 self._base._focus = None
405 for ctrl in self._group:
407 ctrl.setSelected(False)
408 if self.getSelected():
409 self.setSelected(False)
411 self.setSelected(True)
412 self._radioCallback()
414 class glComboButton(glButton):
415 def __init__(self, parent, tooltip, imageIDs, tooltips, pos, callback):
416 super(glComboButton, self).__init__(parent, imageIDs[0], tooltip, pos, self._onComboOpenSelect)
417 self._imageIDs = imageIDs
418 self._tooltips = tooltips
419 self._comboCallback = callback
422 def _onComboOpenSelect(self):
423 self._base._focus = self
428 self._selected = self.hasFocus()
429 super(glComboButton, self).draw()
430 if not self._selected:
433 bs = self._base._buttonSize / 2
434 pos = self._getPixelPos()
437 glTranslatef(pos[0]+bs*0.5, pos[1] + bs*0.5, 0)
438 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
440 for n in xrange(0, len(self._imageIDs)):
441 cx = (self._imageIDs[n] % 4) / 4
442 cy = int(self._imageIDs[n] / 4) / 4
443 glEnable(GL_TEXTURE_2D)
444 glTranslatef(0, 1, 0)
446 glColor4ub(128,128,128,128)
448 glColor4ub(255,255,255,255)
450 glTexCoord2f(cx+0.25, cy)
451 glVertex2f( 0.5,-0.5)
453 glVertex2f(-0.5,-0.5)
454 glTexCoord2f(cx, cy+0.25)
455 glVertex2f(-0.5, 0.5)
456 glTexCoord2f(cx+0.25, cy+0.25)
457 glVertex2f( 0.5, 0.5)
459 glDisable(GL_TEXTURE_2D)
462 glColor4ub(0,0,0,255)
463 glTranslatef(-0.55, 0.1, 0)
464 opengl.glDrawStringRight(self._tooltips[n])
469 return self._selection
471 def setValue(self, value):
472 self._selection = value
473 self._comboCallback()
475 def OnMouseDown(self, x, y):
476 if self._hidden or self._disabled:
479 bs = self._base._buttonSize / 2
480 pos = self._getPixelPos()
481 if 0 <= x - pos[0] <= bs and 0 <= y - pos[1] - bs <= bs * len(self._imageIDs):
482 self._selection = int((y - pos[1] - bs) / bs)
483 self._imageID = self._imageIDs[self._selection]
484 self._base._focus = None
485 self._comboCallback()
487 return super(glComboButton, self).OnMouseDown(x, y)
489 class glFrame(glGuiContainer):
490 def __init__(self, parent, pos):
491 super(glFrame, self).__init__(parent, pos)
492 self._selected = False
496 def setSelected(self, value):
497 self._selected = value
499 def setHidden(self, value):
502 def getSelected(self):
503 return self._selected
505 def getMinSize(self):
506 return self._base._buttonSize, self._base._buttonSize
508 def _getPixelPos(self):
509 x0, y0, w, h = self.getSize()
516 bs = self._parent._buttonSize
517 pos = self._getPixelPos()
520 glTranslatef(pos[0], pos[1], 0)
521 glDisable(GL_TEXTURE_2D)
523 size = self._layout.getLayoutSize()
524 glColor4ub(60,60,60,255)
527 glVertex2f( size[0], 0)
531 glVertex2f( 0, size[1])
533 glVertex2f( size[0], size[1])
535 glDisable(GL_TEXTURE_2D)
537 #Draw the controls on the frame
538 super(glFrame, self).draw()
540 def _checkHit(self, x, y):
543 pos = self._getPixelPos()
544 w, h = self._layout.getLayoutSize()
545 return 0 <= x - pos[0] <= w and 0 <= y - pos[1] <= h
547 def OnMouseMotion(self, x, y):
548 super(glFrame, self).OnMouseMotion(x, y)
549 if self._checkHit(x, y):
555 def OnMouseDown(self, x, y):
556 if self._checkHit(x, y):
557 super(glFrame, self).OnMouseDown(x, y)
561 class glLabel(glGuiControl):
562 def __init__(self, parent, label, pos):
564 super(glLabel, self).__init__(parent, pos)
566 def getMinSize(self):
567 w, h = opengl.glGetStringSize(self._label)
570 def _getPixelPos(self):
571 x0, y0, w, h = self.getSize()
575 x, y, w, h = self.getSize()
578 glTranslatef(x, y, 0)
580 glColor4ub(255,255,255,128)
592 glTranslate(5, h - 5, 0)
593 glColor4ub(0,0,0,255)
594 opengl.glDrawStringLeft(self._label)
597 def _checkHit(self, x, y):
600 def OnMouseMotion(self, x, y):
603 def OnMouseDown(self, x, y):
606 class glNumberCtrl(glGuiControl):
607 def __init__(self, parent, value, pos, callback):
608 self._callback = callback
609 self._value = str(value)
612 self._inCallback = False
613 super(glNumberCtrl, self).__init__(parent, pos)
615 def setValue(self, value):
618 self._value = str(value)
620 def getMinSize(self):
621 w, h = opengl.glGetStringSize("VALUES")
624 def _getPixelPos(self):
625 x0, y0, w, h = self.getSize()
629 x, y, w, h = self.getSize()
632 glTranslatef(x, y, 0)
635 glColor4ub(255,255,255,255)
637 glColor4ub(255,255,255,192)
649 glTranslate(5, h - 5, 0)
650 glColor4ub(0,0,0,255)
651 opengl.glDrawStringLeft(self._value)
653 glTranslate(opengl.glGetStringSize(self._value[0:self._selectPos])[0] - 2, -1, 0)
654 opengl.glDrawStringLeft('|')
657 def _checkHit(self, x, y):
658 x1, y1, w, h = self.getSize()
659 return 0 <= x - x1 <= w and 0 <= y - y1 <= h
661 def OnMouseMotion(self, x, y):
664 def OnMouseDown(self, x, y):
665 if self._checkHit(x, y):
670 def OnKeyChar(self, c):
671 self._inCallback = True
674 self._selectPos = max(0, self._selectPos)
675 if c == wx.WXK_RIGHT:
677 self._selectPos = min(self._selectPos, len(self._value))
680 value = float(self._value)
685 self._value = str(value)
686 self._callback(self._value)
689 value = float(self._value)
695 self._value = str(value)
696 self._callback(self._value)
697 if c == wx.WXK_BACK and self._selectPos > 0:
698 self._value = self._value[0:self._selectPos - 1] + self._value[self._selectPos:]
700 self._callback(self._value)
701 if c == wx.WXK_DELETE:
702 self._value = self._value[0:self._selectPos] + self._value[self._selectPos + 1:]
703 self._callback(self._value)
705 if wx.GetKeyState(wx.WXK_SHIFT):
709 if (ord('0') <= c <= ord('9') or c == ord('.')) and len(self._value) < self._maxLen:
710 self._value = self._value[0:self._selectPos] + chr(c) + self._value[self._selectPos:]
712 self._callback(self._value)
713 self._inCallback = False
716 self._base._focus = self
717 self._selectPos = len(self._value)
720 class glCheckbox(glGuiControl):
721 def __init__(self, parent, value, pos, callback):
722 self._callback = callback
726 self._inCallback = False
727 super(glCheckbox, self).__init__(parent, pos)
729 def setValue(self, value):
732 self._value = str(value)
737 def getMinSize(self):
740 def _getPixelPos(self):
741 x0, y0, w, h = self.getSize()
745 x, y, w, h = self.getSize()
748 glTranslatef(x, y, 0)
751 glColor4ub(0,255,0,255)
753 glColor4ub(255,0,0,255)
767 def _checkHit(self, x, y):
768 x1, y1, w, h = self.getSize()
769 return 0 <= x - x1 <= w and 0 <= y - y1 <= h
771 def OnMouseMotion(self, x, y):
774 def OnMouseDown(self, x, y):
775 if self._checkHit(x, y):
776 self._value = not self._value
780 class glSlider(glGuiControl):
781 def __init__(self, parent, value, minValue, maxValue, pos, callback):
782 super(glSlider, self).__init__(parent, pos)
783 self._callback = callback
787 self._minValue = minValue
788 self._maxValue = maxValue
790 def setValue(self, value):
792 self._value = max(self._minValue, self._value)
793 self._value = min(self._maxValue, self._value)
798 def setRange(self, minValue, maxValue):
799 self._minValue = minValue
800 self._maxValue = maxValue
801 self._value = max(minValue, self._value)
802 self._value = min(maxValue, self._value)
804 def getMinValue(self):
805 return self._minValue
807 def getMaxValue(self):
808 return self._maxValue
810 def setHidden(self, value):
813 def getMinSize(self):
814 return self._base._buttonSize * 0.2, self._base._buttonSize * 4
816 def _getPixelPos(self):
817 x0, y0, w, h = self.getSize()
818 minSize = self.getMinSize()
819 return x0 + w / 2 - minSize[0] / 2, y0 + h / 2 - minSize[1] / 2
825 w, h = self.getMinSize()
826 pos = self._getPixelPos()
829 glTranslatef(pos[0], pos[1], 0)
830 glDisable(GL_TEXTURE_2D)
832 glColor4ub(60,60,60,255)
834 glColor4ub(60,60,60,192)
836 glVertex2f( w/2,-h/2)
837 glVertex2f(-w/2,-h/2)
838 glVertex2f(-w/2, h/2)
839 glVertex2f( w/2, h/2)
842 glTranslate(0.0,scrollLength/2,0)
844 glColor4ub(0,0,0,255)
846 glTranslate(-w/2,opengl.glGetStringSize(str(self._minValue))[1]/2,0)
847 opengl.glDrawStringRight(str(self._minValue))
848 glTranslate(0,-scrollLength,0)
849 opengl.glDrawStringRight(str(self._maxValue))
850 glTranslate(w,scrollLength-scrollLength*((self._value-self._minValue)/(self._maxValue-self._minValue)),0)
851 opengl.glDrawStringLeft(str(self._value))
853 glColor4ub(255,255,255,240)
854 glTranslate(0.0,-scrollLength*((self._value-self._minValue)/(self._maxValue-self._minValue)),0)
856 glVertex2f( w/2,-w/2)
857 glVertex2f(-w/2,-w/2)
858 glVertex2f(-w/2, w/2)
859 glVertex2f( w/2, w/2)
863 def _checkHit(self, x, y):
866 pos = self._getPixelPos()
867 w, h = self.getMinSize()
868 return -w/2 <= x - pos[0] <= w/2 and -h/2 <= y - pos[1] <= h/2
871 self._base._focus = self
874 def OnMouseMotion(self, x, y):
876 w, h = self.getMinSize()
878 pos = self._getPixelPos()
879 self.setValue(int(self._minValue + (self._maxValue - self._minValue) * -(y - pos[1] - scrollLength/2) / scrollLength))
882 if self._checkHit(x, y):
888 def OnMouseDown(self, x, y):
889 if self._checkHit(x, y):
891 self.OnMouseMotion(x, y)
895 def OnMouseUp(self, x, y):
897 self._base._focus = None