DirectFrame.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. """A DirectFrame is a basic DirectGUI component that acts as the base
  2. class for various other components, and can also serve as a basic
  3. container to hold other DirectGUI components.
  4. A DirectFrame can have:
  5. * A background texture (pass in path to image, or Texture Card)
  6. * A midground geometry item (pass in geometry)
  7. * A foreground text Node (pass in text string or OnscreenText)
  8. Each of these has 1 or more states. The same object can be used for
  9. all states or each state can have a different text/geom/image (for
  10. radio button and check button indicators, for example).
  11. See the :ref:`directframe` page in the programming manual for a more in-depth
  12. explanation and an example of how to use this class.
  13. """
  14. __all__ = ['DirectFrame']
  15. from panda3d.core import *
  16. from . import DirectGuiGlobals as DGG
  17. from .DirectGuiBase import *
  18. from .OnscreenImage import OnscreenImage
  19. from .OnscreenGeom import OnscreenGeom
  20. import sys
  21. if sys.version_info >= (3, 0):
  22. stringType = str
  23. else:
  24. stringType = basestring
  25. class DirectFrame(DirectGuiWidget):
  26. DefDynGroups = ('text', 'geom', 'image')
  27. def __init__(self, parent = None, **kw):
  28. # Inherits from DirectGuiWidget
  29. optiondefs = (
  30. # Define type of DirectGuiWidget
  31. ('pgFunc', PGItem, None),
  32. ('numStates', 1, None),
  33. ('state', self.inactiveInitState, None),
  34. # Frame can have:
  35. # A background texture
  36. ('image', None, self.setImage),
  37. # A midground geometry item
  38. ('geom', None, self.setGeom),
  39. # A foreground text node
  40. ('text', None, self.setText),
  41. # Change default value of text mayChange flag from 0
  42. # (OnscreenText.py) to 1
  43. ('textMayChange', 1, None),
  44. )
  45. # Merge keyword options with default options
  46. self.defineoptions(kw, optiondefs,
  47. dynamicGroups = DirectFrame.DefDynGroups)
  48. # Initialize superclasses
  49. DirectGuiWidget.__init__(self, parent)
  50. # Call option initialization functions
  51. self.initialiseoptions(DirectFrame)
  52. def destroy(self):
  53. DirectGuiWidget.destroy(self)
  54. def clearText(self):
  55. self['text'] = None
  56. self.setText()
  57. def setText(self, text=None):
  58. if text is not None:
  59. self['text'] = text
  60. # Determine if user passed in single string or a sequence
  61. if self['text'] == None:
  62. textList = (None,) * self['numStates']
  63. elif isinstance(self['text'], stringType):
  64. # If just passing in a single string, make a tuple out of it
  65. textList = (self['text'],) * self['numStates']
  66. else:
  67. # Otherwise, hope that the user has passed in a tuple/list
  68. textList = self['text']
  69. # Create/destroy components
  70. for i in range(self['numStates']):
  71. component = 'text' + repr(i)
  72. # If fewer items specified than numStates,
  73. # just repeat last item
  74. try:
  75. text = textList[i]
  76. except IndexError:
  77. text = textList[-1]
  78. if self.hascomponent(component):
  79. if text == None:
  80. # Destroy component
  81. self.destroycomponent(component)
  82. else:
  83. self[component + '_text'] = text
  84. else:
  85. if text == None:
  86. return
  87. else:
  88. from .OnscreenText import OnscreenText
  89. self.createcomponent(
  90. component, (), 'text',
  91. OnscreenText,
  92. (), parent = self.stateNodePath[i],
  93. text = text, scale = 1, mayChange = self['textMayChange'],
  94. sort = DGG.TEXT_SORT_INDEX,
  95. )
  96. def clearGeom(self):
  97. self['geom'] = None
  98. self.setGeom()
  99. def setGeom(self, geom=None):
  100. if geom is not None:
  101. self['geom'] = geom
  102. # Determine argument type
  103. geom = self['geom']
  104. if geom == None:
  105. # Passed in None
  106. geomList = (None,) * self['numStates']
  107. elif isinstance(geom, NodePath) or \
  108. isinstance(geom, stringType):
  109. # Passed in a single node path, make a tuple out of it
  110. geomList = (geom,) * self['numStates']
  111. else:
  112. # Otherwise, hope that the user has passed in a tuple/list
  113. geomList = geom
  114. # Create/destroy components
  115. for i in range(self['numStates']):
  116. component = 'geom' + repr(i)
  117. # If fewer items specified than numStates,
  118. # just repeat last item
  119. try:
  120. geom = geomList[i]
  121. except IndexError:
  122. geom = geomList[-1]
  123. if self.hascomponent(component):
  124. if geom == None:
  125. # Destroy component
  126. self.destroycomponent(component)
  127. else:
  128. self[component + '_geom'] = geom
  129. else:
  130. if geom == None:
  131. return
  132. else:
  133. self.createcomponent(
  134. component, (), 'geom',
  135. OnscreenGeom,
  136. (), parent = self.stateNodePath[i],
  137. geom = geom, scale = 1,
  138. sort = DGG.GEOM_SORT_INDEX)
  139. def clearImage(self):
  140. self['image'] = None
  141. self.setImage()
  142. def setImage(self, image=None):
  143. if image is not None:
  144. self['image'] = image
  145. # Determine argument type
  146. arg = self['image']
  147. if arg == None:
  148. # Passed in None
  149. imageList = (None,) * self['numStates']
  150. elif isinstance(arg, NodePath) or \
  151. isinstance(arg, Texture) or \
  152. isinstance(arg, stringType):
  153. # Passed in a single node path, make a tuple out of it
  154. imageList = (arg,) * self['numStates']
  155. else:
  156. # Otherwise, hope that the user has passed in a tuple/list
  157. if ((len(arg) == 2) and
  158. isinstance(arg[0], stringType) and
  159. isinstance(arg[1], stringType)):
  160. # Its a model/node pair of strings
  161. imageList = (arg,) * self['numStates']
  162. else:
  163. # Assume its a list of node paths
  164. imageList = arg
  165. # Create/destroy components
  166. for i in range(self['numStates']):
  167. component = 'image' + repr(i)
  168. # If fewer items specified than numStates,
  169. # just repeat last item
  170. try:
  171. image = imageList[i]
  172. except IndexError:
  173. image = imageList[-1]
  174. if self.hascomponent(component):
  175. if image == None:
  176. # Destroy component
  177. self.destroycomponent(component)
  178. else:
  179. self[component + '_image'] = image
  180. else:
  181. if image == None:
  182. return
  183. else:
  184. self.createcomponent(
  185. component, (), 'image',
  186. OnscreenImage,
  187. (), parent = self.stateNodePath[i],
  188. image = image, scale = 1,
  189. sort = DGG.IMAGE_SORT_INDEX)