Skip to content

Commit 2fb516d

Browse files
committed
Panda's ColorEntry is broken. move it here
so people dont have to update their pandas.
1 parent 09cbf1c commit 2fb516d

File tree

2 files changed

+348
-2
lines changed

2 files changed

+348
-2
lines changed

toontown/fixes/VectorWidgets.py

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
"""Currently, pandas verison of this is just broken."""
2+
3+
__all__ = ['VectorEntry', 'Vector2Entry', 'Vector3Entry', 'Vector4Entry', 'ColorEntry']
4+
5+
from direct.showbase.TkGlobal import *
6+
from direct.tkwidgets import Valuator
7+
import Pmw
8+
from tkinter.colorchooser import askcolor
9+
10+
11+
class VectorEntry(Pmw.MegaWidget):
12+
def __init__(self, parent = None, **kw):
13+
14+
# Default vector size
15+
DEFAULT_DIM = 3
16+
# Default value depends on *actual* vector size, test for user input
17+
DEFAULT_VALUE = [0.0] * kw.get('dim', DEFAULT_DIM)
18+
DEFAULT_LABELS = ['v[%d]' % x for x in range(kw.get('dim', DEFAULT_DIM))]
19+
20+
# Process options
21+
INITOPT = Pmw.INITOPT
22+
optiondefs = (
23+
('dim', DEFAULT_DIM, INITOPT),
24+
('value', DEFAULT_VALUE, INITOPT),
25+
('resetValue', DEFAULT_VALUE, None),
26+
('label_width', 12, None),
27+
('labelIpadx', 2, None),
28+
('command', None, None),
29+
('entryWidth', 8, self._updateEntryWidth),
30+
('relief', GROOVE, self._updateRelief),
31+
('bd', 2, self._updateBorderWidth),
32+
('text', 'Vector:', self._updateText),
33+
('min', None, self._updateValidate),
34+
('max', None, self._updateValidate),
35+
('numDigits', 2, self._setSigDigits),
36+
('type', 'floater', None),
37+
('state', 'normal', self._setState),
38+
)
39+
self.defineoptions(kw, optiondefs)
40+
41+
# Initialize superclass
42+
Pmw.MegaWidget.__init__(self, parent)
43+
44+
# Initialize value
45+
# Make sure its a list (and as a byproduct, make a distinct copy)
46+
self._value = list(self['value'])
47+
self['resetValue'] = self['value']
48+
self._floaters = None
49+
self.entryFormat = '%.2f'
50+
51+
# Get a handle on the parent container
52+
interior = self.interior()
53+
54+
# This does double duty as a menu button
55+
self._label = self.createcomponent('label', (), None,
56+
Menubutton, (interior,),
57+
text = self['text'],
58+
activebackground = '#909090')
59+
self.menu = self._label['menu'] = Menu(self._label)
60+
self.menu.add_command(label = 'Reset', command = self.reset)
61+
self.menu.add_command(label = 'Popup sliders', command = self.popupSliders)
62+
self._label.pack(side = LEFT, fill = X, ipadx = self['labelIpadx'])
63+
64+
self.variableList = []
65+
self.entryList = []
66+
for index in range(self['dim']):
67+
var = StringVar()
68+
self.variableList.append(var)
69+
# To set the configuration of all entrys in a vector use:
70+
# ve.configure(Entry_XXX = YYY)
71+
# To configure an individual entryfield's entry use:
72+
# ve.configure(entry0_XXX = YYY)
73+
entry = self.createcomponent(
74+
'entryField%d' % index,
75+
(('entry%d' % index,
76+
'entryField%d_entry' % index),),
77+
'Entry',
78+
Pmw.EntryField, (interior,),
79+
entry_justify = RIGHT,
80+
entry_textvariable = var,
81+
command = lambda s = self, i = index: s._entryUpdateAt(i))
82+
entry.pack(side = LEFT, expand = 1, fill = X)
83+
self.entryList.append(entry)
84+
85+
# To configure the floaterGroup use:
86+
# ve.configure(floaterGroup_XXX = YYY)
87+
# ve.configure(fGroup_XXX = YYY) or
88+
# To set the configuration all floaters in a group use:
89+
# ve.configure(Valuator_XXX = YYY)
90+
# To configure an individual floater in a group use:
91+
# ve.configure(floaterGroup_floater0_XXX = YYY) or
92+
# ve.configure(fGroup_floater0_XXX = YYY)
93+
self._floaters = self.createcomponent(
94+
'floaterGroup',
95+
(('fGroup', 'floaterGroup'),
96+
('valuator', 'floaterGroup_valuator'),), None,
97+
Valuator.ValuatorGroupPanel, (self.interior(),),
98+
dim = self['dim'],
99+
#title = self['text'],
100+
type = self['type'],
101+
command = self.set)
102+
# Note: This means the 'X' on the menu bar doesn't really destroy
103+
# the panel, just withdraws it. This is to avoid problems which occur
104+
# if the user kills the floaterGroup and then tries to pop it open again
105+
self._floaters.userdeletefunc(self._floaters.withdraw)
106+
self._floaters.withdraw()
107+
108+
109+
# Make sure entries are updated
110+
self.set(self['value'])
111+
112+
# Record entry color
113+
self.entryBackground = self.cget('Entry_entry_background')
114+
115+
# Make sure input variables processed
116+
self.initialiseoptions(VectorEntry)
117+
118+
def menu(self):
119+
return self.menu
120+
121+
def label(self):
122+
return self._label
123+
124+
def entry(self, index):
125+
return self.entryList[index]
126+
127+
def entryList(self):
128+
return self.entryList
129+
130+
def floaters(self):
131+
return self._floaters
132+
133+
def _clearFloaters(self):
134+
self._floaters.withdraw()
135+
136+
def _updateText(self):
137+
self._label['text'] = self['text']
138+
139+
def _updateRelief(self):
140+
self.interior()['relief'] = self['relief']
141+
142+
def _updateBorderWidth(self):
143+
self.interior()['bd'] = self['bd']
144+
145+
def _updateEntryWidth(self):
146+
self['Entry_entry_width'] = self['entryWidth']
147+
148+
def _setSigDigits(self):
149+
sd = self['numDigits']
150+
self.entryFormat = '%.' + '%d' % sd + 'f'
151+
self.configure(valuator_numDigits = sd)
152+
# And refresh value to reflect change
153+
for index in range(self['dim']):
154+
self._refreshEntry(index)
155+
156+
def _updateValidate(self):
157+
# Update entry field to respect new limits
158+
self.configure(Entry_validate = {
159+
'validator': 'real',
160+
'min': self['min'],
161+
'max': self['max'],
162+
'minstrict': 0,
163+
'maxstrict': 0})
164+
# Reflect changes in floaters
165+
self.configure(valuator_min = self['min'],
166+
valuator_max = self['max'])
167+
168+
def get(self):
169+
return self._value
170+
171+
def getAt(self, index):
172+
return self._value[index]
173+
174+
def set(self, value, fCommand = 1):
175+
if type(value) in (float, int):
176+
value = [value] * self['dim']
177+
for i in range(self['dim']):
178+
self._value[i] = value[i]
179+
self.variableList[i].set(self.entryFormat % value[i])
180+
self.action(fCommand)
181+
182+
def setAt(self, index, value, fCommand = 1):
183+
self.variableList[index].set(self.entryFormat % value)
184+
self._value[index] = value
185+
self.action(fCommand)
186+
187+
def _entryUpdateAt(self, index):
188+
entryVar = self.variableList[index]
189+
# Did we get a valid float?
190+
try:
191+
newVal = float(entryVar.get())
192+
except ValueError:
193+
return
194+
195+
# Clamp value
196+
if self['min'] is not None:
197+
if newVal < self['min']:
198+
newVal = self['min']
199+
if self['max'] is not None:
200+
if newVal > self['max']:
201+
newVal = self['max']
202+
203+
# Update vector's value
204+
self._value[index] = newVal
205+
206+
# refresh entry to reflect formatted value
207+
self._refreshEntry(index)
208+
209+
# Update the floaters and call the command
210+
self.action()
211+
212+
def _refreshEntry(self, index):
213+
self.variableList[index].set(self.entryFormat % self._value[index])
214+
self.entryList[index].checkentry()
215+
216+
def _refreshFloaters(self):
217+
if self._floaters:
218+
self._floaters.set(self._value, 0)
219+
220+
def action(self, fCommand = 1):
221+
self._refreshFloaters()
222+
if fCommand and (self['command'] != None):
223+
self['command'](self._value)
224+
225+
def reset(self):
226+
self.set(self['resetValue'])
227+
228+
def addMenuItem(self, label = '', command = None):
229+
self.menu.add_command(label = label, command = command)
230+
231+
def popupSliders(self):
232+
self._floaters.set(self.get()[:])
233+
self._floaters.show()
234+
235+
def _setState(self):
236+
if self['state'] == 'disabled':
237+
# Disable entry
238+
self.configure(Entry_entry_state = 'disabled')
239+
self.configure(Entry_entry_background = '#C0C0C0')
240+
# Disable floater Group scale
241+
self.component('fGroup').configure(
242+
valuator_state = 'disabled')
243+
# Disable floater group entry
244+
self.component('fGroup').configure(
245+
valuator_entry_state = 'disabled')
246+
self.component('fGroup').configure(
247+
valuator_entry_background = '#C0C0C0')
248+
else:
249+
# Disable entry
250+
self.configure(Entry_entry_state = 'normal')
251+
self.configure(Entry_entry_background = self.entryBackground)
252+
# Disable floater Group scale
253+
self.component('fGroup').configure(
254+
valuator_state = 'normal')
255+
# Disable floater group entry
256+
self.component('fGroup').configure(
257+
valuator_entry_state = 'normal')
258+
self.component('fGroup').configure(
259+
valuator_entry_background = self.entryBackground)
260+
261+
class Vector2Entry(VectorEntry):
262+
def __init__(self, parent = None, **kw):
263+
# Initialize options for the class
264+
optiondefs = (
265+
('dim', 2, Pmw.INITOPT),
266+
('fGroup_labels', ('X','Y','Z'), None),
267+
)
268+
self.defineoptions(kw, optiondefs)
269+
# Initialize the superclass, make sure dim makes it to superclass
270+
VectorEntry.__init__(self, parent, dim = self['dim'])
271+
# Needed because this method checks if self.__class__ is myClass
272+
# where myClass is the argument passed into inialiseoptions
273+
self.initialiseoptions(Vector2Entry)
274+
275+
class Vector3Entry(VectorEntry):
276+
def __init__(self, parent = None, **kw):
277+
# Initialize options for the class
278+
optiondefs = (
279+
('dim', 3, Pmw.INITOPT),
280+
('fGroup_labels', ('X','Y','Z'), None),
281+
)
282+
self.defineoptions(kw, optiondefs)
283+
# Initialize the superclass, make sure dim makes it to superclass
284+
VectorEntry.__init__(self, parent, dim = self['dim'])
285+
# Needed because this method checks if self.__class__ is myClass
286+
# where myClass is the argument passed into inialiseoptions
287+
self.initialiseoptions(Vector3Entry)
288+
289+
class Vector4Entry(VectorEntry):
290+
def __init__(self, parent = None, **kw):
291+
# Initialize options for the class
292+
optiondefs = (
293+
('dim', 4, Pmw.INITOPT),
294+
('fGroup_labels', ('X','Y','Z','W'), None),
295+
)
296+
self.defineoptions(kw, optiondefs)
297+
# Initialize the superclass, make sure dim makes it to superclass
298+
VectorEntry.__init__(self, parent, dim = self['dim'])
299+
# Needed because this method checks if self.__class__ is myClass
300+
# where myClass is the argument passed into inialiseoptions
301+
self.initialiseoptions(Vector4Entry)
302+
303+
class ColorEntry(VectorEntry):
304+
def __init__(self, parent = None, **kw):
305+
# Initialize options for the class (overriding some superclass options)
306+
optiondefs = (
307+
('dim', 4, Pmw.INITOPT),
308+
('type', 'slider', Pmw.INITOPT),
309+
('fGroup_labels', ('R','G','B','A'), None),
310+
('min', 0, None),
311+
('max', 255, None),
312+
('numDigits', 0, None),
313+
('valuator_resolution', 1.0, None),
314+
)
315+
self.defineoptions(kw, optiondefs)
316+
317+
# Initialize the superclass, make sure dim makes it to superclass
318+
VectorEntry.__init__(self, parent, dim = self['dim'])
319+
# Add menu item to popup color picker
320+
self.addMenuItem(
321+
'Popup color picker',
322+
command = lambda s = self: s.popupColorPicker())
323+
# Needed because this method checks if self.__class__ is myClass
324+
# where myClass is the argument passed into inialiseoptions
325+
self.initialiseoptions(ColorEntry)
326+
327+
def popupColorPicker(self):
328+
# Can pass in current color with: color = (255, 0, 0)
329+
color = askcolor(
330+
parent = self.interior(),
331+
# Initialize it to current color
332+
initialcolor = (
333+
int(self.get()[0]), int(self.get()[1]), int(self.get()[2]))
334+
)
335+
if color:
336+
self.set((color[0][0], color[0][1], color[0][2], self.get()[3]))
337+
338+
if __name__ == '__main__':
339+
root = Toplevel()
340+
root.title('Vector Widget demo')
341+
342+
ve = VectorEntry(root); ve.pack()
343+
v3e = Vector3Entry(root); v3e.pack()
344+
v4e = Vector4Entry(root); v4e.pack()
345+
ce = ColorEntry(root); ce.pack()

toontown/leveleditor/LevelEditor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# from whrandom import *
1616
# from random import *
1717
from direct.tkwidgets import Floater
18-
from direct.tkwidgets import VectorWidgets
18+
from toontown.fixes import VectorWidgets
1919
import string
2020
import os
2121
import glob
@@ -1649,6 +1649,7 @@ def addLandmark(self, landmarkType, specialType):
16491649
self.setCurrent('toon_landmark_texture', landmarkType)
16501650
# And create new landmark building
16511651
block = self.getNextLandmarkBlock()
1652+
print(landmarkType)
16521653
newDNALandmarkBuilding = DNALandmarkBuilding(
16531654
'tb' + block + ':' + landmarkType + '_DNARoot')
16541655
newDNALandmarkBuilding.setCode(landmarkType)
@@ -5104,7 +5105,7 @@ def __init__(self, levelEditor, parent = None, **kw):
51045105
self.notebook.setnaturalsize()
51055106

51065107
self.colorEntry = VectorWidgets.ColorEntry(
5107-
hull, text = 'Select Color',
5108+
hull, text = 'Select Color', value = (0, 0, 0, 255),
51085109
command = self.updateSelectedObjColor)
51095110
self.colorEntry.menu.add_command(
51105111
label = 'Save Color', command = self.levelEditor.saveColor)

0 commit comments

Comments
 (0)