chiark / gitweb /
Added ultimaker robot logo.
[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._glRobotTexture = None
112                 self._buttonSize = 64
113
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)
122
123         def OnKeyChar(self, e):
124                 if self._focus is not None:
125                         self._focus.OnKeyChar(e.GetKeyCode())
126                         self.Refresh()
127
128         def OnFocusLost(self, e):
129                 self._focus = None
130                 self.Refresh()
131
132         def _OnGuiMouseLeftDown(self,e):
133                 self.SetFocus()
134                 if self._container.OnMouseDown(e.GetX(), e.GetY()):
135                         self.Refresh()
136                         return
137                 self.OnMouseLeftDown(e)
138         def _OnGuiMouseLeftUp(self, e):
139                 if self._container.OnMouseUp(e.GetX(), e.GetY()):
140                         self.Refresh()
141                         return
142                 self.OnMouseLeftUp(e)
143
144         def _OnGuiMouseMotion(self,e):
145                 self.Refresh()
146                 if not self._container.OnMouseMotion(e.GetX(), e.GetY()):
147                         self.OnMouseMotion(e)
148
149         def _OnGuiPaint(self, e):
150                 h = self.GetSize().GetHeight()
151                 w = self.GetSize().GetWidth()
152                 oldButtonSize = self._buttonSize
153                 if h / 3 < w / 4:
154                         w = h * 4 / 3
155                 if w < 64 * 8:
156                         self._buttonSize = 32
157                 elif w < 64 * 10:
158                         self._buttonSize = 48
159                 elif w < 64 * 15:
160                         self._buttonSize = 64
161                 elif w < 64 * 20:
162                         self._buttonSize = 80
163                 else:
164                         self._buttonSize = 96
165                 if self._buttonSize != oldButtonSize:
166                         self._container.updateLayout()
167
168                 dc = wx.PaintDC(self)
169                 self.SetCurrent(self._context)
170                 self.OnPaint(e)
171                 self._drawGui()
172                 glFlush()
173                 self.SwapBuffers()
174
175         def _drawGui(self):
176                 if self._glButtonsTexture is None:
177                         self._glButtonsTexture = opengl.loadGLTexture('glButtons.png')
178                         self._glRobotTexture = opengl.loadGLTexture('UltimakerRobot.png')
179
180                 glDisable(GL_DEPTH_TEST)
181                 glEnable(GL_BLEND)
182                 glDisable(GL_LIGHTING)
183                 glColor4ub(255,255,255,255)
184
185                 glMatrixMode(GL_PROJECTION)
186                 glLoadIdentity()
187                 size = self.GetSize()
188                 glOrtho(0, size.GetWidth()-1, size.GetHeight()-1, 0, -1000.0, 1000.0)
189                 glMatrixMode(GL_MODELVIEW)
190                 glLoadIdentity()
191
192                 self._container.draw()
193                 glBindTexture(GL_TEXTURE_2D, self._glRobotTexture)
194                 glEnable(GL_TEXTURE_2D)
195                 glPushMatrix()
196                 glColor4f(1,1,1,1)
197                 glTranslate(size.GetWidth() - 8,size.GetHeight() - 16,0)
198                 s = self._buttonSize * 1.4
199                 glScale(s,s,s)
200                 glBegin(GL_QUADS)
201                 glTexCoord2f(1, 0)
202                 glVertex2f(0,-1)
203                 glTexCoord2f(0, 0)
204                 glVertex2f(-1,-1)
205                 glTexCoord2f(0, 1)
206                 glVertex2f(-1, 0)
207                 glTexCoord2f(1, 1)
208                 glVertex2f(0, 0)
209                 glEnd()
210                 glDisable(GL_TEXTURE_2D)
211                 glPopMatrix()
212
213         def _OnEraseBackground(self,event):
214                 #Workaround for windows background redraw flicker.
215                 pass
216
217         def _OnSize(self,e):
218                 self._container.setSize(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
219                 self._container.updateLayout()
220                 self.Refresh()
221
222         def OnMouseLeftDown(self,e):
223                 pass
224         def OnMouseLeftUp(self,e):
225                 pass
226         def OnMouseMotion(self, e):
227                 pass
228         def OnPaint(self, e):
229                 pass
230
231         def add(self, ctrl):
232                 if self._container is not None:
233                         self._container.add(ctrl)
234
235 class glGuiLayoutButtons(object):
236         def __init__(self, parent):
237                 self._parent = parent
238                 self._parent._layout = self
239
240         def update(self):
241                 bs = self._parent._base._buttonSize
242                 x0, y0, w, h = self._parent.getSize()
243                 gridSize = bs * 1.2
244                 for ctrl in self._parent._glGuiControlList:
245                         pos = ctrl._pos
246                         if pos[0] < 0:
247                                 x = w + pos[0] * gridSize - bs * 0.2
248                         else:
249                                 x = pos[0] * gridSize + bs * 0.2
250                         if pos[1] < 0:
251                                 y = h + pos[1] * gridSize - bs * 0.2
252                         else:
253                                 y = pos[1] * gridSize + bs * 0.2
254                         ctrl.setSize(x, y, gridSize, gridSize)
255
256         def getLayoutSize(self):
257                 _, _, w, h = self._parent.getSize()
258                 return w, h
259
260 class glGuiLayoutGrid(object):
261         def __init__(self, parent):
262                 self._parent = parent
263                 self._parent._layout = self
264                 self._size = 0,0
265
266         def update(self):
267                 borderSize = self._parent._base._buttonSize * 0.2
268                 x0, y0, w, h = self._parent.getSize()
269                 x0 += borderSize
270                 y0 += borderSize
271                 widths = {}
272                 heights = {}
273                 for ctrl in self._parent._glGuiControlList:
274                         x, y = ctrl._pos
275                         w, h = ctrl.getMinSize()
276                         if not x in widths:
277                                 widths[x] = w
278                         else:
279                                 widths[x] = max(widths[x], w)
280                         if not y in heights:
281                                 heights[y] = h
282                         else:
283                                 heights[y] = max(heights[y], h)
284                 for ctrl in self._parent._glGuiControlList:
285                         x, y = ctrl._pos
286                         x1 = x0
287                         y1 = y0
288                         for n in xrange(0, x):
289                                 if not n in widths:
290                                         widths[n] = 3
291                                 x1 += widths[n]
292                         for n in xrange(0, y):
293                                 if not n in heights:
294                                         heights[n] = 3
295                                 y1 += heights[n]
296                         ctrl.setSize(x1, y1, widths[x], heights[y])
297                 self._size = sum(widths.values()) + borderSize * 2, sum(heights.values()) + borderSize * 2
298
299         def getLayoutSize(self):
300                 return self._size
301
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
310                 self._focus = False
311                 self._hidden = False
312                 self._disabled = False
313
314         def setSelected(self, value):
315                 self._selected = value
316
317         def setHidden(self, value):
318                 self._hidden = value
319
320         def setDisabled(self, value):
321                 self._disabled = value
322
323         def getSelected(self):
324                 return self._selected
325
326         def getMinSize(self):
327                 return self._base._buttonSize, self._base._buttonSize
328
329         def _getPixelPos(self):
330                 x0, y0, w, h = self.getSize()
331                 return x0 + w / 2, y0 + h / 2
332
333         def draw(self):
334                 if self._hidden:
335                         return
336
337                 cx = (self._imageID % 4) / 4
338                 cy = int(self._imageID / 4) / 4
339                 bs = self._base._buttonSize
340                 pos = self._getPixelPos()
341
342                 glPushMatrix()
343                 glTranslatef(pos[0], pos[1], 0)
344                 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
345                 glEnable(GL_TEXTURE_2D)
346                 scale = 0.8
347                 if self._selected:
348                         scale = 1.0
349                 elif self._focus:
350                         scale = 0.9
351                 glScalef(bs * scale, bs * scale, bs * scale)
352                 if self._disabled:
353                         glColor4ub(128,128,128,128)
354                 else:
355                         glColor4ub(255,255,255,255)
356                 glBegin(GL_QUADS)
357                 glTexCoord2f(cx+0.25, cy)
358                 glVertex2f( 0.5,-0.5)
359                 glTexCoord2f(cx, cy)
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)
365                 glEnd()
366                 glDisable(GL_TEXTURE_2D)
367                 if self._focus:
368                         glColor4ub(0,0,0,255)
369                         glTranslatef(0, -0.55, 0)
370                         opengl.glDrawStringCenter(self._tooltip)
371                 glPopMatrix()
372
373         def _checkHit(self, x, y):
374                 if self._hidden or self._disabled:
375                         return False
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
379
380         def OnMouseMotion(self, x, y):
381                 if self._checkHit(x, y):
382                         self._focus = True
383                         return True
384                 self._focus = False
385                 return False
386
387         def OnMouseDown(self, x, y):
388                 if self._checkHit(x, y):
389                         self._callback()
390                         return True
391                 return False
392
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)
396                 self._group = group
397                 self._radioCallback = callback
398                 self._group.append(self)
399
400         def setSelected(self, value):
401                 self._selected = value
402
403         def _onRadioSelect(self):
404                 self._base._focus = None
405                 for ctrl in self._group:
406                         if ctrl != self:
407                                 ctrl.setSelected(False)
408                 if self.getSelected():
409                         self.setSelected(False)
410                 else:
411                         self.setSelected(True)
412                 self._radioCallback()
413
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
420                 self._selection = 0
421
422         def _onComboOpenSelect(self):
423                 self._base._focus = self
424
425         def draw(self):
426                 if self._hidden:
427                         return
428                 self._selected = self.hasFocus()
429                 super(glComboButton, self).draw()
430                 if not self._selected:
431                         return
432
433                 bs = self._base._buttonSize / 2
434                 pos = self._getPixelPos()
435
436                 glPushMatrix()
437                 glTranslatef(pos[0]+bs*0.5, pos[1] + bs*0.5, 0)
438                 glBindTexture(GL_TEXTURE_2D, self._base._glButtonsTexture)
439                 glScalef(bs, bs, bs)
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)
445                         if self._disabled:
446                                 glColor4ub(128,128,128,128)
447                         else:
448                                 glColor4ub(255,255,255,255)
449                         glBegin(GL_QUADS)
450                         glTexCoord2f(cx+0.25, cy)
451                         glVertex2f( 0.5,-0.5)
452                         glTexCoord2f(cx, cy)
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)
458                         glEnd()
459                         glDisable(GL_TEXTURE_2D)
460
461                         glPushMatrix()
462                         glColor4ub(0,0,0,255)
463                         glTranslatef(-0.55, 0.1, 0)
464                         opengl.glDrawStringRight(self._tooltips[n])
465                         glPopMatrix()
466                 glPopMatrix()
467
468         def getValue(self):
469                 return self._selection
470
471         def setValue(self, value):
472                 self._selection = value
473                 self._comboCallback()
474
475         def OnMouseDown(self, x, y):
476                 if self._hidden or self._disabled:
477                         return False
478                 if self.hasFocus():
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()
486                                 return True
487                 return super(glComboButton, self).OnMouseDown(x, y)
488
489 class glFrame(glGuiContainer):
490         def __init__(self, parent, pos):
491                 super(glFrame, self).__init__(parent, pos)
492                 self._selected = False
493                 self._focus = False
494                 self._hidden = False
495
496         def setSelected(self, value):
497                 self._selected = value
498
499         def setHidden(self, value):
500                 self._hidden = value
501
502         def getSelected(self):
503                 return self._selected
504
505         def getMinSize(self):
506                 return self._base._buttonSize, self._base._buttonSize
507
508         def _getPixelPos(self):
509                 x0, y0, w, h = self.getSize()
510                 return x0, y0
511
512         def draw(self):
513                 if self._hidden:
514                         return
515
516                 bs = self._parent._buttonSize
517                 pos = self._getPixelPos()
518
519                 glPushMatrix()
520                 glTranslatef(pos[0], pos[1], 0)
521                 glDisable(GL_TEXTURE_2D)
522
523                 size = self._layout.getLayoutSize()
524                 glColor4ub(60,60,60,255)
525                 glBegin(GL_QUADS)
526                 glTexCoord2f(1, 0)
527                 glVertex2f( size[0], 0)
528                 glTexCoord2f(0, 0)
529                 glVertex2f( 0, 0)
530                 glTexCoord2f(0, 1)
531                 glVertex2f( 0, size[1])
532                 glTexCoord2f(1, 1)
533                 glVertex2f( size[0], size[1])
534                 glEnd()
535                 glDisable(GL_TEXTURE_2D)
536                 glPopMatrix()
537                 #Draw the controls on the frame
538                 super(glFrame, self).draw()
539
540         def _checkHit(self, x, y):
541                 if self._hidden:
542                         return False
543                 pos = self._getPixelPos()
544                 w, h = self._layout.getLayoutSize()
545                 return 0 <= x - pos[0] <= w and 0 <= y - pos[1] <= h
546
547         def OnMouseMotion(self, x, y):
548                 super(glFrame, self).OnMouseMotion(x, y)
549                 if self._checkHit(x, y):
550                         self._focus = True
551                         return True
552                 self._focus = False
553                 return False
554
555         def OnMouseDown(self, x, y):
556                 if self._checkHit(x, y):
557                         super(glFrame, self).OnMouseDown(x, y)
558                         return True
559                 return False
560
561 class glLabel(glGuiControl):
562         def __init__(self, parent, label, pos):
563                 self._label = label
564                 super(glLabel, self).__init__(parent, pos)
565
566         def getMinSize(self):
567                 w, h = opengl.glGetStringSize(self._label)
568                 return w + 10, h + 4
569
570         def _getPixelPos(self):
571                 x0, y0, w, h = self.getSize()
572                 return x0, y0
573
574         def draw(self):
575                 x, y, w, h = self.getSize()
576
577                 glPushMatrix()
578                 glTranslatef(x, y, 0)
579
580                 glColor4ub(255,255,255,128)
581                 glBegin(GL_QUADS)
582                 glTexCoord2f(1, 0)
583                 glVertex2f( w, 0)
584                 glTexCoord2f(0, 0)
585                 glVertex2f( 0, 0)
586                 glTexCoord2f(0, 1)
587                 glVertex2f( 0, h)
588                 glTexCoord2f(1, 1)
589                 glVertex2f( w, h)
590                 glEnd()
591
592                 glTranslate(5, h - 5, 0)
593                 glColor4ub(0,0,0,255)
594                 opengl.glDrawStringLeft(self._label)
595                 glPopMatrix()
596
597         def _checkHit(self, x, y):
598                 return False
599
600         def OnMouseMotion(self, x, y):
601                 return False
602
603         def OnMouseDown(self, x, y):
604                 return False
605
606 class glNumberCtrl(glGuiControl):
607         def __init__(self, parent, value, pos, callback):
608                 self._callback = callback
609                 self._value = str(value)
610                 self._selectPos = 0
611                 self._maxLen = 6
612                 self._inCallback = False
613                 super(glNumberCtrl, self).__init__(parent, pos)
614
615         def setValue(self, value):
616                 if self._inCallback:
617                         return
618                 self._value = str(value)
619
620         def getMinSize(self):
621                 w, h = opengl.glGetStringSize("VALUES")
622                 return w + 10, h + 4
623
624         def _getPixelPos(self):
625                 x0, y0, w, h = self.getSize()
626                 return x0, y0
627
628         def draw(self):
629                 x, y, w, h = self.getSize()
630
631                 glPushMatrix()
632                 glTranslatef(x, y, 0)
633
634                 if self.hasFocus():
635                         glColor4ub(255,255,255,255)
636                 else:
637                         glColor4ub(255,255,255,192)
638                 glBegin(GL_QUADS)
639                 glTexCoord2f(1, 0)
640                 glVertex2f( w, 0)
641                 glTexCoord2f(0, 0)
642                 glVertex2f( 0, 0)
643                 glTexCoord2f(0, 1)
644                 glVertex2f( 0, h)
645                 glTexCoord2f(1, 1)
646                 glVertex2f( w, h)
647                 glEnd()
648
649                 glTranslate(5, h - 5, 0)
650                 glColor4ub(0,0,0,255)
651                 opengl.glDrawStringLeft(self._value)
652                 if self.hasFocus():
653                         glTranslate(opengl.glGetStringSize(self._value[0:self._selectPos])[0] - 2, -1, 0)
654                         opengl.glDrawStringLeft('|')
655                 glPopMatrix()
656
657         def _checkHit(self, x, y):
658                 x1, y1, w, h = self.getSize()
659                 return 0 <= x - x1 <= w and 0 <= y - y1 <= h
660
661         def OnMouseMotion(self, x, y):
662                 return False
663
664         def OnMouseDown(self, x, y):
665                 if self._checkHit(x, y):
666                         self.setFocus()
667                         return True
668                 return False
669
670         def OnKeyChar(self, c):
671                 self._inCallback = True
672                 if c == wx.WXK_LEFT:
673                         self._selectPos -= 1
674                         self._selectPos = max(0, self._selectPos)
675                 if c == wx.WXK_RIGHT:
676                         self._selectPos += 1
677                         self._selectPos = min(self._selectPos, len(self._value))
678                 if c == wx.WXK_UP:
679                         try:
680                                 value = float(self._value)
681                         except:
682                                 pass
683                         else:
684                                 value += 0.1
685                                 self._value = str(value)
686                                 self._callback(self._value)
687                 if c == wx.WXK_DOWN:
688                         try:
689                                 value = float(self._value)
690                         except:
691                                 pass
692                         else:
693                                 value -= 0.1
694                                 if value > 0:
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:]
699                         self._selectPos -= 1
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)
704                 if c == wx.WXK_TAB:
705                         if wx.GetKeyState(wx.WXK_SHIFT):
706                                 self.focusPrevious()
707                         else:
708                                 self.focusNext()
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:]
711                         self._selectPos += 1
712                         self._callback(self._value)
713                 self._inCallback = False
714
715         def setFocus(self):
716                 self._base._focus = self
717                 self._selectPos = len(self._value)
718                 return True
719
720 class glCheckbox(glGuiControl):
721         def __init__(self, parent, value, pos, callback):
722                 self._callback = callback
723                 self._value = value
724                 self._selectPos = 0
725                 self._maxLen = 6
726                 self._inCallback = False
727                 super(glCheckbox, self).__init__(parent, pos)
728
729         def setValue(self, value):
730                 if self._inCallback:
731                         return
732                 self._value = str(value)
733
734         def getValue(self):
735                 return self._value
736
737         def getMinSize(self):
738                 return 20, 20
739
740         def _getPixelPos(self):
741                 x0, y0, w, h = self.getSize()
742                 return x0, y0
743
744         def draw(self):
745                 x, y, w, h = self.getSize()
746
747                 glPushMatrix()
748                 glTranslatef(x, y, 0)
749
750                 if self._value:
751                         glColor4ub(0,255,0,255)
752                 else:
753                         glColor4ub(255,0,0,255)
754                 glBegin(GL_QUADS)
755                 glTexCoord2f(1, 0)
756                 glVertex2f( w, 0)
757                 glTexCoord2f(0, 0)
758                 glVertex2f( 0, 0)
759                 glTexCoord2f(0, 1)
760                 glVertex2f( 0, h)
761                 glTexCoord2f(1, 1)
762                 glVertex2f( w, h)
763                 glEnd()
764
765                 glPopMatrix()
766
767         def _checkHit(self, x, y):
768                 x1, y1, w, h = self.getSize()
769                 return 0 <= x - x1 <= w and 0 <= y - y1 <= h
770
771         def OnMouseMotion(self, x, y):
772                 return False
773
774         def OnMouseDown(self, x, y):
775                 if self._checkHit(x, y):
776                         self._value = not self._value
777                         return True
778                 return False
779
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
784                 self._focus = False
785                 self._hidden = False
786                 self._value = value
787                 self._minValue = minValue
788                 self._maxValue = maxValue
789
790         def setValue(self, value):
791                 self._value = value
792                 self._value = max(self._minValue, self._value)
793                 self._value = min(self._maxValue, self._value)
794
795         def getValue(self):
796                 return self._value
797
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)
803
804         def getMinValue(self):
805                 return self._minValue
806
807         def getMaxValue(self):
808                 return self._maxValue
809
810         def setHidden(self, value):
811                 self._hidden = value
812
813         def getMinSize(self):
814                 return self._base._buttonSize * 0.2, self._base._buttonSize * 4
815
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
820
821         def draw(self):
822                 if self._hidden:
823                         return
824
825                 w, h = self.getMinSize()
826                 pos = self._getPixelPos()
827
828                 glPushMatrix()
829                 glTranslatef(pos[0], pos[1], 0)
830                 glDisable(GL_TEXTURE_2D)
831                 if self.hasFocus():
832                         glColor4ub(60,60,60,255)
833                 else:
834                         glColor4ub(60,60,60,192)
835                 glBegin(GL_QUADS)
836                 glVertex2f( w/2,-h/2)
837                 glVertex2f(-w/2,-h/2)
838                 glVertex2f(-w/2, h/2)
839                 glVertex2f( w/2, h/2)
840                 glEnd()
841                 scrollLength = h - w
842                 glTranslate(0.0,scrollLength/2,0)
843                 if self._focus:
844                         glColor4ub(0,0,0,255)
845                         glPushMatrix()
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))
852                         glPopMatrix()
853                 glColor4ub(255,255,255,240)
854                 glTranslate(0.0,-scrollLength*((self._value-self._minValue)/(self._maxValue-self._minValue)),0)
855                 glBegin(GL_QUADS)
856                 glVertex2f( w/2,-w/2)
857                 glVertex2f(-w/2,-w/2)
858                 glVertex2f(-w/2, w/2)
859                 glVertex2f( w/2, w/2)
860                 glEnd()
861                 glPopMatrix()
862
863         def _checkHit(self, x, y):
864                 if self._hidden:
865                         return False
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
869
870         def setFocus(self):
871                 self._base._focus = self
872                 return True
873
874         def OnMouseMotion(self, x, y):
875                 if self.hasFocus():
876                         w, h = self.getMinSize()
877                         scrollLength = h - w
878                         pos = self._getPixelPos()
879                         self.setValue(int(self._minValue + (self._maxValue - self._minValue) * -(y - pos[1] - scrollLength/2) / scrollLength))
880                         self._callback()
881                         return True
882                 if self._checkHit(x, y):
883                         self._focus = True
884                         return True
885                 self._focus = False
886                 return False
887
888         def OnMouseDown(self, x, y):
889                 if self._checkHit(x, y):
890                         self.setFocus()
891                         self.OnMouseMotion(x, y)
892                         return True
893                 return False
894
895         def OnMouseUp(self, x, y):
896                 if self.hasFocus():
897                         self._base._focus = None
898                         return True
899                 return False