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