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