chiark / gitweb /
Make the scale entry box look a bit better.
[cura.git] / Cura / gui / util / openglGui.py
1 from __future__ import absolute_import
2 from __future__ import division
3
4 import wx
5 import math
6
7 from wx import glcanvas
8 import OpenGL
9 OpenGL.ERROR_CHECKING = False
10 from OpenGL.GL import *
11
12 from Cura.gui.util import opengl
13
14 class glGuiControl(object):
15         def __init__(self, parent, pos):
16                 self._parent = parent
17                 self._base = parent._base
18                 self._pos = pos
19                 self._size = (0,0, 1, 1)
20                 self._parent.add(self)
21
22         def setSize(self, x, y, w, h):
23                 self._size = (x, y, w, h)
24
25         def getSize(self):
26                 return self._size
27
28         def getMinSize(self):
29                 return 1, 1
30
31         def updateLayout(self):
32                 pass
33
34         def focusNext(self):
35                 for n in xrange(self._parent._glGuiControlList.index(self) + 1, len(self._parent._glGuiControlList)):
36                         if self._parent._glGuiControlList[n].setFocus():
37                                 return
38                 for n in xrange(0, self._parent._glGuiControlList.index(self)):
39                         if self._parent._glGuiControlList[n].setFocus():
40                                 return
41
42         def focusPrevious(self):
43                 for n in xrange(self._parent._glGuiControlList.index(self) -1, -1, -1):
44                         if self._parent._glGuiControlList[n].setFocus():
45                                 return
46                 for n in xrange(len(self._parent._glGuiControlList) - 1, self._parent._glGuiControlList.index(self), -1):
47                         if self._parent._glGuiControlList[n].setFocus():
48                                 return
49
50         def setFocus(self):
51                 return False
52
53         def hasFocus(self):
54                 return self._base._focus == self
55
56         def OnMouseUp(self, x, y):
57                 pass
58
59         def OnKeyChar(self, key):
60                 pass
61
62 class glGuiContainer(glGuiControl):
63         def __init__(self, parent, pos):
64                 self._glGuiControlList = []
65                 glGuiLayoutButtons(self)
66                 super(glGuiContainer, self).__init__(parent, pos)
67
68         def add(self, ctrl):
69                 self._glGuiControlList.append(ctrl)
70                 self.updateLayout()
71
72         def OnMouseDown(self, x, y):
73                 for ctrl in self._glGuiControlList:
74                         if ctrl.OnMouseDown(x, y):
75                                 return True
76                 return False
77
78         def OnMouseUp(self, x, y):
79                 for ctrl in self._glGuiControlList:
80                         if ctrl.OnMouseUp(x, y):
81                                 return True
82                 return False
83
84         def OnMouseMotion(self, x, y):
85                 handled = False
86                 for ctrl in self._glGuiControlList:
87                         if ctrl.OnMouseMotion(x, y):
88                                 handled = True
89                 return handled
90
91         def draw(self):
92                 for ctrl in self._glGuiControlList:
93                         ctrl.draw()
94
95         def updateLayout(self):
96                 self._layout.update()
97                 for ctrl in self._glGuiControlList:
98                         ctrl.updateLayout()
99
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)
104                 self._base = self
105                 self._focus = None
106                 self._container = None
107                 self._container = glGuiContainer(self, (0,0))
108
109                 self._context = glcanvas.GLContext(self)
110                 self._glButtonsTexture = None
111                 self._buttonSize = 64
112
113                 wx.EVT_PAINT(self, self._OnGuiPaint)
114                 wx.EVT_SIZE(self, self._OnSize)
115                 wx.EVT_ERASE_BACKGROUND(self, self._OnEraseBackground)
116                 wx.EVT_LEFT_DOWN(self, self._OnGuiMouseLeftDown)
117                 wx.EVT_LEFT_UP(self, self._OnGuiMouseLeftUp)
118                 wx.EVT_MOTION(self, self._OnGuiMouseMotion)
119                 wx.EVT_CHAR(self, self.OnKeyChar)
120                 wx.EVT_KILL_FOCUS(self, self.OnFocusLost)
121
122         def OnKeyChar(self, e):
123                 if self._focus is not None:
124                         self._focus.OnKeyChar(e.GetKeyCode())
125                         self.Refresh()
126
127         def OnFocusLost(self, e):
128                 self._focus = None
129                 self.Refresh()
130
131         def _OnGuiMouseLeftDown(self,e):
132                 self.SetFocus()
133                 if self._container.OnMouseDown(e.GetX(), e.GetY()):
134                         self.Refresh()
135                         return
136                 self.OnMouseLeftDown(e)
137         def _OnGuiMouseLeftUp(self, e):
138                 if self._container.OnMouseUp(e.GetX(), e.GetY()):
139                         self.Refresh()
140                         return
141                 self.OnMouseLeftUp(e)
142
143         def _OnGuiMouseMotion(self,e):
144                 self.Refresh()
145                 if not self._container.OnMouseMotion(e.GetX(), e.GetY()):
146                         self.OnMouseMotion(e)
147
148         def _OnGuiPaint(self, e):
149                 h = self.GetSize().GetHeight()
150                 w = self.GetSize().GetWidth()
151                 oldButtonSize = self._buttonSize
152                 if h / 3 < w / 4:
153                         w = h * 4 / 3
154                 if w < 64 * 8:
155                         self._buttonSize = 32
156                 elif w < 64 * 10:
157                         self._buttonSize = 48
158                 elif w < 64 * 15:
159                         self._buttonSize = 64
160                 elif w < 64 * 20:
161                         self._buttonSize = 80
162                 else:
163                         self._buttonSize = 96
164                 if self._buttonSize != oldButtonSize:
165                         self._container.updateLayout()
166
167                 dc = wx.PaintDC(self)
168                 self.SetCurrent(self._context)
169                 self.OnPaint(e)
170                 self._drawGui()
171                 glFlush()
172                 self.SwapBuffers()
173
174         def _drawGui(self):
175                 if self._glButtonsTexture is None:
176                         self._glButtonsTexture = opengl.loadGLTexture('glButtons.png')
177
178                 glDisable(GL_DEPTH_TEST)
179                 glEnable(GL_BLEND)
180                 glDisable(GL_LIGHTING)
181                 glColor4ub(255,255,255,255)
182
183                 glMatrixMode(GL_PROJECTION)
184                 glLoadIdentity()
185                 size = self.GetSize()
186                 glOrtho(0, size.GetWidth()-1, size.GetHeight()-1, 0, -1000.0, 1000.0)
187                 glMatrixMode(GL_MODELVIEW)
188                 glLoadIdentity()
189
190                 self._container.draw()
191
192         def _OnEraseBackground(self,event):
193                 #Workaround for windows background redraw flicker.
194                 pass
195
196         def _OnSize(self,e):
197                 self._container.setSize(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
198                 self._container.updateLayout()
199                 self.Refresh()
200
201         def OnMouseLeftDown(self,e):
202                 pass
203         def OnMouseLeftUp(self,e):
204                 pass
205         def OnMouseMotion(self, e):
206                 pass
207         def OnPaint(self, e):
208                 pass
209
210         def add(self, ctrl):
211                 if self._container is not None:
212                         self._container.add(ctrl)
213
214 class glGuiLayoutButtons(object):
215         def __init__(self, parent):
216                 self._parent = parent
217                 self._parent._layout = self
218
219         def update(self):
220                 bs = self._parent._base._buttonSize
221                 x0, y0, w, h = self._parent.getSize()
222                 gridSize = bs * 1.2
223                 for ctrl in self._parent._glGuiControlList:
224                         pos = ctrl._pos
225                         if pos[0] < 0:
226                                 x = w + pos[0] * gridSize - bs * 0.2
227                         else:
228                                 x = pos[0] * gridSize + bs * 0.2
229                         if pos[1] < 0:
230                                 y = h + pos[1] * gridSize - bs * 0.2
231                         else:
232                                 y = pos[1] * gridSize + bs * 0.2
233                         ctrl.setSize(x, y, gridSize, gridSize)
234
235         def getLayoutSize(self):
236                 _, _, w, h = self._parent.getSize()
237                 return w, h
238
239 class glGuiLayoutGrid(object):
240         def __init__(self, parent):
241                 self._parent = parent
242                 self._parent._layout = self
243                 self._size = 0,0
244
245         def update(self):
246                 borderSize = self._parent._base._buttonSize * 0.2
247                 x0, y0, w, h = self._parent.getSize()
248                 x0 += borderSize
249                 y0 += borderSize
250                 widths = {}
251                 heights = {}
252                 for ctrl in self._parent._glGuiControlList:
253                         x, y = ctrl._pos
254                         w, h = ctrl.getMinSize()
255                         if not x in widths:
256                                 widths[x] = w
257                         else:
258                                 widths[x] = max(widths[x], w)
259                         if not y in heights:
260                                 heights[y] = h
261                         else:
262                                 heights[y] = max(heights[y], h)
263                 for ctrl in self._parent._glGuiControlList:
264                         x, y = ctrl._pos
265                         x1 = x0
266                         y1 = y0
267                         for n in xrange(0, x):
268                                 if not n in widths:
269                                         widths[n] = 3
270                                 x1 += widths[n]
271                         for n in xrange(0, y):
272                                 if not n in heights:
273                                         heights[n] = 3
274                                 y1 += heights[n]
275                         ctrl.setSize(x1, y1, widths[x], heights[y])
276                 self._size = sum(widths.values()) + borderSize * 2, sum(heights.values()) + borderSize * 2
277
278         def getLayoutSize(self):
279                 return self._size
280
281 class glButton(glGuiControl):
282         def __init__(self, parent, imageID, tooltip, pos, callback):
283                 super(glButton, self).__init__(parent, pos)
284                 self._tooltip = tooltip
285                 self._parent = parent
286                 self._imageID = imageID
287                 self._callback = callback
288                 self._selected = False
289                 self._focus = False
290                 self._hidden = False
291                 self._disabled = False
292
293         def setSelected(self, value):
294                 self._selected = value
295
296         def setHidden(self, value):
297                 self._hidden = value
298
299         def setDisabled(self, value):
300                 self._disabled = value
301
302         def getSelected(self):
303                 return self._selected
304
305         def getMinSize(self):
306                 return self._base._buttonSize, self._base._buttonSize
307
308         def _getPixelPos(self):
309                 x0, y0, w, h = self.getSize()
310                 return x0 + w / 2, y0 + h / 2
311
312         def draw(self):
313                 if self._hidden:
314                         return
315
316                 cx = (self._imageID % 4) / 4
317                 cy = int(self._imageID / 4) / 4
318                 bs = self._base._buttonSize
319                 pos = self._getPixelPos()
320
321                 glPushMatrix()
322                 glTranslatef(pos[0], pos[1], 0)
323                 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
324                 glEnable(GL_TEXTURE_2D)
325                 scale = 0.8
326                 if self._selected:
327                         scale = 1.0
328                 elif self._focus:
329                         scale = 0.9
330                 glScalef(bs * scale, bs * scale, bs * scale)
331                 if self._disabled:
332                         glColor4ub(128,128,128,128)
333                 else:
334                         glColor4ub(255,255,255,255)
335                 glBegin(GL_QUADS)
336                 glTexCoord2f(cx+0.25, cy)
337                 glVertex2f( 0.5,-0.5)
338                 glTexCoord2f(cx, cy)
339                 glVertex2f(-0.5,-0.5)
340                 glTexCoord2f(cx, cy+0.25)
341                 glVertex2f(-0.5, 0.5)
342                 glTexCoord2f(cx+0.25, cy+0.25)
343                 glVertex2f( 0.5, 0.5)
344                 glEnd()
345                 glDisable(GL_TEXTURE_2D)
346                 if self._focus:
347                         glColor4ub(0,0,0,255)
348                         glTranslatef(0, -0.55, 0)
349                         opengl.glDrawStringCenter(self._tooltip)
350                 glPopMatrix()
351
352         def _checkHit(self, x, y):
353                 if self._hidden or self._disabled:
354                         return False
355                 bs = self.getMinSize()[0]
356                 pos = self._getPixelPos()
357                 return -bs * 0.5 <= x - pos[0] <= bs * 0.5 and -bs * 0.5 <= y - pos[1] <= bs * 0.5
358
359         def OnMouseMotion(self, x, y):
360                 if self._checkHit(x, y):
361                         self._focus = True
362                         return True
363                 self._focus = False
364                 return False
365
366         def OnMouseDown(self, x, y):
367                 if self._checkHit(x, y):
368                         self._callback()
369                         return True
370                 return False
371
372 class glRadioButton(glButton):
373         def __init__(self, parent, imageID, tooltip, pos, group, callback):
374                 super(glRadioButton, self).__init__(parent, imageID, tooltip, pos, self._onRadioSelect)
375                 self._group = group
376                 self._radioCallback = callback
377                 self._group.append(self)
378
379         def setSelected(self, value):
380                 self._selected = value
381
382         def _onRadioSelect(self):
383                 self._base._focus = None
384                 for ctrl in self._group:
385                         if ctrl != self:
386                                 ctrl.setSelected(False)
387                 if self.getSelected():
388                         self.setSelected(False)
389                 else:
390                         self.setSelected(True)
391                 self._radioCallback()
392
393 class glComboButton(glButton):
394         def __init__(self, parent, tooltip, imageIDs, tooltips, pos, callback):
395                 super(glComboButton, self).__init__(parent, imageIDs[0], tooltip, pos, self._onComboOpenSelect)
396                 self._imageIDs = imageIDs
397                 self._tooltips = tooltips
398                 self._comboCallback = callback
399                 self._selection = 0
400
401         def _onComboOpenSelect(self):
402                 self._base._focus = self
403
404         def draw(self):
405                 if self._hidden:
406                         return
407                 self._selected = self.hasFocus()
408                 super(glComboButton, self).draw()
409                 if not self._selected:
410                         return
411
412                 bs = self._base._buttonSize / 2
413                 pos = self._getPixelPos()
414
415                 glPushMatrix()
416                 glTranslatef(pos[0]+bs*0.5, pos[1] + bs*0.5, 0)
417                 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
418                 glScalef(bs, bs, bs)
419                 for n in xrange(0, len(self._imageIDs)):
420                         cx = (self._imageIDs[n] % 4) / 4
421                         cy = int(self._imageIDs[n] / 4) / 4
422                         glEnable(GL_TEXTURE_2D)
423                         glTranslatef(0, 1, 0)
424                         if self._disabled:
425                                 glColor4ub(128,128,128,128)
426                         else:
427                                 glColor4ub(255,255,255,255)
428                         glBegin(GL_QUADS)
429                         glTexCoord2f(cx+0.25, cy)
430                         glVertex2f( 0.5,-0.5)
431                         glTexCoord2f(cx, cy)
432                         glVertex2f(-0.5,-0.5)
433                         glTexCoord2f(cx, cy+0.25)
434                         glVertex2f(-0.5, 0.5)
435                         glTexCoord2f(cx+0.25, cy+0.25)
436                         glVertex2f( 0.5, 0.5)
437                         glEnd()
438                         glDisable(GL_TEXTURE_2D)
439
440                         glPushMatrix()
441                         glColor4ub(0,0,0,255)
442                         glTranslatef(-0.55, 0.1, 0)
443                         opengl.glDrawStringRight(self._tooltips[n])
444                         glPopMatrix()
445                 glPopMatrix()
446
447         def getValue(self):
448                 return self._selection
449
450         def setValue(self, value):
451                 self._selection = value
452                 self._comboCallback()
453
454         def OnMouseDown(self, x, y):
455                 if self._hidden or self._disabled:
456                         return False
457                 if self.hasFocus():
458                         bs = self._base._buttonSize / 2
459                         pos = self._getPixelPos()
460                         if 0 <= x - pos[0] <= bs and 0 <= y - pos[1] - bs <= bs * len(self._imageIDs):
461                                 self._selection = int((y - pos[1] - bs) / bs)
462                                 self._imageID = self._imageIDs[self._selection]
463                                 self._base._focus = None
464                                 self._comboCallback()
465                                 return True
466                 return super(glComboButton, self).OnMouseDown(x, y)
467
468 class glFrame(glGuiContainer):
469         def __init__(self, parent, pos):
470                 super(glFrame, self).__init__(parent, pos)
471                 self._selected = False
472                 self._focus = False
473                 self._hidden = False
474
475         def setSelected(self, value):
476                 self._selected = value
477
478         def setHidden(self, value):
479                 self._hidden = value
480
481         def getSelected(self):
482                 return self._selected
483
484         def getMinSize(self):
485                 return self._base._buttonSize, self._base._buttonSize
486
487         def _getPixelPos(self):
488                 x0, y0, w, h = self.getSize()
489                 return x0, y0
490
491         def draw(self):
492                 if self._hidden:
493                         return
494
495                 bs = self._parent._buttonSize
496                 pos = self._getPixelPos()
497
498                 glPushMatrix()
499                 glTranslatef(pos[0], pos[1], 0)
500                 glDisable(GL_TEXTURE_2D)
501
502                 size = self._layout.getLayoutSize()
503                 glColor4ub(0x60,0x60,0x60,255)
504                 glBegin(GL_QUADS)
505                 glTexCoord2f(1, 0)
506                 glVertex2f( size[0], 0)
507                 glTexCoord2f(0, 0)
508                 glVertex2f( 0, 0)
509                 glTexCoord2f(0, 1)
510                 glVertex2f( 0, size[1])
511                 glTexCoord2f(1, 1)
512                 glVertex2f( size[0], size[1])
513                 glEnd()
514                 glDisable(GL_TEXTURE_2D)
515                 glPopMatrix()
516                 #Draw the controls on the frame
517                 super(glFrame, self).draw()
518
519         def _checkHit(self, x, y):
520                 if self._hidden:
521                         return False
522                 pos = self._getPixelPos()
523                 w, h = self._layout.getLayoutSize()
524                 return 0 <= x - pos[0] <= w and 0 <= y - pos[1] <= h
525
526         def OnMouseMotion(self, x, y):
527                 super(glFrame, self).OnMouseMotion(x, y)
528                 if self._checkHit(x, y):
529                         self._focus = True
530                         return True
531                 self._focus = False
532                 return False
533
534         def OnMouseDown(self, x, y):
535                 if self._checkHit(x, y):
536                         super(glFrame, self).OnMouseDown(x, y)
537                         return True
538                 return False
539
540 class glLabel(glGuiControl):
541         def __init__(self, parent, label, pos):
542                 self._label = label
543                 super(glLabel, self).__init__(parent, pos)
544
545         def getMinSize(self):
546                 w, h = opengl.glGetStringSize(self._label)
547                 return w + 10, h + 4
548
549         def _getPixelPos(self):
550                 x0, y0, w, h = self.getSize()
551                 return x0, y0
552
553         def draw(self):
554                 x, y, w, h = self.getSize()
555
556                 glPushMatrix()
557                 glTranslatef(x, y, 0)
558
559                 glColor4ub(255,255,255,128)
560                 glBegin(GL_QUADS)
561                 glTexCoord2f(1, 0)
562                 glVertex2f( w, 0)
563                 glTexCoord2f(0, 0)
564                 glVertex2f( 0, 0)
565                 glTexCoord2f(0, 1)
566                 glVertex2f( 0, h)
567                 glTexCoord2f(1, 1)
568                 glVertex2f( w, h)
569                 glEnd()
570
571                 glTranslate(5, h - 5, 0)
572                 glColor4ub(0,0,0,255)
573                 opengl.glDrawStringLeft(self._label)
574                 glPopMatrix()
575
576         def _checkHit(self, x, y):
577                 return False
578
579         def OnMouseMotion(self, x, y):
580                 return False
581
582         def OnMouseDown(self, x, y):
583                 return False
584
585 class glNumberCtrl(glGuiControl):
586         def __init__(self, parent, value, pos, callback):
587                 self._callback = callback
588                 self._value = str(value)
589                 self._selectPos = 0
590                 self._maxLen = 6
591                 self._inCallback = False
592                 super(glNumberCtrl, self).__init__(parent, pos)
593
594         def setValue(self, value):
595                 if self._inCallback:
596                         return
597                 self._value = str(value)
598
599         def getMinSize(self):
600                 w, h = opengl.glGetStringSize("VALUES")
601                 return w + 10, h + 4
602
603         def _getPixelPos(self):
604                 x0, y0, w, h = self.getSize()
605                 return x0, y0
606
607         def draw(self):
608                 x, y, w, h = self.getSize()
609
610                 glPushMatrix()
611                 glTranslatef(x, y, 0)
612
613                 if self.hasFocus():
614                         glColor4ub(255,255,255,255)
615                 else:
616                         glColor4ub(255,255,255,192)
617                 glBegin(GL_QUADS)
618                 glTexCoord2f(1, 0)
619                 glVertex2f( w, 0)
620                 glTexCoord2f(0, 0)
621                 glVertex2f( 0, 0)
622                 glTexCoord2f(0, 1)
623                 glVertex2f( 0, h)
624                 glTexCoord2f(1, 1)
625                 glVertex2f( w, h)
626                 glEnd()
627
628                 glTranslate(5, h - 5, 0)
629                 glColor4ub(0,0,0,255)
630                 opengl.glDrawStringLeft(self._value)
631                 if self.hasFocus():
632                         glTranslate(opengl.glGetStringSize(self._value[0:self._selectPos])[0] - 2, -1, 0)
633                         opengl.glDrawStringLeft('|')
634                 glPopMatrix()
635
636         def _checkHit(self, x, y):
637                 x1, y1, w, h = self.getSize()
638                 return 0 <= x - x1 <= w and 0 <= y - y1 <= h
639
640         def OnMouseMotion(self, x, y):
641                 return False
642
643         def OnMouseDown(self, x, y):
644                 if self._checkHit(x, y):
645                         self.setFocus()
646                         return True
647                 return False
648
649         def OnKeyChar(self, c):
650                 self._inCallback = True
651                 if c == wx.WXK_LEFT:
652                         self._selectPos -= 1
653                         self._selectPos = max(0, self._selectPos)
654                 if c == wx.WXK_RIGHT:
655                         self._selectPos += 1
656                         self._selectPos = min(self._selectPos, len(self._value))
657                 if c == wx.WXK_UP:
658                         try:
659                                 value = float(self._value)
660                         except:
661                                 pass
662                         else:
663                                 value += 0.1
664                                 self._value = str(value)
665                                 self._callback(self._value)
666                 if c == wx.WXK_DOWN:
667                         try:
668                                 value = float(self._value)
669                         except:
670                                 pass
671                         else:
672                                 value -= 0.1
673                                 if value > 0:
674                                         self._value = str(value)
675                                         self._callback(self._value)
676                 if c == wx.WXK_BACK and self._selectPos > 0:
677                         self._value = self._value[0:self._selectPos - 1] + self._value[self._selectPos:]
678                         self._selectPos -= 1
679                         self._callback(self._value)
680                 if c == wx.WXK_DELETE:
681                         self._value = self._value[0:self._selectPos] + self._value[self._selectPos + 1:]
682                         self._callback(self._value)
683                 if c == wx.WXK_TAB:
684                         if wx.GetKeyState(wx.WXK_SHIFT):
685                                 self.focusPrevious()
686                         else:
687                                 self.focusNext()
688                 if (ord('0') <= c <= ord('9') or c == ord('.')) and len(self._value) < self._maxLen:
689                         self._value = self._value[0:self._selectPos] + chr(c) + self._value[self._selectPos:]
690                         self._selectPos += 1
691                         self._callback(self._value)
692                 self._inCallback = False
693
694         def setFocus(self):
695                 self._base._focus = self
696                 self._selectPos = len(self._value)
697                 return True
698
699 class glCheckbox(glGuiControl):
700         def __init__(self, parent, value, pos, callback):
701                 self._callback = callback
702                 self._value = value
703                 self._selectPos = 0
704                 self._maxLen = 6
705                 self._inCallback = False
706                 super(glCheckbox, self).__init__(parent, pos)
707
708         def setValue(self, value):
709                 if self._inCallback:
710                         return
711                 self._value = str(value)
712
713         def getValue(self):
714                 return self._value
715
716         def getMinSize(self):
717                 return 20, 20
718
719         def _getPixelPos(self):
720                 x0, y0, w, h = self.getSize()
721                 return x0, y0
722
723         def draw(self):
724                 x, y, w, h = self.getSize()
725
726                 glPushMatrix()
727                 glTranslatef(x, y, 0)
728
729                 if self._value:
730                         glColor4ub(0,255,0,255)
731                 else:
732                         glColor4ub(255,0,0,255)
733                 glBegin(GL_QUADS)
734                 glTexCoord2f(1, 0)
735                 glVertex2f( w, 0)
736                 glTexCoord2f(0, 0)
737                 glVertex2f( 0, 0)
738                 glTexCoord2f(0, 1)
739                 glVertex2f( 0, h)
740                 glTexCoord2f(1, 1)
741                 glVertex2f( w, h)
742                 glEnd()
743
744                 glPopMatrix()
745
746         def _checkHit(self, x, y):
747                 x1, y1, w, h = self.getSize()
748                 return 0 <= x - x1 <= w and 0 <= y - y1 <= h
749
750         def OnMouseMotion(self, x, y):
751                 return False
752
753         def OnMouseDown(self, x, y):
754                 if self._checkHit(x, y):
755                         self._value = not self._value
756                         return True
757                 return False
758
759 class glSlider(glGuiControl):
760         def __init__(self, parent, value, minValue, maxValue, pos, callback):
761                 super(glSlider, self).__init__(parent, pos)
762                 self._callback = callback
763                 self._focus = False
764                 self._hidden = False
765                 self._value = value
766                 self._minValue = minValue
767                 self._maxValue = maxValue
768
769         def setValue(self, value):
770                 self._value = value
771                 self._value = max(self._minValue, self._value)
772                 self._value = min(self._maxValue, self._value)
773
774         def getValue(self):
775                 return self._value
776
777         def setRange(self, minValue, maxValue):
778                 self._minValue = minValue
779                 self._maxValue = maxValue
780                 self._value = max(minValue, self._value)
781                 self._value = min(maxValue, self._value)
782
783         def getMinValue(self):
784                 return self._minValue
785
786         def getMaxValue(self):
787                 return self._maxValue
788
789         def setHidden(self, value):
790                 self._hidden = value
791
792         def getMinSize(self):
793                 return self._base._buttonSize * 0.2, self._base._buttonSize * 4
794
795         def _getPixelPos(self):
796                 x0, y0, w, h = self.getSize()
797                 minSize = self.getMinSize()
798                 return x0 + w / 2 - minSize[0] / 2, y0 + h / 2 - minSize[1] / 2
799
800         def draw(self):
801                 if self._hidden:
802                         return
803
804                 w, h = self.getMinSize()
805                 pos = self._getPixelPos()
806
807                 glPushMatrix()
808                 glTranslatef(pos[0], pos[1], 0)
809                 glDisable(GL_TEXTURE_2D)
810                 if self.hasFocus():
811                         glColor4ub(32,32,32,255)
812                 else:
813                         glColor4ub(32,32,32,192)
814                 glBegin(GL_QUADS)
815                 glVertex2f( w/2,-h/2)
816                 glVertex2f(-w/2,-h/2)
817                 glVertex2f(-w/2, h/2)
818                 glVertex2f( w/2, h/2)
819                 glEnd()
820                 scrollLength = h - w
821                 glTranslate(0.0,scrollLength/2,0)
822                 if self._focus:
823                         glColor4ub(0,0,0,255)
824                         glPushMatrix()
825                         glTranslate(-w/2,opengl.glGetStringSize(str(self._minValue))[1]/2,0)
826                         opengl.glDrawStringRight(str(self._minValue))
827                         glTranslate(0,-scrollLength,0)
828                         opengl.glDrawStringRight(str(self._maxValue))
829                         glTranslate(w,scrollLength-scrollLength*((self._value-self._minValue)/(self._maxValue-self._minValue)),0)
830                         opengl.glDrawStringLeft(str(self._value))
831                         glPopMatrix()
832                 glColor4ub(255,255,255,240)
833                 glTranslate(0.0,-scrollLength*((self._value-self._minValue)/(self._maxValue-self._minValue)),0)
834                 glBegin(GL_QUADS)
835                 glVertex2f( w/2,-w/2)
836                 glVertex2f(-w/2,-w/2)
837                 glVertex2f(-w/2, w/2)
838                 glVertex2f( w/2, w/2)
839                 glEnd()
840                 glPopMatrix()
841
842         def _checkHit(self, x, y):
843                 if self._hidden:
844                         return False
845                 pos = self._getPixelPos()
846                 w, h = self.getMinSize()
847                 return -w/2 <= x - pos[0] <= w/2 and -h/2 <= y - pos[1] <= h/2
848
849         def setFocus(self):
850                 self._base._focus = self
851                 return True
852
853         def OnMouseMotion(self, x, y):
854                 if self.hasFocus():
855                         w, h = self.getMinSize()
856                         scrollLength = h - w
857                         pos = self._getPixelPos()
858                         self.setValue(int(self._minValue + (self._maxValue - self._minValue) * -(y - pos[1] - scrollLength/2) / scrollLength))
859                         self._callback()
860                         return True
861                 if self._checkHit(x, y):
862                         self._focus = True
863                         return True
864                 self._focus = False
865                 return False
866
867         def OnMouseDown(self, x, y):
868                 if self._checkHit(x, y):
869                         self.setFocus()
870                         self.OnMouseMotion(x, y)
871                         return True
872                 return False
873
874         def OnMouseUp(self, x, y):
875                 if self.hasFocus():
876                         self._base._focus = None
877                         return True
878                 return False