target_tk_app_def.py
directory : D:\2018_py_proj\TkGridGUI\tkgridgui
Line Count : 1071
Line Clip Size : No Clipping
tab_of_notebook_changed Word MatchCase (1) 805
1
2
3 from __future__ import print_function
4 from __future__ import unicode_literals
5
6 from future import standard_library
7 standard_library.install_aliases()
8 from builtins import range
9 from builtins import object
10 from builtins import str
11 """
12 Define the target TK Application
13
14 Holds values of all controls on main GUI (grid_gui.GridGUI).
15 Provides Read and Save routines for full GUI definition.
16
17 Has not only widget types and locations from grid_notebook.NotebookGridDes,
18 but also any additional property assignments that were made by EditWin.
19 """
20
21 import os
22 import sys
23 import binascii
24
25
26 from tkinter import *
27 import tkinter.messagebox
28 from tkinter import Button, Canvas, Checkbutton, Entry, Frame, Label, LabelFrame
29 from tkinter import Listbox, Message, Radiobutton, Spinbox, Text
30 from tkinter import OptionMenu
31 from tkinter.ttk import Combobox, Progressbar, Separator, Treeview, Style, Notebook
32
33 from tkgridgui.edit_options import get_properties_dict, set_attribute_if_possible
34 from tkgridgui.edit_Dialog import Edit_Properties_Dialog
35
36 from tkgridgui.grid_notebook import ContainerControlsL, intCast
37 from tkgridgui.config_file import ConfigInterface
38 from tkgridgui.comp_tree import CNode, ComponentTree
39 from tkgridgui.preview_win_widgets import PW_Widget, SCROLL_Y_WIDGETS, SCROLL_X_WIDGETS, tkWidgetsD
40
41
42 TEXT_WIDTH_WIDGETS = set(['Button','Checkbutton','Combobox','Entry','Label',
43 'Radiobutton','Spinbox','Text',"Message", "Menubutton", "Tab"])
44
45 reqd_variable_typeD = {'Entry':'StringVar', 'OptionMenu':'StringVar', 'Combobox':'StringVar',
46 'Checkbutton':'StringVar', 'Menubutton':'StringVar',
47 'Radiobutton':'StringVar', 'Scale':'StringVar'}
48
49 DEBUG_PRINT = 0
50
51
52 def make_weights_dict_from_str( wt_str ):
53 """return a dict with index=row or col: value=wt"""
54 weightD = {}
55 sL = wt_str.split()
56 for s in sL:
57 cL = s.split(':')
58 rc = intCast( cL[0] )
59 wt = intCast( cL[-1] )
60 weightD[rc] = wt
61
62 return weightD
63
64 def add_entry_to_weight_str( rc_inp, wt_inp, current_str):
65 """
66 Reset string representation of tab_label row_weights or col_weights ("row:wt" or "col:wt")
67 If wt==0, then must remove any row entry other than 0.
68 If the row is already present with a different wt, must detect it and change wt.
69 """
70
71 currentD = make_weights_dict_from_str( current_str )
72
73 currentD[rc_inp] = wt_inp
74
75 full_str = ' '.join( ['%s:%s'%(rc,wt) for rc,wt in list(currentD.items()) if wt>0 ] )
76
77 return full_str
78
79 class Component( object ):
80 """Carries info for each widget in the target app."""
81
82 def __str__(self):
83 return '<%s, %s>'%(self.widget_name, self.tab_label)
84
85
86 def __init__(self, widget_type="Button", widget_name="Button_1", tab_label="Main",
87 row=1, col=1, target_app=None ):
88
89 self.widget_type = widget_type
90 self.widget_name = widget_name
91 self.tab_label = tab_label
92 self.row = row
93 self.col = col
94 self.target_app = target_app
95
96 self.default_tkOptionD = {}
97
98 self.user_tkOptionD = {}
99
100 self.user_tkOptionD['docstring'] = ''
101
102 if widget_type != 'Tab':
103 self.user_tkOptionD['sticky'] = ''
104 self.user_tkOptionD['columnspan'] = ''
105 self.user_tkOptionD['rowspan'] = ''
106
107
108 if self.widget_type in ContainerControlsL:
109 self.user_tkOptionD['row_weights'] = ''
110 self.user_tkOptionD['col_weights'] = ''
111
112
113
114 if widget_type == "Spinbox":
115 self.user_tkOptionD['from_'] = 1
116 self.user_tkOptionD['to'] = 10
117 elif widget_type == "Radiobutton":
118 self.user_tkOptionD['value'] = widget_name.split('_')[-1]
119 elif widget_type == "Combobox":
120 self.user_tkOptionD['values'] = 'Mine Yours Ours'
121 elif widget_type == "Separator":
122 self.user_tkOptionD['sticky'] = 'ew'
123 elif widget_type == 'Text':
124 self.user_tkOptionD['scrolly'] = 'yes'
125 elif widget_type in SCROLL_Y_WIDGETS:
126 self.user_tkOptionD['scrolly'] = 'no'
127
128 if widget_type in SCROLL_X_WIDGETS:
129 self.user_tkOptionD['scrollx'] = 'no'
130
131
132
133 if widget_type in TEXT_WIDTH_WIDGETS:
134 self.width_type = "text"
135 self.user_tkOptionD['text'] = widget_name
136
137 if widget_type == 'Text':
138 self.user_tkOptionD['width'] = 40
139 self.user_tkOptionD['height'] = 12
140 elif widget_type == "Message":
141 self.user_tkOptionD['width'] = 55
142 elif widget_type == "Tab":
143 pass
144 else:
145 self.user_tkOptionD['width'] = 15
146
147 elif widget_type == "Listbox":
148 self.user_tkOptionD['width'] = 18
149 self.user_tkOptionD['height'] = 12
150
151 elif widget_type == "OptionMenu":
152 self.user_tkOptionD['width'] = 20
153 self.user_tkOptionD['height'] = 2
154
155 elif widget_type == "Menubutton":
156 self.user_tkOptionD['width'] = 20
157 self.user_tkOptionD['height'] = 2
158
159 elif widget_type == "Treeview":
160 pass
161
162 elif widget_type == "Scale":
163 pass
164
165 elif widget_type == "Notebook":
166 self.width_type = "pixel"
167 self.user_tkOptionD['width'] = 400
168 self.user_tkOptionD['height'] = 300
169
170
171 self.user_tkOptionD['tab_labels'] = 'Mickey\nGoofy\nPopeye'
172
173 self.tab_nameL = []
174
175 else:
176 self.width_type = "pixel"
177 self.user_tkOptionD['width'] = 60
178 self.user_tkOptionD['height'] = 50
179
180 self.pw_widget = None
181 self.disp_frame = None
182
183
184 tkvar_type = reqd_variable_typeD.get( self.widget_type, '' )
185 self.tkvar = None
186 self.tkvar_list = None
187 if tkvar_type:
188 try:
189 if tkvar_type == "StringVar":
190 self.tkvar = StringVar()
191 elif tkvar_type == "IntVar":
192 self.tkvar = IntVar()
193 elif tkvar_type == "DoubleVar":
194 self.tkvar = DoubleVar()
195 else:
196 print("ERROR... do not recognize tk variable type = ", tkvar_type)
197
198 if widget_type=="Menubutton":
199 self.tkvar_list = []
200 for _ in range(3):
201 self.tkvar_list.append( StringVar() )
202 except:
203 print("WARNING... Failed to make ",tkvar_type," for ",self.widget_name)
204
205
206 def get_docstring(self):
207 """For documenting generated source code."""
208
209 loc_str = ' at %s(%s,%s)'%(self.tab_label, self.row, self.col)
210
211
212 if self.user_tkOptionD['docstring']:
213 return '%12s: '%self.widget_type + self.user_tkOptionD['docstring'] + ' :' + loc_str
214
215
216 text = self.user_tkOptionD.get('text', '')
217 if text == self.widget_name:
218 text = ''
219 if text:
220 return '%12s: '%self.widget_type + text + ' :' + loc_str
221
222
223 value = self.user_tkOptionD.get('value', '')
224 if value:
225 return '%12s: '%self.widget_type + value + ' :' + loc_str
226
227
228 values = self.user_tkOptionD.get('values', '')
229 if values:
230 return '%12s: '%self.widget_type + values + ' :' + loc_str
231
232
233 from_ = '%s'%self.user_tkOptionD.get('from_', '')
234 if from_:
235 return '%12s: '%self.widget_type + from_ + ' to ' + '%s'%self.user_tkOptionD.get('to', '') + ' :' + loc_str
236
237
238 return '%12s: '%self.widget_type + loc_str
239
240 def highlight_pw_widget(self):
241
242 if self.widget_type == "Tab":
243 notebook_name = self.tab_label
244 nb_obj = self.target_app.compObjD[ notebook_name ]
245 if nb_obj.pw_widget is not None:
246 nb_obj.pw_widget.pw_highlight_widget()
247
248 self.target_app.grid_notebook.grid_gui.select_preview_tab( self.widget_name )
249
250 elif self.pw_widget is not None:
251 self.pw_widget.pw_highlight_widget()
252
253
254 def highlight_grid_widget(self):
255 if self.target_app.grid_notebook is not None:
256 self.target_app.grid_notebook.highlight_grid_widget( self.widget_name )
257
258 def highlight_widget(self):
259 self.highlight_pw_widget()
260 self.highlight_grid_widget()
261
262 def unhighlight_pw_widget(self):
263 if self.widget_type == "Tab":
264 notebook_name = self.tab_label
265 nb_obj = self.target_app.compObjD[ notebook_name ]
266 if nb_obj.pw_widget is not None:
267 nb_obj.pw_widget.pw_unhighlight_widget()
268
269
270 elif self.pw_widget is not None:
271 self.pw_widget.pw_unhighlight_widget()
272
273 def unhighlight_grid_widget(self):
274 if self.target_app.grid_notebook is not None:
275 self.target_app.grid_notebook.unhighlight_grid_widget( self.widget_name )
276
277 def unhighlight_widget(self):
278 self.unhighlight_pw_widget()
279 self.unhighlight_grid_widget()
280
281 def widget_has_moved(self, tab_label="Main", row=1, col=1):
282 """Test for widget having been moved"""
283 if (tab_label, row, col) == (self.tab_label, self.row, self.col):
284 return False
285 else:
286 return True
287
288 def reset_location(self, tab_label="Main", row=1, col=1):
289 self.tab_label = tab_label
290 self.row = row
291 self.col = col
292
293 def maybe_make_widget(self, disp_frame):
294 """If not already created, create the pw_widget"""
295
296
297 if self.pw_widget is None:
298
299 self.disp_frame = disp_frame
300
301
302 self.pw_widget = PW_Widget( disp_frame, self )
303
304 self.set_widget_tk_properties()
305
306
307 self.pw_widget.native_widget.bind("<Button-3>", self.Widget_Right_Click)
308
309 return True
310 else:
311 return False
312
313 def Widget_Right_Click(self, __event):
314
315
316
317 nb_obj = self.target_app.grid_notebook
318 nb_obj.set_current_tab_by_label( self.tab_label )
319
320 self.highlight_widget()
321
322
323 dialogOptionsD = {}
324 for key,val in list(self.default_tkOptionD.items()):
325 dialogOptionsD[key] = (val, "def.")
326
327 for key,val in list(self.user_tkOptionD.items()):
328 dialogOptionsD[key] = (val, "USER VALUE")
329
330 dialogOptionsD['child_widget_list'] = self.target_app.get_names_of_containers_widgets( self.widget_name )
331
332
333 (tab_label, rtarg, col_target, placementWidgetType, label) = \
334 self.target_app.grid_notebook.label_obj_from_nameD[ self.widget_name ]
335
336 self.target_app.grid_notebook.current_label_being_edited = label
337
338 dialog = Edit_Properties_Dialog(self.target_app.grid_notebook.master, self.widget_name, dialogOptionsD=dialogOptionsD)
339
340 self.target_app.grid_notebook.current_label_being_edited = None
341
342 self.unhighlight_widget()
343
344 if dialog.result is not None:
345
346 if ("DeleteWidget" in dialog.result) and (dialog.result["DeleteWidget"]=="yes"):
347
348 if self.widget_type in ContainerControlsL:
349
350 self.target_app.removeContainerByName( self.widget_name )
351 else:
352
353
354 self.target_app.grid_notebook.delete_widget_by_name( self.widget_name )
355
356 self.target_app.delComponentByName( self.widget_name )
357
358 else:
359
360
361 self.user_tkOptionD.update( dialog.result )
362 self.set_user_properties()
363
364
365
366
367
368
369
370 if self.widget_type == "Canvas":
371 self.pw_widget.native_widget.delete( 'all' )
372 w = int(self.user_tkOptionD['width'])
373 h = int(self.user_tkOptionD['height'])
374 self.pw_widget.native_widget.create_text(w//2,h//2, text=self.widget_name,
375 fill="black", width=w, anchor='center')
376
377 if self.target_app.PreviewWin is not None:
378 self.target_app.PreviewWin.maybe_resize_preview_win()
379
380 def destroy_preview_widget(self):
381 """destroy pw_widget if present"""
382 if self.pw_widget is not None:
383 self.pw_widget.destroy()
384 self.pw_widget = None
385 self.disp_frame = None
386
387 def set_widget_tk_properties(self):
388
389 if self.pw_widget is None:
390 return
391
392
393
394
395
396
397
398
399
400
401
402 self.pw_widget.set_native_widget_attr()
403
404
405 try:
406 self.pw_widget.native_widget.delete(0, END)
407 except:
408 pass
409 try:
410 self.pw_widget.native_widget.insert(END, self.widget_name)
411 except:
412 pass
413
414 def set_user_properties(self):
415
416 self.pw_widget.set_native_widget_attr()
417
418
419
420
421
422
423
424 def get_property(self, attr_name):
425 if attr_name in self.user_tkOptionD:
426 return self.user_tkOptionD[ attr_name ]
427
428 if attr_name in self.default_tkOptionD:
429 return self.default_tkOptionD[ attr_name ]
430 return None
431
432 def set_a_row_weight(self, row_inp, wt_inp):
433 """container objects might have weights on rows and columns"""
434 self.user_tkOptionD['row_weights'] = add_entry_to_weight_str( row_inp, wt_inp, self.user_tkOptionD['row_weights'])
435
436 def set_a_col_weight(self, col_inp, wt_inp):
437 """container objects might have weights on rows and columns"""
438 self.user_tkOptionD['col_weights'] = add_entry_to_weight_str( col_inp, wt_inp, self.user_tkOptionD['col_weights'])
439
440 class TargetTkAppDef( object ):
441
442 def __init__(self, name='myApp', PreviewWin=None, grid_notebook=None ):
443
444 self.name = name
445
446 self.PreviewWin = PreviewWin
447 self.grid_notebook = grid_notebook
448 self.init_properties()
449
450
451 self.crc_reference = self.get_model_crc()
452
453 def init_properties(self):
454
455 self.app_attrD = {'name':self.name,'x':350, 'y':20, 'width':300, 'height':300,
456 'guitype':'main', 'hideokbutton':'no',
457 'hasmenu':'no',
458 'menu':'File\n New\n Open\n Save\n\n Exit\nHelp\n Sounds\n Moo\n Meow',
459 'add_menu_ctrl_keys':'yes',
460 'hasstatusbar':'no','hasstddialmess':'no', 'hasstddialfile':'no',
461 'hasstddialcolor':'no', 'hasstdalarm':'no', 'resizable':'yes',
462 'row_weights':'', 'col_weights':''}
463
464 self.tkOptionD = {}
465
466
467 self.compObjD = {}
468
469 self.tab_ownerD = {}
470
471 def reset_crc_reference(self):
472 """When a model is first read, or after it is saved, reset the crc_reference."""
473 self.crc_reference = self.get_model_crc()
474
475 def model_has_changed(self):
476 """Returns True if the model has changed (i.e. CRC no longer matches.)"""
477 return self.crc_reference != self.get_model_crc()
478
479 def get_model_crc(self):
480 """Use a calculated cylic redundancy check (CRC) to detect changes to model."""
481 sL = []
482
483 for key in sorted(dir(self), key=lambda s: s.lower()):
484 if key.startswith('__') or key in ('PreviewWin','grid_notebook','crc_reference'):
485 pass
486 else:
487 val = getattr(self, key)
488 if type(val) in (int, dict, list, float, str, type(None)):
489
490 sL.append( repr(val) )
491
492 for widget_name in sorted(list(self.compObjD.keys()), key=lambda s: s.lower()):
493 c = self.compObjD[ widget_name ]
494
495 for key in sorted(dir(c), key=lambda s: s.lower()):
496 if key.startswith('__') or key in ('PreviewWin','grid_notebook'):
497 pass
498 else:
499 val = getattr(c, key)
500 if type(val) in (int, dict, list, float, str, type(None)):
501
502 sL.append( repr(val) )
503
504 s = ''.join(sL)
505
506 return binascii.crc32( binascii.a2b_qp(s) ) & 0xffffffff
507
508
509
510 def change_notebook_tab_label(self, tab_name_inp, tab_label_inp):
511 notebook_name = self.tab_ownerD[ tab_name_inp ]
512 nb_obj = self.compObjD[ notebook_name ]
513
514 for itab, (row, col, tab_name, tab_label) in enumerate( nb_obj.tab_nameL ):
515 if tab_name == tab_name_inp:
516 if tab_label_inp:
517 tab_label = tab_label_inp
518 nb_obj.tab_nameL[ itab ] = (row, col, tab_name_inp, tab_label)
519 break
520
521
522 nb_obj.tab_nameL = sorted( nb_obj.tab_nameL )
523 nb_obj.user_tkOptionD['tab_labels'] = '\n'.join( [t[3] for t in nb_obj.tab_nameL] )
524
525
526 def arrange_notebook_tabs(self, tab_name_inp, row_inp, col_inp):
527
528 notebook_name = self.tab_ownerD[ tab_name_inp ]
529 nb_obj = self.compObjD[ notebook_name ]
530
531 for itab, (row, col, tab_name, tab_label) in enumerate( nb_obj.tab_nameL ):
532 if tab_name == tab_name_inp:
533 nb_obj.tab_nameL[ itab ] = (row_inp, col_inp, tab_name_inp, tab_label)
534 break
535
536
537 nb_obj.tab_nameL = sorted( nb_obj.tab_nameL )
538 nb_obj.user_tkOptionD['tab_labels'] = '\n'.join( [t[3] for t in nb_obj.tab_nameL] )
539
540
541
542 if nb_obj.pw_widget:
543 nb_obj.pw_widget.destroy()
544 nb_obj.pw_widget = None
545
546
547 def add_tab_to_notebook(self, row, col, tab_name, notebook_name):
548 self.tab_ownerD[ tab_name ] = notebook_name
549
550
551 nb_obj = self.compObjD[ notebook_name ]
552
553 nb_obj.tab_nameL.append( (row, col, tab_name, tab_name) )
554
555
556
557 self.arrange_notebook_tabs( tab_name, row, col )
558
559
560 def get_tab_native_widget(self, tab_name ):
561 notebook_name = self.tab_ownerD[ tab_name ]
562 nb_obj = self.compObjD[ notebook_name ]
563
564
565 n = 0
566
567 for i, (row, col, t_name, tab_label) in enumerate( nb_obj.tab_nameL ):
568
569 if t_name == tab_name:
570 n = i
571 break
572
573
574 return nb_obj.pw_widget.tab_frameL[ n ]
575
576
577 def reinitialize(self):
578 """Delete everything and start over"""
579 self.destroy_all_preview_widgets()
580 self.del_all_components()
581 self.init_properties()
582
583 def get_a_full_desc_of_weights(self):
584 """
585 Returns a two dict of non-zero weights, a row dict and a column dict.
586 The indeces are of the form (tab_label, row) and (tab_label, col)
587 The values are the wt value
588 """
589 full_rowD = {}
590 full_colD = {}
591
592 rowD = make_weights_dict_from_str( self.app_attrD['row_weights'] )
593 for row,wt in list(rowD.items()):
594 full_rowD[ ("Main", row) ] = wt
595
596 colD = make_weights_dict_from_str( self.app_attrD['col_weights'] )
597 for col,wt in list(colD.items()):
598 full_colD[ ("Main", col) ] = wt
599
600
601 for widget_name, c in list(self.compObjD.items()):
602 if c.widget_type in ContainerControlsL:
603
604 rowD = make_weights_dict_from_str( c.user_tkOptionD['row_weights'] )
605 for row,wt in list(rowD.items()):
606 full_rowD[ (c.widget_name, row) ] = wt
607
608 colD = make_weights_dict_from_str( c.user_tkOptionD['col_weights'] )
609 for col,wt in list(colD.items()):
610 full_colD[ (c.widget_name, col) ] = wt
611
612
613
614 return full_rowD, full_colD
615
616 def set_a_row_weight(self, tab_label, row_inp, wt_inp):
617 if tab_label=="Main":
618 self.app_attrD['row_weights'] = add_entry_to_weight_str( row_inp, wt_inp, self.app_attrD['row_weights'])
619 else:
620 c = self.compObjD[ tab_label ]
621 c.user_tkOptionD['row_weights'] = add_entry_to_weight_str( row_inp, wt_inp, c.user_tkOptionD['row_weights'])
622
623 def set_a_col_weight(self, tab_label, col_inp, wt_inp):
624 if tab_label=="Main":
625 self.app_attrD['col_weights'] = add_entry_to_weight_str( col_inp, wt_inp, self.app_attrD['col_weights'])
626 else:
627 c = self.compObjD[ tab_label ]
628 c.user_tkOptionD['col_weights'] = add_entry_to_weight_str( col_inp, wt_inp, c.user_tkOptionD['col_weights'])
629
630 def setSpecialOption(self, name, value):
631 self.app_attrD[name] = value
632
633 def getSpecialOption(self, name ):
634 return self.app_attrD.get(name, '')
635
636 def set_PreviewWin(self, PreviewWin):
637 self.PreviewWin = PreviewWin
638
639 def set_Notebook( self, grid_notebook ):
640 self.grid_notebook = grid_notebook
641
642
643 def show_preview(self):
644 """Loops over all components, adds them to PreviewWin if they are new or have changed."""
645
646 if self.PreviewWin is None:
647 return
648
649 ct = ComponentTree()
650 for widget_name, c in list(self.compObjD.items()):
651 ct.add_node( CNode(widget_name, c.tab_label, c) )
652
653 containerD = {"Main":self.PreviewWin.prevFrame}
654
655 cnodeL = ct.get_ordered_components()
656
657
658
659
660
661
662 nb_tab_nameLD = {}
663 for cn in cnodeL:
664 c = cn.component
665 if c.widget_type == 'Notebook':
666 nb_tab_nameLD[c.widget_name] = []
667 elif c.widget_type == 'Tab':
668 nb_tab_nameLD[c.tab_label].append( (c.row, c.col, c.widget_name, c.user_tkOptionD['text']) )
669 nb_tab_nameLD[c.tab_label] = sorted( nb_tab_nameLD[c.tab_label] )
670
671
672
673 for cn in cnodeL:
674 c = cn.component
675
676
677
678 if c.widget_type == 'Tab':
679 self.tab_ownerD[ c.widget_name ] = c.tab_label
680 containerD[ c.widget_name ] = self.get_tab_native_widget( c.widget_name )
681 else:
682 if c.widget_type == 'Notebook':
683 c.tab_nameL = nb_tab_nameLD[ c.widget_name ]
684
685 parent_component = self.compObjD.get( c.tab_label , None )
686
687 c.maybe_make_widget( containerD[c.tab_label] )
688
689 if c.pw_widget:
690 self.PreviewWin.add_widget(c.row, c.col, c.pw_widget)
691 containerD[ c.widget_name ] = c.pw_widget.native_widget
692
693
694 if self.grid_notebook is not None:
695
696
697 self.grid_notebook.set_row_column_weights_from_target_app()
698
699
700 rowD, colD = self.get_a_full_desc_of_weights()
701
702 for (tab_label, row_target),wt in list(rowD.items()):
703 parent = containerD.get( tab_label, None )
704 if parent is not None:
705 parent.rowconfigure(row_target, weight=wt)
706
707
708 for (tab_label, col_target),wt in list(colD.items()):
709 parent = containerD.get( tab_label, None )
710 if parent is not None:
711 parent.columnconfigure(col_target, weight=wt)
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731 def destroy_all_preview_widgets(self):
732 """destroy pw_widget if present"""
733 for c in list(self.compObjD.values()):
734 if c.pw_widget is not None:
735 c.destroy_preview_widget()
736
737
738 def del_all_components(self):
739 for c in list(self.compObjD.values()):
740 c.destroy_preview_widget()
741 self.compObjD = {}
742
743
744 def delComponentByName(self, widget_name):
745 '''MUST have "widget_name" value in compObjD dictionary'''
746
747 if widget_name in self.compObjD:
748 c = self.compObjD[ widget_name ]
749 c.destroy_preview_widget()
750 del self.compObjD[ widget_name ]
751
752
753 def maybe_add_component(self, widget_type="Button", widget_name="Button_1", tab_label="Main",
754 row=1, col=1):
755 """If the component is not already in app, add it."""
756
757 if widget_name in self.compObjD:
758 c = self.compObjD[ widget_name ]
759
760 if c.widget_has_moved( tab_label=tab_label, row=row, col=col ):
761 c.destroy_preview_widget()
762 c.reset_location( tab_label=tab_label, row=row, col=col )
763 else:
764 c = Component( widget_type=widget_type, widget_name=widget_name, tab_label=tab_label,
765 row=row, col=col, target_app=self )
766 self.compObjD[ widget_name ] = c
767
768
769 if self.grid_notebook is not None:
770 if self.grid_notebook.dup_source_widget_name:
771 c_src = self.compObjD[ self.grid_notebook.dup_source_widget_name ]
772
773 for key,val in list(c_src.user_tkOptionD.items()):
774
775 if val != self.grid_notebook.dup_source_widget_name:
776 c.user_tkOptionD[key] = val
777
778 if widget_type == "Notebook":
779 c.grid_notebook = self.grid_notebook
780
781 def removeContainerByName(self, container_name):
782 """
783 container_name is a widget_name to be removed.
784 The approach is to collect the names of remaining components and rebuild the target_app.
785 """
786 del_child_nameL = self.get_names_of_containers_widgets( container_name )
787 del_child_nameL.append( container_name )
788
789
790 if container_name.startswith('Tab_'):
791 c_tab = self.compObjD[ container_name ]
792 notebook_name = c_tab.tab_label
793 c_nb = self.compObjD[ notebook_name ]
794 sL = c_nb.user_tkOptionD['tab_labels'].split('\n')
795 sL = [s for s in sL if s != container_name]
796 c_nb.user_tkOptionD['tab_labels'] = '\n'.join(sL)
797
798
799 cnodeL = self.get_ordered_components()
800
801
802 save_tkOptionD = self.tkOptionD.copy()
803 self.reinitialize()
804 self.grid_notebook.initialize_NotebookGridDes()
805 self.grid_notebook.notebook.bind("<<NotebookTabChanged>>", self.grid_notebook.grid_gui.tab_of_notebook_changed)
806
807 self.tkOptionD = save_tkOptionD
808
809
810
811 for cn in cnodeL:
812 c = cn.component
813 if c.widget_name not in del_child_nameL:
814
815
816
817 self.maybe_add_component( widget_type=c.widget_type, widget_name=c.widget_name,
818 tab_label=c.tab_label, row=c.row, col=c.col)
819
820 c_new = self.compObjD[ c.widget_name ]
821
822
823 for key, val in list(c.user_tkOptionD.items()):
824 if key == 'tab_labels':
825 val = val.replace('\\n', '\n')
826 c_new.user_tkOptionD[key] = val
827
828 elif key not in ['widget_type', 'tab_label', 'row', 'col']:
829 c_new.user_tkOptionD[key] = val
830
831
832 widgetL = []
833 for cn in cnodeL:
834 c = cn.component
835 if c.widget_name not in del_child_nameL:
836 widgetL.append( (c.widget_type, c.widget_name, c.tab_label, c.row, c.col) )
837
838 self.grid_notebook.set_complete_list_of_widgets( widgetL )
839
840 self.grid_notebook.repaint_all_labels()
841
842 self.grid_notebook.grid_gui.refresh_preview_win()
843 self.grid_notebook.grid_gui.restore_black_listbox()
844
845 def get_ordered_components(self):
846 """Return a complete list of all components in add-order."""
847
848 ct = ComponentTree()
849 for widget_name, c in list(self.compObjD.items()):
850 ct.add_node( CNode(widget_name, c.tab_label, c) )
851
852 cnodeL = ct.get_ordered_components()
853 return cnodeL
854
855 def get_names_of_containers_widgets(self, container_name):
856 """Return the widget_name value for all widgets in container_name."""
857
858 c_cont = self.compObjD[ container_name ]
859 if c_cont.widget_type not in ContainerControlsL:
860 return []
861
862 ct = ComponentTree()
863 for widget_name, c in list(self.compObjD.items()):
864 ct.add_node( CNode(widget_name, c.tab_label, c) )
865
866 cnodeL = ct.get_ordered_components()
867
868 child_tab_set = set([container_name])
869 child_name_set = set()
870 num_kids = 0
871
872 while True:
873 for cn in cnodeL:
874 c = cn.component
875
876 if c.tab_label in child_tab_set:
877 child_name_set.add( c.widget_name )
878
879 if c.widget_type in ContainerControlsL:
880 child_tab_set.add( c.widget_name )
881
882 if len(child_name_set) == num_kids:
883 break
884 num_kids = len(child_name_set)
885
886 return sorted( list(child_name_set) )
887
888
889 def readAppDefFile(self, readPathName):
890
891 def maybe_int( s ):
892 try:
893 result = int(s.strip())
894 except:
895 result = s
896 return result
897
898 if readPathName:
899 self.reinitialize()
900
901 fullpath = os.path.abspath( readPathName )
902 fname = os.path.basename( fullpath )
903 name = fname.split('.')[0]
904 suffix = fname.split('.')[1]
905 if suffix.lower() != 'def':
906 print( 'WARNING... Expected *.def file, got',fname )
907
908
909 cf = ConfigInterface( config_filename=fullpath )
910
911 infoD = cf.get_dictionary()
912
913 for sec_name in cf.get_sectionL():
914
915
916
917
918 D = infoD[sec_name]
919 for key,val in list(D.items()):
920 D[key] = maybe_int( val )
921
922 if sec_name=='app_attr':
923 for key,val in list(D.items()):
924 if key in ('menu', 'tablabels'):
925 val = val.replace('\\n', '\n')
926 val = val.replace('\\t', ' ')
927
928 if key in self.app_attrD:
929 self.app_attrD[key] = val
930 else:
931 self.tkOptionD[key] = val
932
933 else:
934 self.maybe_add_component( widget_type=D['widget_type'], widget_name=sec_name,
935 tab_label=D['tab_label'], row=D['row'], col=D['col'])
936
937 c = self.compObjD[ sec_name ]
938 for key, val in list(D.items()):
939 if key == 'tab_labels':
940 val = val.replace('\\n', '\n')
941 c.user_tkOptionD[key] = val
942
943
944 elif key not in ['widget_type', 'tab_label', 'row', 'col']:
945 c.user_tkOptionD[key] = val
946
947
948 if self.grid_notebook is not None:
949 self.grid_notebook.set_row_column_weights_from_target_app()
950
951
952 self.reset_crc_reference()
953
954 def saveAppDefFile(self, savePathName=''):
955
956 if savePathName:
957 if 1:
958
959 fullpath = os.path.abspath(savePathName)
960 fname = os.path.basename( fullpath )
961 name = fname.split('.')[0]
962 suffix = fname.split('.')[1]
963 if suffix.lower() != 'def':
964 print( 'ERROR... illegal file name',fname )
965 return 0
966
967 self.name = name
968 curdir = os.path.dirname( fullpath )
969 fName = os.path.normpath(curdir +'/'+ name + '.def')
970
971
972 if os.path.exists( fName ):
973 backup_fname = name + '.def.bak'
974 full_backup = os.path.abspath( backup_fname )
975
976 if os.path.exists( full_backup ):
977 os.remove( full_backup )
978 print('Deleted Previous Backup:', backup_fname)
979
980 print(" Created Backup File:",backup_fname)
981 os.rename( fName, full_backup)
982
983
984 if DEBUG_PRINT: print( 'app definition saved to',fName )
985 self.app_attrD['name'] = name
986
987
988
989
990 if self.PreviewWin is not None:
991 self.app_attrD['width'] = self.PreviewWin.winfo_width()
992 self.app_attrD['height'] = self.PreviewWin.winfo_height()
993 self.app_attrD['x'] = self.PreviewWin.winfo_x()
994 self.app_attrD['y'] = self.PreviewWin.winfo_y()
995 else:
996 print('WARNING... no PreviewWin for Save Info.')
997
998
999 cf = ConfigInterface( config_filename=fName )
1000
1001 for key, val in list(self.app_attrD.items()):
1002 if key == 'menu':
1003 val = val.replace('\n','\\n')
1004 val = val.replace('\t','\\t')
1005
1006 cf.set('app_attr', key, val)
1007
1008 keyL = sorted( self.compObjD.keys() )
1009 for key in keyL:
1010 c = self.compObjD[ key ]
1011
1012
1013 for a in ['widget_type', 'tab_label', 'row', 'col']:
1014 cf.set(c.widget_name, a, getattr(c, a))
1015
1016
1017 for a, val in list(c.user_tkOptionD.items()):
1018 if a=='sticky':
1019 if val:
1020 cf.set(c.widget_name, a, val)
1021 elif a == 'tab_labels':
1022 val = val.replace('\n','\\n')
1023 val = val.replace('\t','\\t')
1024 cf.set(c.widget_name, a, val)
1025
1026 else:
1027 cf.set(c.widget_name, a, val)
1028
1029
1030 cf.save_file()
1031
1032 self.reset_crc_reference()
1033
1034 return 1
1035
1036 else:
1037 print( 'ERROR... saving file:',savePathName )
1038 return 0
1039 else:
1040 print("ERROR... no file name in saveAppDefFile.")
1041 return 0
1042
1043
1044 if __name__ == "__main__":
1045
1046 fd = TargetTkAppDef( 'myTestApp' )
1047 fd.tkOptionD['background']='yellow'
1048
1049 N = (len( fd.compObjD )+2) * 20
1050 I = len( fd.compObjD ) + 1
1051 fd.maybe_add_component(widget_type="Button", widget_name="Button_1", tab_label="Main",
1052 row=1, col=1)
1053
1054
1055 fd.maybe_add_component(widget_type="Label", widget_name="Label_1", tab_label="Main",
1056 row=1, col=2)
1057
1058
1059 for obj in list(fd.compObjD.values()):
1060 print( 'for "%s" object "%s"'%(obj.widget_name, obj.widget_type) )
1061 if obj.default_tkOptionD:
1062 print('...default properties')
1063 for key,val in list(obj.default_tkOptionD.items()):
1064 print( key,val )
1065 print('...user properties')
1066 for key,val in list(obj.user_tkOptionD.items()):
1067 print( key,val )
1068 print()
1069
1070 print( 'fd.get_model_crc() =',fd.get_model_crc() )
1071