pyvguicom 1.0.0__py3-none-any.whl → 1.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvguicom might be problematic. Click here for more details.
- pyvguicom/__init__.py +1 -0
- pyvguicom/browsewin.py +10 -11
- pyvguicom/custwidg.py +110 -0
- pyvguicom/pgbox.py +59 -118
- pyvguicom/pgbutt.py +3 -2
- pyvguicom/pgentry.py +183 -22
- pyvguicom/pggui.py +239 -55
- pyvguicom/pgsel.py +441 -0
- pyvguicom/pgsimp.py +34 -265
- pyvguicom/pgtests.py +128 -0
- pyvguicom/pgtextview.py +0 -1
- pyvguicom/pgutils.py +391 -405
- pyvguicom/pgwkit.py +36 -27
- pyvguicom/testbutt.py +27 -25
- pyvguicom/testcust.py +49 -0
- pyvguicom/testentry.py +105 -0
- pyvguicom/testgui.py +125 -0
- pyvguicom/testlettsel.py +98 -0
- pyvguicom/testmsgs.py +142 -0
- pyvguicom/testnums.py +7 -12
- pyvguicom/testroot.py +7 -6
- pyvguicom/testsimple.py +24 -29
- pyvguicom/testtests.py +79 -0
- pyvguicom/testtextv.py +5 -14
- pyvguicom/testutils.py +139 -0
- {pyvguicom-1.0.0.dist-info → pyvguicom-1.1.1.dist-info}/METADATA +11 -5
- pyvguicom-1.1.1.dist-info/RECORD +32 -0
- pyvguicom/sutil.py +0 -344
- pyvguicom-1.0.0.dist-info/RECORD +0 -23
- {pyvguicom-1.0.0.dist-info → pyvguicom-1.1.1.dist-info}/WHEEL +0 -0
- {pyvguicom-1.0.0.dist-info → pyvguicom-1.1.1.dist-info}/top_level.txt +0 -0
pyvguicom/pgsel.py
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
|
|
2
|
+
#!/usr/bin/python
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import gi
|
|
7
|
+
gi.require_version("Gtk", "3.0")
|
|
8
|
+
from gi.repository import Gtk
|
|
9
|
+
from gi.repository import Gdk
|
|
10
|
+
from gi.repository import GObject
|
|
11
|
+
from gi.repository import Pango
|
|
12
|
+
|
|
13
|
+
''' Simplified controls '''
|
|
14
|
+
|
|
15
|
+
gui_testmode = False
|
|
16
|
+
|
|
17
|
+
import pgutils, pggui
|
|
18
|
+
|
|
19
|
+
# ------------------------------------------------------------------------
|
|
20
|
+
# Letter selection control
|
|
21
|
+
|
|
22
|
+
class LetterNumberSel(Gtk.VBox):
|
|
23
|
+
|
|
24
|
+
''' Letter Number selector '''
|
|
25
|
+
|
|
26
|
+
def __init__(self, callb = None, font="Mono 13", pad = ""):
|
|
27
|
+
|
|
28
|
+
Gtk.VBox.__init__(self)
|
|
29
|
+
|
|
30
|
+
self.set_can_focus(True)
|
|
31
|
+
self.set_focus_on_click(True)
|
|
32
|
+
self.set_can_default(True)
|
|
33
|
+
|
|
34
|
+
self.callb = callb
|
|
35
|
+
|
|
36
|
+
self.frame = Gtk.Frame()
|
|
37
|
+
|
|
38
|
+
hbox3a = Gtk.HBox()
|
|
39
|
+
hbox3a.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
40
|
+
|
|
41
|
+
strx = "abcdefghijklmnopqrstuvwxyz"
|
|
42
|
+
self.simsel = internal_SimpleSel(strx, self.lettercb, font, pad)
|
|
43
|
+
#self.override_background_color(Gtk.StateFlags.FOCUSED, Gdk.RGBA(.9,.9,.9))
|
|
44
|
+
|
|
45
|
+
self.connect("key-press-event", self.simsel_key)
|
|
46
|
+
self.connect("key-release-event", self.simsel_key_rel)
|
|
47
|
+
|
|
48
|
+
hbox3a.pack_start(self.simsel, 0, 0, 0)
|
|
49
|
+
hbox3a.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
50
|
+
|
|
51
|
+
strn2 = ""
|
|
52
|
+
hbox3b = Gtk.HBox()
|
|
53
|
+
hbox3b.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
54
|
+
strn = "1234567890!@#$^*_-+"
|
|
55
|
+
self.simsel2 = internal_SimpleSel(strn, self.lettercb, font, pad)
|
|
56
|
+
hbox3b.pack_start(self.simsel2, 0, 0, 0)
|
|
57
|
+
|
|
58
|
+
self.simall = internal_AllSel("All", self.lettercb, font, pad)
|
|
59
|
+
hbox3b.pack_start(self.simall, 0, 0, 0)
|
|
60
|
+
hbox3b.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
61
|
+
|
|
62
|
+
self.simsel2.other = self.simsel
|
|
63
|
+
self.simsel.other = self.simsel2
|
|
64
|
+
|
|
65
|
+
self.simsel2.other2 = self.simall
|
|
66
|
+
self.simsel.other2 = self.simall
|
|
67
|
+
|
|
68
|
+
self.simall.other = self.simsel
|
|
69
|
+
self.simall.other2 = self.simsel2
|
|
70
|
+
|
|
71
|
+
self.curr = self.simsel
|
|
72
|
+
# Commit changes
|
|
73
|
+
self.simsel.exec_index(True)
|
|
74
|
+
|
|
75
|
+
self.hand_cursor = Gdk.Cursor(Gdk.CursorType.HAND2)
|
|
76
|
+
self.simsel.connect("enter_notify_event", self.enter_label)
|
|
77
|
+
self.simsel.connect("leave_notify_event", self.leave_label)
|
|
78
|
+
self.simsel2.connect("enter_notify_event", self.enter_label)
|
|
79
|
+
self.simsel2.connect("leave_notify_event", self.leave_label)
|
|
80
|
+
|
|
81
|
+
self.connect("focus_in_event", self.focus_label)
|
|
82
|
+
self.connect("focus_out_event", self.focus_out_label)
|
|
83
|
+
|
|
84
|
+
vbox = Gtk.VBox()
|
|
85
|
+
vbox.pack_start(hbox3a, 0, 0, False)
|
|
86
|
+
#vbox.pack_start(pggui.ySpacer(), 0, 0, False)
|
|
87
|
+
vbox.pack_start(hbox3b, 0, 0, False)
|
|
88
|
+
|
|
89
|
+
self.frame = Gtk.Frame()
|
|
90
|
+
self.frame.set_shadow_type(Gtk.ShadowType.NONE)
|
|
91
|
+
|
|
92
|
+
self.frame.add(vbox)
|
|
93
|
+
self.pack_start(self.frame, 0, 0, False)
|
|
94
|
+
|
|
95
|
+
def focus_label(self, arg, arg2):
|
|
96
|
+
#print("focus in")
|
|
97
|
+
self.frame.set_shadow_type(Gtk.ShadowType.OUT)
|
|
98
|
+
|
|
99
|
+
def focus_out_label(self, arg, arg2):
|
|
100
|
+
#print("focus out")
|
|
101
|
+
self.frame.set_shadow_type(Gtk.ShadowType.NONE)
|
|
102
|
+
|
|
103
|
+
def simsel_key_rel(self, arg, event):
|
|
104
|
+
if event.keyval == Gdk.KEY_Return or event.keyval == Gdk.KEY_space:
|
|
105
|
+
return True
|
|
106
|
+
|
|
107
|
+
def simsel_key(self, arg, event):
|
|
108
|
+
|
|
109
|
+
# print(event.keyval)
|
|
110
|
+
|
|
111
|
+
if event.keyval == Gdk.KEY_Left:
|
|
112
|
+
self.curr.idx -= 1
|
|
113
|
+
if self.curr.idx < 0:
|
|
114
|
+
#print("Skip left")
|
|
115
|
+
if self.curr == self.simsel:
|
|
116
|
+
self.curr = self.simall
|
|
117
|
+
self.curr.idx = len(self.curr.textarr)-1
|
|
118
|
+
elif self.curr == self.simall:
|
|
119
|
+
self.curr = self.simsel2
|
|
120
|
+
self.curr.idx = len(self.curr.textarr)-1
|
|
121
|
+
else:
|
|
122
|
+
self.curr = self.simsel
|
|
123
|
+
self.curr.idx = len(self.curr.textarr)-1
|
|
124
|
+
self.curr.exec_index(True)
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
if event.keyval == Gdk.KEY_Right:
|
|
128
|
+
self.curr.idx += 1
|
|
129
|
+
if self.curr.idx >= len(self.curr.textarr):
|
|
130
|
+
#print("Skip right")
|
|
131
|
+
if self.curr == self.simsel:
|
|
132
|
+
self.curr = self.simsel2
|
|
133
|
+
self.curr.idx = 0
|
|
134
|
+
elif self.curr == self.simsel2:
|
|
135
|
+
self.curr = self.simall
|
|
136
|
+
self.curr.idx = 0
|
|
137
|
+
else:
|
|
138
|
+
self.curr = self.simsel
|
|
139
|
+
self.curr.idx = 0
|
|
140
|
+
self.curr.exec_index(True)
|
|
141
|
+
return True
|
|
142
|
+
|
|
143
|
+
if event.keyval == Gdk.KEY_Down:
|
|
144
|
+
if self.curr == self.simsel:
|
|
145
|
+
self.curr = self.simsel2
|
|
146
|
+
self.curr.exec_index(True)
|
|
147
|
+
else:
|
|
148
|
+
# Thu 02.May.2024 tab instead
|
|
149
|
+
self.emit("move-focus", Gtk.DirectionType.TAB_FORWARD)
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
if event.keyval == Gdk.KEY_Up:
|
|
153
|
+
if self.curr == self.simsel2:
|
|
154
|
+
self.curr = self.simsel
|
|
155
|
+
self.curr.exec_index(True)
|
|
156
|
+
else:
|
|
157
|
+
# Thu 02.May.2024 tab instead
|
|
158
|
+
self.emit("move-focus", Gtk.DirectionType.TAB_BACKWARD)
|
|
159
|
+
return True
|
|
160
|
+
|
|
161
|
+
if event.keyval == Gdk.KEY_Home:
|
|
162
|
+
self.curr.idx = 0
|
|
163
|
+
self.curr.exec_index(True)
|
|
164
|
+
return True
|
|
165
|
+
|
|
166
|
+
if event.keyval == Gdk.KEY_End:
|
|
167
|
+
self.curr.idx = len(self.curr.textarr) - 1
|
|
168
|
+
self.curr.exec_index(True)
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
if event.keyval == Gdk.KEY_Return or event.keyval == Gdk.KEY_space:
|
|
172
|
+
self.curr.exec_index(False)
|
|
173
|
+
return True
|
|
174
|
+
|
|
175
|
+
if event.keyval >= Gdk.KEY_a and event.keyval <= Gdk.KEY_z:
|
|
176
|
+
self.curr.idx = event.keyval - Gdk.KEY_a
|
|
177
|
+
self.curr.exec_index(True)
|
|
178
|
+
return True
|
|
179
|
+
|
|
180
|
+
def enter_label(self, arg, arg2):
|
|
181
|
+
#print("Enter")
|
|
182
|
+
self.get_window().set_cursor(self.hand_cursor)
|
|
183
|
+
|
|
184
|
+
def leave_label(self, arg, arg2):
|
|
185
|
+
#print("Leave")
|
|
186
|
+
self.get_window().set_cursor()
|
|
187
|
+
|
|
188
|
+
def lettercb(self, letter):
|
|
189
|
+
#print("LetterSel::letterx:", letter)
|
|
190
|
+
if self.callb:
|
|
191
|
+
self.callb(letter)
|
|
192
|
+
|
|
193
|
+
# Select character by index (do not call directly)
|
|
194
|
+
|
|
195
|
+
class internal_AllSel(Gtk.Label):
|
|
196
|
+
|
|
197
|
+
''' Internal class for selectors '''
|
|
198
|
+
|
|
199
|
+
def __init__(self, textx = " ", callb = None, font="Mono 13", pad = ""):
|
|
200
|
+
|
|
201
|
+
Gtk.Label.__init__(self, "")
|
|
202
|
+
|
|
203
|
+
self.set_events(Gdk.EventMask.ALL_EVENTS_MASK )
|
|
204
|
+
self.connect("button-press-event", self.area_button)
|
|
205
|
+
self.modify_font(Pango.FontDescription(font))
|
|
206
|
+
self.set_has_window(True)
|
|
207
|
+
self.text = textx
|
|
208
|
+
#self.textarr = [" " + textx + " ", "[" + textx + "]"]
|
|
209
|
+
self.textarr = [textx]
|
|
210
|
+
self.org = " " + textx + " "
|
|
211
|
+
self.callb = callb
|
|
212
|
+
self.lastsel = ""
|
|
213
|
+
self.lastidx = 0
|
|
214
|
+
self.other = None
|
|
215
|
+
self.other2 = None
|
|
216
|
+
self.pad = pad
|
|
217
|
+
self.newtext = pad
|
|
218
|
+
self.idx = -1
|
|
219
|
+
self.set_can_focus(True)
|
|
220
|
+
self.set_focus_on_click(True)
|
|
221
|
+
self.fill() #self.set_text(self.org)
|
|
222
|
+
|
|
223
|
+
def fill(self):
|
|
224
|
+
if self.idx == 0:
|
|
225
|
+
self.text = "[" + self.org[1:-1] + "]"
|
|
226
|
+
else:
|
|
227
|
+
self.text = " " + self.org[1:-1] + " "
|
|
228
|
+
self.set_text(self.text)
|
|
229
|
+
|
|
230
|
+
def area_button(self, but, event):
|
|
231
|
+
|
|
232
|
+
self.get_parent().get_parent().grab_focus()
|
|
233
|
+
#print("allbutt")
|
|
234
|
+
self.idx = 0
|
|
235
|
+
self.fill()
|
|
236
|
+
if 1: #not fromkey:
|
|
237
|
+
if self.callb:
|
|
238
|
+
self.callb(self.textarr[self.idx])
|
|
239
|
+
|
|
240
|
+
def exec_index(self, fromkey):
|
|
241
|
+
|
|
242
|
+
self.fill()
|
|
243
|
+
|
|
244
|
+
# Fill others, if allocated
|
|
245
|
+
if self.other:
|
|
246
|
+
self.other.idx = -1
|
|
247
|
+
self.other.fill()
|
|
248
|
+
if self.other2:
|
|
249
|
+
self.other2.idx = -1
|
|
250
|
+
self.other2.fill()
|
|
251
|
+
|
|
252
|
+
if not fromkey:
|
|
253
|
+
if self.callb:
|
|
254
|
+
self.callb(self.textarr[self.idx])
|
|
255
|
+
|
|
256
|
+
class internal_SimpleSel(Gtk.Label):
|
|
257
|
+
|
|
258
|
+
''' Internal class for selectors '''
|
|
259
|
+
|
|
260
|
+
def __init__(self, textx = " ", callb = None, font="Mono 13", pad = ""):
|
|
261
|
+
|
|
262
|
+
Gtk.Label.__init__(self, "")
|
|
263
|
+
|
|
264
|
+
self.set_events(Gdk.EventMask.ALL_EVENTS_MASK )
|
|
265
|
+
self.connect("button-press-event", self.area_button)
|
|
266
|
+
self.modify_font(Pango.FontDescription(font))
|
|
267
|
+
self.set_has_window(True)
|
|
268
|
+
|
|
269
|
+
self.callb = callb
|
|
270
|
+
|
|
271
|
+
self.lastsel = ""
|
|
272
|
+
self.lastidx = 0
|
|
273
|
+
self.other = None
|
|
274
|
+
self.other2 = None
|
|
275
|
+
self.pad = pad
|
|
276
|
+
self.newtext = pad
|
|
277
|
+
self.idx = 0
|
|
278
|
+
self.set_can_focus(True)
|
|
279
|
+
self.set_focus_on_click(True)
|
|
280
|
+
|
|
281
|
+
self.textarr = []
|
|
282
|
+
for aa in textx:
|
|
283
|
+
self.textarr.append(aa)
|
|
284
|
+
|
|
285
|
+
self.fill()
|
|
286
|
+
|
|
287
|
+
def area_button(self, but, event):
|
|
288
|
+
|
|
289
|
+
self.get_parent().get_parent().grab_focus()
|
|
290
|
+
www = self.get_allocation().width
|
|
291
|
+
pitch = float(www) / len(self.textarr)
|
|
292
|
+
#print("pitch", pitch, "www", www, "len",
|
|
293
|
+
# len(self.textarr), "event.x", event.x)
|
|
294
|
+
|
|
295
|
+
# Map point to position
|
|
296
|
+
self.idx = int(event.x / pitch)
|
|
297
|
+
#print("idxx:", idxx, self.idx)
|
|
298
|
+
self.exec_index(False)
|
|
299
|
+
|
|
300
|
+
def _fill2(self, xarr, xidx, padx):
|
|
301
|
+
''' Internal '''
|
|
302
|
+
cnt = 0
|
|
303
|
+
newtext = ""
|
|
304
|
+
for aa in xarr:
|
|
305
|
+
if cnt == xidx:
|
|
306
|
+
newtext += self.pad + "<span weight='bold' " \
|
|
307
|
+
"underline='double'>" + aa.upper() + "</span>"
|
|
308
|
+
else:
|
|
309
|
+
newtext += self.pad + aa
|
|
310
|
+
cnt += 1
|
|
311
|
+
newtext += self.pad
|
|
312
|
+
return newtext
|
|
313
|
+
|
|
314
|
+
def fill(self):
|
|
315
|
+
self.newtext = self._fill2(self.textarr, self.idx, self.pad)
|
|
316
|
+
self.set_markup(self.newtext)
|
|
317
|
+
|
|
318
|
+
def exec_index(self, fromkey):
|
|
319
|
+
|
|
320
|
+
if self.idx < 0:
|
|
321
|
+
self.idx = 0
|
|
322
|
+
if self.idx > len(self.textarr) - 1:
|
|
323
|
+
self.idx = len(self.textarr) - 1
|
|
324
|
+
#print("index:", self.idx)
|
|
325
|
+
self.fill()
|
|
326
|
+
|
|
327
|
+
# Fill others, if allocated
|
|
328
|
+
if self.other:
|
|
329
|
+
self.other.idx = -1
|
|
330
|
+
self.other.fill()
|
|
331
|
+
if self.other2:
|
|
332
|
+
self.other2.idx = -1
|
|
333
|
+
self.other2.fill()
|
|
334
|
+
|
|
335
|
+
if not fromkey:
|
|
336
|
+
if self.callb:
|
|
337
|
+
self.callb(self.textarr[self.idx])
|
|
338
|
+
|
|
339
|
+
class NumberSel(Gtk.Label):
|
|
340
|
+
|
|
341
|
+
''' Number selector. Give a proportional answer from mouse position '''
|
|
342
|
+
|
|
343
|
+
def __init__(self, text = " ", callb = None, font="Mono 13"):
|
|
344
|
+
self.text = text
|
|
345
|
+
self.callb = callb
|
|
346
|
+
self.axx = self.text.find("[All]")
|
|
347
|
+
Gtk.Label.__init__(self, text)
|
|
348
|
+
self.set_has_window(True)
|
|
349
|
+
self.set_events(Gdk.EventMask.ALL_EVENTS_MASK )
|
|
350
|
+
self.connect("button-press-event", self.area_button)
|
|
351
|
+
self.override_font(Pango.FontDescription(font))
|
|
352
|
+
self.lastsel = 0
|
|
353
|
+
|
|
354
|
+
def area_button(self, but, event):
|
|
355
|
+
|
|
356
|
+
#print("sss =", self.get_allocation().width)
|
|
357
|
+
#print("click", event.x, event.y)
|
|
358
|
+
|
|
359
|
+
prop = event.x / float(self.get_allocation().width)
|
|
360
|
+
idx = int(prop * len(self.text))
|
|
361
|
+
|
|
362
|
+
# Navigate to IDX
|
|
363
|
+
if self.text[idx] == " ":
|
|
364
|
+
idx += 1
|
|
365
|
+
else:
|
|
366
|
+
if self.text[idx-1] != " ":
|
|
367
|
+
idx -= 1
|
|
368
|
+
if idx >= len(self.text):
|
|
369
|
+
return
|
|
370
|
+
if idx < 0:
|
|
371
|
+
idx = 0
|
|
372
|
+
try:
|
|
373
|
+
# See of it is all
|
|
374
|
+
if self.axx >= 0:
|
|
375
|
+
if idx > self.axx:
|
|
376
|
+
#print("all", idx, self.text[idx-5:idx+7])
|
|
377
|
+
self.lastsel = "All"
|
|
378
|
+
self.newtext = self.text[:self.axx] + self.text[self.axx:].upper()
|
|
379
|
+
self.set_text(self.newtext)
|
|
380
|
+
else:
|
|
381
|
+
self.newtext = self.text[:self.axx] + self.text[self.axx:].lower()
|
|
382
|
+
self.set_text(self.newtext)
|
|
383
|
+
|
|
384
|
+
else:
|
|
385
|
+
self.lastsel = self.text[idx:idx+2]
|
|
386
|
+
#print("lastsel", self.lastsel)
|
|
387
|
+
self.newtext = self.text[:idx] + self.text[idx].upper() + self.text[idx+1:]
|
|
388
|
+
self.set_text(self.newtext)
|
|
389
|
+
|
|
390
|
+
if self.callb:
|
|
391
|
+
self.callb(self.lastsel)
|
|
392
|
+
|
|
393
|
+
except:
|
|
394
|
+
print(sys.exc_info())
|
|
395
|
+
|
|
396
|
+
class HourSel(Gtk.VBox):
|
|
397
|
+
|
|
398
|
+
''' Hour selector '''
|
|
399
|
+
|
|
400
|
+
def __init__(self, callb = None):
|
|
401
|
+
|
|
402
|
+
Gtk.VBox.__init__(self)
|
|
403
|
+
self.callb = callb
|
|
404
|
+
|
|
405
|
+
strx = " 8 10 12 14 16 "
|
|
406
|
+
hbox3a = Gtk.HBox()
|
|
407
|
+
hbox3a.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
408
|
+
self.simsel = NumberSel(strx, self.lettercb)
|
|
409
|
+
hbox3a.pack_start(self.simsel, 0, 0, 0)
|
|
410
|
+
hbox3a.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
411
|
+
|
|
412
|
+
self.pack_start(hbox3a, 0, 0, False)
|
|
413
|
+
|
|
414
|
+
def lettercb(self, letter):
|
|
415
|
+
#print("LetterSel::letterx:", letter)
|
|
416
|
+
if self.callb:
|
|
417
|
+
self.callb(letter)
|
|
418
|
+
|
|
419
|
+
class MinSel(Gtk.VBox):
|
|
420
|
+
|
|
421
|
+
''' Minute selector '''
|
|
422
|
+
|
|
423
|
+
def __init__(self, callb = None):
|
|
424
|
+
|
|
425
|
+
Gtk.VBox.__init__(self)
|
|
426
|
+
self.callb = callb
|
|
427
|
+
|
|
428
|
+
strx = " 0 10 20 30 40 50 "
|
|
429
|
+
hbox3a = Gtk.HBox()
|
|
430
|
+
hbox3a.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
431
|
+
self.simsel = NumberSel(strx, self.lettercb)
|
|
432
|
+
hbox3a.pack_start(self.simsel, 0, 0, 0)
|
|
433
|
+
hbox3a.pack_start(Gtk.Label(label=" "), 1, 1, 0)
|
|
434
|
+
|
|
435
|
+
self.pack_start(hbox3a, 0, 0, False)
|
|
436
|
+
|
|
437
|
+
def lettercb(self, letter):
|
|
438
|
+
#print("LetterSel::letterx:", letter)
|
|
439
|
+
if self.callb:
|
|
440
|
+
self.callb(letter)
|
|
441
|
+
|