2
0

DirectCheckButton.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. from DirectButton import *
  2. from DirectLabel import *
  3. class DirectCheckButton(DirectButton):
  4. """
  5. DirectCheckButton(parent) - Create a DirectGuiWidget which responds
  6. to mouse clicks by setting a state of on or off and execute a callback
  7. function (passing that state through) if defined
  8. """
  9. def __init__(self, parent = aspect2d, **kw):
  10. # Inherits from DirectButton
  11. # A Direct Frame can have:
  12. # - A background texture (pass in path to image, or Texture Card)
  13. # - A midground geometry item (pass in geometry)
  14. # - A foreground text Node (pass in text string or Onscreen Text)
  15. # For a direct button:
  16. # Each button has 4 states (ready, press, rollover, disabled)
  17. # The same image/geom/text can be used for all four states or each
  18. # state can have a different text/geom/image
  19. # State transitions happen automatically based upon mouse interaction
  20. # Responds to click event and calls command if None
  21. self.colors = None
  22. optiondefs = (
  23. ('indicatorValue', 0, self.setIndicatorValue),
  24. # boxBorder defines the space created around the check box
  25. ('boxBorder', 0, None),
  26. # boxPlacement maps left, above, right, below
  27. ('boxPlacement', 'left', None),
  28. ('boxImage', None, None),
  29. ('boxImageScale', 1, None),
  30. ('boxImageColor', None, None),
  31. ('boxRelief', 'sunken', None),
  32. )
  33. # Merge keyword options with default options
  34. self.defineoptions(kw, optiondefs)
  35. # Initialize superclasses
  36. DirectButton.__init__(self, parent)
  37. self.indicator = self.createcomponent("indicator", (), None,
  38. DirectLabel, (self,),
  39. numStates = 2,
  40. image = self['boxImage'],
  41. image_scale = self['boxImageScale'],
  42. image_color = self['boxImageColor'],
  43. state = 'disabled',
  44. text = ('X' , 'X'),
  45. relief = self['boxRelief'],
  46. )
  47. # Call option initialization functions
  48. self.initialiseoptions(DirectCheckButton)
  49. # After initialization with X giving it the correct size, put back space
  50. if self['boxImage'] == None:
  51. self.indicator['text'] = (' ', '*')
  52. self.indicator['text_pos'] = (0,-.2)
  53. else:
  54. self.indicator['text'] = (' ', ' ')
  55. if self['boxImageColor'] != None and self['boxImage'] != None:
  56. self.colors = [VBase4(0,0,0,0), self['boxImageColor']]
  57. self.component('indicator')['image_color'] = VBase4(0,0,0,0)
  58. # Override the resetFrameSize of DirectGuiWidget inorder to provide space for label
  59. def resetFrameSize(self):
  60. self.setFrameSize(fClearFrame = 1)
  61. def setFrameSize(self, fClearFrame = 0):
  62. if self['frameSize']:
  63. # Use user specified bounds
  64. self.bounds = self['frameSize']
  65. else:
  66. # Use ready state to compute bounds
  67. frameType = self.frameStyle[0].getType()
  68. if fClearFrame and (frameType != PGFrameStyle.TNone):
  69. self.frameStyle[0].setType(PGFrameStyle.TNone)
  70. self.guiItem.setFrameStyle(0, self.frameStyle[0])
  71. # To force an update of the button
  72. self.guiItem.getStateDef(0)
  73. # Clear out frame before computing bounds
  74. self.getBounds()
  75. # Restore frame style if necessary
  76. if (frameType != PGFrameStyle.TNone):
  77. self.frameStyle[0].setType(frameType)
  78. self.guiItem.setFrameStyle(0, self.frameStyle[0])
  79. # Ok, they didn't set specific bounds,
  80. # let's add room for the label indicator
  81. # get the difference in height
  82. ibw = self.indicator['borderWidth']
  83. indicatorWidth = (self.indicator.getWidth() + (2*ibw[0]))
  84. indicatorHeight = (self.indicator.getHeight() + (2*ibw[1]))
  85. diff = (indicatorHeight + (2*self['boxBorder']) -
  86. (self.bounds[3] - self.bounds[2]))
  87. # If background is smaller then indicator, enlarge background
  88. if diff > 0:
  89. if self['boxPlacement'] == 'left': #left
  90. self.bounds[0] += -(indicatorWidth + (2*self['boxBorder']))
  91. self.bounds[3] += diff/2
  92. self.bounds[2] -= diff/2
  93. elif self['boxPlacement'] == 'below': #below
  94. self.bounds[2] += -(indicatorHeight+(2*self['boxBorder']))
  95. elif self['boxPlacement'] == 'right': #right
  96. self.bounds[1] += indicatorWidth + (2*self['boxBorder'])
  97. self.bounds[3] += diff/2
  98. self.bounds[2] -= diff/2
  99. else: #above
  100. self.bounds[3] += indicatorHeight + (2*self['boxBorder'])
  101. # Else make space on correct side for indicator
  102. else:
  103. if self['boxPlacement'] == 'left': #left
  104. self.bounds[0] += -(indicatorWidth + (2*self['boxBorder']))
  105. elif self['boxPlacement'] == 'below': #below
  106. self.bounds[2] += -(indicatorHeight + (2*self['boxBorder']))
  107. elif self['boxPlacement'] == 'right': #right
  108. self.bounds[1] += indicatorWidth + (2*self['boxBorder'])
  109. else: #above
  110. self.bounds[3] += indicatorHeight + (2*self['boxBorder'])
  111. # Set frame to new dimensions
  112. if ((frameType != PGFrameStyle.TNone) and
  113. (frameType != PGFrameStyle.TFlat)):
  114. bw = self['borderWidth']
  115. else:
  116. bw = (0,0)
  117. # Set frame to new dimensions
  118. self.guiItem.setFrame(
  119. self.bounds[0] - bw[0],
  120. self.bounds[1] + bw[0],
  121. self.bounds[2] - bw[1],
  122. self.bounds[3] + bw[1])
  123. # If they didn't specify a position, put it in the center of new area
  124. if not self.indicator['pos']:
  125. bbounds = self.bounds
  126. lbounds = self.indicator.bounds
  127. newpos = [0,0,0]
  128. if self['boxPlacement'] == 'left': #left
  129. newpos[0] += bbounds[0]-lbounds[0] + self['boxBorder'] + ibw[0]
  130. dropValue = (bbounds[3]-bbounds[2]-lbounds[3]+lbounds[2])/2 + self['boxBorder']
  131. newpos[2] += (bbounds[3]-lbounds[3] + self['boxBorder'] -
  132. dropValue)
  133. elif self['boxPlacement'] == 'right': #right
  134. newpos[0] += bbounds[1]-lbounds[1] - self['boxBorder'] - ibw[0]
  135. dropValue = (bbounds[3]-bbounds[2]-lbounds[3]+lbounds[2])/2 + self['boxBorder']
  136. newpos[2] += (bbounds[3]-lbounds[3] + self['boxBorder']
  137. - dropValue)
  138. elif self['boxPlacement'] == 'above': #above
  139. newpos[2] += bbounds[3]-lbounds[3] - self['boxBorder'] - ibw[1]
  140. else: #below
  141. newpos[2] += bbounds[2]-lbounds[2] + self['boxBorder'] + ibw[1]
  142. self.indicator.setPos(newpos[0],newpos[1],newpos[2])
  143. def commandFunc(self, event):
  144. self['indicatorValue'] = 1 - self['indicatorValue']
  145. if self.colors != None:
  146. self.component('indicator')['image_color'] = self.colors[self['indicatorValue']]
  147. if self['command']:
  148. # Pass any extra args to command
  149. apply(self['command'], [self['indicatorValue']] + self['extraArgs'])
  150. def setIndicatorValue(self):
  151. self.component('indicator').guiItem.setState(self['indicatorValue'])
  152. if self.colors != None:
  153. self.component('indicator')['image_color'] = self.colors[self['indicatorValue']]