chiark / gitweb /
Update on the OpenGL gui, now uses layout managers, and started work on a frame for...
[cura.git] / Cura / gui / util / openglGui.py
1 from __future__ import absolute_import
2 from __future__ import division
3
4 import wx
5 from wx import glcanvas
6 import OpenGL
7 OpenGL.ERROR_CHECKING = False
8 from OpenGL.GL import *
9
10 from Cura.gui.util import opengl
11
12 class glGuiControl(object):
13         def __init__(self, parent, pos):
14                 self._parent = parent
15                 self._base = parent._base
16                 self._pos = pos
17                 self._size = (0,0, 1, 1)
18                 self._parent.add(self)
19
20         def setSize(self, x, y, w, h):
21                 self._size = (x, y, w, h)
22
23         def getSize(self):
24                 return self._size
25
26         def getMinSize(self):
27                 return 1, 1
28
29         def updateLayout(self):
30                 pass
31
32 class glGuiContainer(glGuiControl):
33         def __init__(self, parent, pos):
34                 self._glGuiControlList = []
35                 glGuiLayoutButtons(self)
36                 super(glGuiContainer, self).__init__(parent, pos)
37
38         def add(self, ctrl):
39                 self._glGuiControlList.append(ctrl)
40                 self.updateLayout()
41
42         def OnMouseDown(self, x, y):
43                 for ctrl in self._glGuiControlList:
44                         if ctrl.OnMouseDown(x, y):
45                                 return
46
47         def OnMouseMotion(self, x, y):
48                 handled = False
49                 for ctrl in self._glGuiControlList:
50                         if ctrl.OnMouseMotion(x, y):
51                                 handled = True
52                 return handled
53
54         def draw(self):
55                 for ctrl in self._glGuiControlList:
56                         ctrl.draw()
57
58         def updateLayout(self):
59                 self._layout.update()
60                 for ctrl in self._glGuiControlList:
61                         ctrl.updateLayout()
62
63 class glGuiPanel(glcanvas.GLCanvas):
64         def __init__(self, parent):
65                 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
66                 glcanvas.GLCanvas.__init__(self, parent, style=wx.WANTS_CHARS, attribList = attribList)
67                 self._base = self
68                 self._focus = None
69                 self._container = None
70                 self._container = glGuiContainer(self, (0,0))
71
72                 self._context = glcanvas.GLContext(self)
73                 self._glButtonsTexture = None
74                 self._buttonSize = 64
75
76                 wx.EVT_PAINT(self, self._OnGuiPaint)
77                 wx.EVT_SIZE(self, self._OnSize)
78                 wx.EVT_ERASE_BACKGROUND(self, self._OnEraseBackground)
79                 wx.EVT_LEFT_DOWN(self, self._OnGuiMouseLeftDown)
80                 wx.EVT_MOTION(self, self._OnGuiMouseMotion)
81                 wx.EVT_CHAR(self, self.OnKeyChar)
82                 wx.EVT_KILL_FOCUS(self, self.OnFocusLost)
83
84         def OnKeyChar(self, e):
85                 pass
86
87         def OnFocusLost(self, e):
88                 self._focus = None
89                 self.Refresh()
90
91         def _OnGuiMouseLeftDown(self,e):
92                 self.SetFocus()
93                 if self._container.OnMouseDown(e.GetX(), e.GetY()):
94                         return
95                 self.OnMouseLeftDown(e)
96
97         def _OnGuiMouseMotion(self,e):
98                 self.Refresh()
99                 if not self._container.OnMouseMotion(e.GetX(), e.GetY()):
100                         self.OnMouseMotion(e)
101
102         def _OnGuiPaint(self, e):
103                 h = self.GetSize().GetHeight()
104                 w = self.GetSize().GetWidth()
105                 oldButtonSize = self._buttonSize
106                 if h / 3 > w / 4:
107                         w = h * 4 / 3
108                 if w < 64 * 10:
109                         self._buttonSize = 48
110                 elif w < 64 * 15:
111                         self._buttonSize = 64
112                 elif w < 64 * 20:
113                         self._buttonSize = 80
114                 else:
115                         self._buttonSize = 96
116                 if self._buttonSize != oldButtonSize:
117                         self._container.updateLayout()
118
119                 dc = wx.PaintDC(self)
120                 self.SetCurrent(self._context)
121                 self.OnPaint(e)
122                 self._drawGui()
123                 glFlush()
124                 self.SwapBuffers()
125
126         def _drawGui(self):
127                 if self._glButtonsTexture is None:
128                         self._glButtonsTexture = opengl.loadGLTexture('glButtons.png')
129
130                 glDisable(GL_DEPTH_TEST)
131                 glEnable(GL_BLEND)
132                 glDisable(GL_LIGHTING)
133                 glColor4ub(255,255,255,255)
134
135                 glMatrixMode(GL_PROJECTION)
136                 glLoadIdentity()
137                 size = self.GetSize()
138                 glOrtho(0, size.GetWidth()-1, size.GetHeight()-1, 0, -1000.0, 1000.0)
139                 glMatrixMode(GL_MODELVIEW)
140                 glLoadIdentity()
141
142                 self._container.draw()
143
144         def _OnEraseBackground(self,event):
145                 #Workaround for windows background redraw flicker.
146                 pass
147
148         def _OnSize(self,e):
149                 self._container.setSize(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
150                 self._container.updateLayout()
151                 self.Refresh()
152
153         def OnMouseLeftDown(self,e):
154                 pass
155         def OnMouseMotion(self, e):
156                 pass
157         def OnPaint(self, e):
158                 pass
159
160         def add(self, ctrl):
161                 if self._container is not None:
162                         self._container.add(ctrl)
163
164 class glGuiLayoutButtons(object):
165         def __init__(self, parent):
166                 self._parent = parent
167                 self._parent._layout = self
168
169         def update(self):
170                 bs = self._parent._base._buttonSize
171                 x0, y0, w, h = self._parent.getSize()
172                 gridSize = bs * 1.3
173                 for ctrl in self._parent._glGuiControlList:
174                         pos = ctrl._pos
175                         if pos[0] < 0:
176                                 x = w + pos[0] * gridSize - bs * 0.2
177                         else:
178                                 x = pos[0] * gridSize + bs * 0.2
179                         if pos[1] < 0:
180                                 y = h + pos[1] * gridSize - bs * 0.2
181                         else:
182                                 y = pos[1] * gridSize + bs * 0.2
183                         ctrl.setSize(x, y, gridSize, gridSize)
184
185         def getLayoutSize(self):
186                 _, _, w, h = self._parent.getSize()
187                 return w, h
188
189 class glGuiLayoutGrid(object):
190         def __init__(self, parent):
191                 self._parent = parent
192                 self._parent._layout = self
193                 self._size = 0,0
194
195         def update(self):
196                 borderSize = self._parent._base._buttonSize * 0.2
197                 x0, y0, w, h = self._parent.getSize()
198                 x0 += borderSize
199                 y0 += borderSize
200                 widths = {}
201                 heights = {}
202                 for ctrl in self._parent._glGuiControlList:
203                         x, y = ctrl._pos
204                         w, h = ctrl.getMinSize()
205                         if not x in widths:
206                                 widths[x] = w
207                         else:
208                                 widths[x] = max(widths[x], w)
209                         if not y in heights:
210                                 heights[y] = h
211                         else:
212                                 heights[y] = max(heights[y], h)
213                 for ctrl in self._parent._glGuiControlList:
214                         x, y = ctrl._pos
215                         x1 = x0
216                         y1 = y0
217                         for n in xrange(0, x):
218                                 if not n in widths:
219                                         widths[n] = 0
220                                 x1 += widths[n]
221                         for n in xrange(0, y):
222                                 if not n in widths:
223                                         heights[n] = 0
224                                 y1 += heights[n]
225                         ctrl.setSize(x1, y1, widths[x], heights[y])
226                 self._size = sum(widths.values()) + borderSize * 2, sum(heights.values()) + borderSize * 2
227
228         def getLayoutSize(self):
229                 return self._size
230
231 class glButton(glGuiControl):
232         def __init__(self, parent, imageID, tooltip, pos, callback):
233                 super(glButton, self).__init__(parent, pos)
234                 self._tooltip = tooltip
235                 self._parent = parent
236                 self._imageID = imageID
237                 self._callback = callback
238                 self._selected = False
239                 self._focus = False
240                 self._hidden = False
241
242         def setSelected(self, value):
243                 self._selected = value
244
245         def setHidden(self, value):
246                 self._hidden = value
247
248         def getSelected(self):
249                 return self._selected
250
251         def getMinSize(self):
252                 return self._base._buttonSize, self._base._buttonSize
253
254         def _getPixelPos(self):
255                 x0, y0, w, h = self.getSize()
256                 return x0 + w / 2, y0 + h / 2
257
258         def draw(self):
259                 if self._hidden:
260                         return
261
262                 cx = (self._imageID % 4) / 4
263                 cy = int(self._imageID / 4) / 4
264                 bs = self._base._buttonSize
265                 pos = self._getPixelPos()
266
267                 glPushMatrix()
268                 glTranslatef(pos[0], pos[1], 0)
269                 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
270                 glEnable(GL_TEXTURE_2D)
271                 scale = 0.8
272                 if self._selected:
273                         scale = 1.0
274                 elif self._focus:
275                         scale = 0.9
276                 glScalef(bs * scale, bs * scale, bs * scale)
277                 glColor4ub(255,255,255,255)
278                 glBegin(GL_QUADS)
279                 glTexCoord2f(cx+0.25, cy)
280                 glVertex2f( 0.5,-0.5)
281                 glTexCoord2f(cx, cy)
282                 glVertex2f(-0.5,-0.5)
283                 glTexCoord2f(cx, cy+0.25)
284                 glVertex2f(-0.5, 0.5)
285                 glTexCoord2f(cx+0.25, cy+0.25)
286                 glVertex2f( 0.5, 0.5)
287                 glEnd()
288                 glDisable(GL_TEXTURE_2D)
289                 if self._focus:
290                         glColor4ub(0,0,0,255)
291                         glTranslatef(0, -0.55, 0)
292                         opengl.glDrawStringCenter(self._tooltip)
293                 glPopMatrix()
294
295         def _checkHit(self, x, y):
296                 if self._hidden:
297                         return False
298                 bs = self.getMinSize()[0]
299                 pos = self._getPixelPos()
300                 return -bs * 0.5 <= x - pos[0] <= bs * 0.5 and -bs * 0.5 <= y - pos[1] <= bs * 0.5
301
302         def OnMouseMotion(self, x, y):
303                 if self._checkHit(x, y):
304                         self._focus = True
305                         return True
306                 self._focus = False
307                 return False
308
309         def OnMouseDown(self, x, y):
310                 if self._checkHit(x, y):
311                         self._callback()
312                         return True
313                 return False
314
315 class glFrame(glGuiContainer):
316         def __init__(self, parent, pos):
317                 super(glFrame, self).__init__(parent, pos)
318                 self._selected = False
319                 self._focus = False
320                 self._hidden = False
321
322         def setSelected(self, value):
323                 self._selected = value
324
325         def setHidden(self, value):
326                 self._hidden = value
327
328         def getSelected(self):
329                 return self._selected
330
331         def getMinSize(self):
332                 return self._base._buttonSize, self._base._buttonSize
333
334         def _getPixelPos(self):
335                 x0, y0, w, h = self.getSize()
336                 return x0, y0
337
338         def draw(self):
339                 if self._hidden:
340                         return
341
342                 bs = self._parent._buttonSize
343                 pos = self._getPixelPos()
344
345                 glPushMatrix()
346                 glTranslatef(pos[0], pos[1], 0)
347                 glBindTexture(GL_TEXTURE_2D, self._parent._glButtonsTexture)
348                 glDisable(GL_TEXTURE_2D)
349
350                 size = self._layout.getLayoutSize()
351                 glColor4ub(255,255,255,128)
352                 glBegin(GL_QUADS)
353                 glTexCoord2f(1, 0)
354                 glVertex2f( size[0], 0)
355                 glTexCoord2f(0, 0)
356                 glVertex2f( 0, 0)
357                 glTexCoord2f(0, 1)
358                 glVertex2f( 0, size[1])
359                 glTexCoord2f(1, 1)
360                 glVertex2f( size[0], size[1])
361                 glEnd()
362                 glDisable(GL_TEXTURE_2D)
363                 glPopMatrix()
364                 #Draw the controls on the frame
365                 super(glFrame, self).draw()
366
367         def _checkHit(self, x, y):
368                 if self._hidden:
369                         return False
370                 pos = self._getPixelPos()
371                 w, h = self._layout.getLayoutSize()
372                 return 0 <= x - pos[0] <= w and 0 <= y - pos[1] <= h
373
374         def OnMouseMotion(self, x, y):
375                 super(glFrame, self).OnMouseMotion(x, y)
376                 if self._checkHit(x, y):
377                         self._focus = True
378                         return True
379                 self._focus = False
380                 return False
381
382         def OnMouseDown(self, x, y):
383                 if self._checkHit(x, y):
384                         super(glFrame, self).OnMouseDown(x, y)
385                         return True
386                 return False
387
388 class glLabel(glGuiControl):
389         def __init__(self, parent, label, pos):
390                 self._label = label
391                 super(glLabel, self).__init__(parent, pos)
392
393         def getMinSize(self):
394                 w, h = opengl.glGetStringSize(self._label)
395                 return w + 10, h + 4
396
397         def _getPixelPos(self):
398                 x0, y0, w, h = self.getSize()
399                 return x0, y0
400
401         def draw(self):
402                 pos = self._getPixelPos()
403
404                 glPushMatrix()
405                 glTranslatef(pos[0], pos[1], 0)
406
407                 size = self.getMinSize()
408                 glColor4ub(255,255,255,128)
409                 glBegin(GL_QUADS)
410                 glTexCoord2f(1, 0)
411                 glVertex2f( size[0], 0)
412                 glTexCoord2f(0, 0)
413                 glVertex2f( 0, 0)
414                 glTexCoord2f(0, 1)
415                 glVertex2f( 0, size[1])
416                 glTexCoord2f(1, 1)
417                 glVertex2f( size[0], size[1])
418                 glEnd()
419
420                 glTranslate(5, size[1] - 5, 0)
421                 glColor4ub(0,0,0,255)
422                 opengl.glDrawStringLeft(self._label)
423                 glPopMatrix()
424
425         def _checkHit(self, x, y):
426                 return False
427
428         def OnMouseMotion(self, x, y):
429                 return False
430
431         def OnMouseDown(self, x, y):
432                 return False