blob: 8c9d7dbd48153b4a5579d6212730f9701ec14c84 [file] [log] [blame]
emayecs5656b2b2021-08-04 12:44:13 -04001#!/usr/bin/env python3
emayecs5966a532021-07-29 10:07:02 -04002#
3#--------------------------------------------------------
emayecs14748312021-08-05 14:21:26 -04004# Help Window for the Project manager
emayecs5966a532021-07-29 10:07:02 -04005#
6#--------------------------------------------------------
7# Written by Tim Edwards
8# efabless, inc.
9# September 12, 2016
10# Version 0.1
11#--------------------------------------------------------
12
13import re
14import tkinter
15from tkinter import ttk
16
17class HelpWindow(tkinter.Toplevel):
emayecs14748312021-08-05 14:21:26 -040018 """help window"""
emayecs5966a532021-07-29 10:07:02 -040019
20 def __init__(self, parent=None, fontsize = 11, *args, **kwargs):
21 '''See the __init__ for Tkinter.Toplevel.'''
22 tkinter.Toplevel.__init__(self, parent, *args, **kwargs)
23
24 s = ttk.Style()
25 s.configure('normal.TButton', font=('Helvetica', fontsize), border = 3, relief = 'raised')
26 self.protocol("WM_DELETE_WINDOW", self.close)
27
28 self.withdraw()
emayecs14748312021-08-05 14:21:26 -040029 self.title('Help')
emayecs5966a532021-07-29 10:07:02 -040030
31 self.helptitle = ttk.Label(self, style='title.TLabel', text = '(no text)')
32 self.helptitle.grid(column = 0, row = 0, sticky = "news")
33 self.helpbar = ttk.Separator(self, orient='horizontal')
34 self.helpbar.grid(column = 0, row = 1, sticky = "news")
35
36 self.hframe = tkinter.Frame(self)
37 self.hframe.grid(column = 0, row = 2, sticky = "news")
38 self.hframe.helpdisplay = ttk.Frame(self.hframe)
39 self.hframe.helpdisplay.pack(side = 'left', fill = 'both', expand = 'true')
40
41 self.hframe.helpdisplay.helptext = tkinter.Text(self.hframe.helpdisplay, wrap='word')
42 self.hframe.helpdisplay.helptext.pack(side = 'top', fill = 'both', expand = 'true')
43 # Add scrollbar to help window
44 self.hframe.scrollbar = ttk.Scrollbar(self.hframe)
45 self.hframe.scrollbar.pack(side='right', fill='y')
46 # attach help window to scrollbar
47 self.hframe.helpdisplay.helptext.config(yscrollcommand = self.hframe.scrollbar.set)
48 self.hframe.scrollbar.config(command = self.hframe.helpdisplay.helptext.yview)
49
50 self.hframe.toc = ttk.Treeview(self.hframe, selectmode='browse')
51 self.hframe.toc.bind('<<TreeviewSelect>>', self.toc_to_page)
52 self.hframe.toc.bind('<<TreeviewOpen>>', self.toc_toggle)
53 self.hframe.toc.bind('<<TreeviewClose>>', self.toc_toggle)
54 self.hframe.toc.tag_configure('title', font=('Helvetica', fontsize, 'bold italic'),
55 foreground = 'brown', anchor = 'center')
56 self.hframe.toc.heading('#0', text = "Table of Contents")
57
58 self.bbar = ttk.Frame(self)
59 self.bbar.grid(column = 0, row = 3, sticky = "news")
60 self.bbar.close_button = ttk.Button(self.bbar, text='Close',
61 command=self.close, style = 'normal.TButton')
62 self.bbar.close_button.grid(column=0, row=0, padx = 5)
63
64 self.bbar.prev_button = ttk.Button(self.bbar, text='Prev',
65 command=self.prevpage, style = 'normal.TButton')
66 self.bbar.prev_button.grid(column=1, row=0, padx = 5)
67
68 self.bbar.next_button = ttk.Button(self.bbar, text='Next',
69 command=self.nextpage, style = 'normal.TButton')
70 self.bbar.next_button.grid(column=2, row=0, padx = 5)
71
72 self.bbar.contents_button = ttk.Button(self.bbar, text='Table of Contents',
73 command=self.page_to_toc, style = 'normal.TButton')
74 self.bbar.contents_button.grid(column=3, row=0, padx = 5)
75
76 self.rowconfigure(0, weight=0)
77 self.rowconfigure(1, weight=0)
78 self.rowconfigure(2, weight=1)
79 self.rowconfigure(3, weight=0)
80 self.columnconfigure(0, weight=1)
81
82 # Help pages
83 self.pages = []
84 self.pageno = -1 # No page
85 self.toggle = False
86
87 def grid_configure(self, padx, pady):
88 pass
89
90 def redisplay(self):
91 # remove contents
92 if self.pageno >= 0 and self.pageno < len(self.pages):
93 self.hframe.helpdisplay.helptext.delete('1.0', 'end')
94 self.hframe.helpdisplay.helptext.insert('end', self.pages[self.pageno]['text'])
95 self.helptitle.configure(text = self.pages[self.pageno]['title'])
96
97 def toc_toggle(self, event):
98 self.toggle = True
99
100 def toc_to_page(self, event):
101 treeview = event.widget
102 selection = treeview.item(treeview.selection())
103
104 # Make sure any open/close callback is handled first!
105 self.update_idletasks()
106 if self.toggle:
107 # Item was opened or closed, so consider this a 'false select' and
108 # do not go to the page.
109 self.toggle = False
110 return
111
112 if 'values' in selection:
113 pagenum = selection['values'][0]
114 else:
115 print('Unknown page selected.')
116 pagenum = 0
117
118 # Display a page after displaying the table of contents
119 self.hframe.toc.pack_forget()
120 self.hframe.scrollbar.pack_forget()
121 self.hframe.helpdisplay.pack(side='left', fill='both', expand = 'true')
122 self.hframe.scrollbar.pack(side='right', fill='y')
123 self.hframe.scrollbar.config(command = self.hframe.helpdisplay.helptext.yview)
124 # Enable Prev and Next buttons
125 self.bbar.prev_button.configure(state='enabled')
126 self.bbar.next_button.configure(state='enabled')
127 # Redisplay
128 self.page(pagenum)
129
130 def page_to_toc(self):
131 # Display the table of contents after displaying a page
132 self.hframe.scrollbar.pack_forget()
133 self.hframe.helpdisplay.pack_forget()
134 self.hframe.toc.pack(side='left', fill='both', expand = 'true')
135 self.hframe.scrollbar.pack(side='right', fill='y')
136 self.hframe.scrollbar.config(command = self.hframe.toc.yview)
137 # Disable Prev and Next buttons
138 self.bbar.prev_button.configure(state='disabled')
139 self.bbar.next_button.configure(state='disabled')
140
141 # Simple add page with a single block of plain text
142 def add_page(self, toc_text, text_block):
143 newdict = {}
144 newdict['text'] = text_block
145 newdict['title'] = toc_text
146 self.pages.append(newdict)
147 newpageno = len(self.pages)
148 self.hframe.toc.insert('', 'end', text=str(newpageno) + '. ' + toc_text,
149 tag='title', value = newpageno - 1)
150 if self.pageno < 0:
151 self.pageno = 0 # First page
152
153 # Fill the help text from a file. The format of the file is:
154 # <page_num>
155 # <title>
156 # <text>
157 # '.'
158 # Text is multi-line and ends when '.' is encountered by itself
159
160 def add_pages_from_file(self, filename):
161 endpagerex = re.compile('^\.$')
162 newpagerex = re.compile('^[0-9\.]+$')
163 commentrex = re.compile('^[\-]+$')
164 hierarchy = ''
165 print('Loading help text from file ' + filename)
166 with open(filename, 'r') as f:
167 toc_text = []
168 page_text = []
169 for line in f:
170 if newpagerex.match(line) or endpagerex.match(line):
171 if toc_text and page_text:
172 newdict = {}
173 self.pages.append(newdict)
174 newpageno = len(self.pages)
175 if '.' in hierarchy:
176 pageinfo = hierarchy.rsplit('.', 1)
177 if pageinfo[1] == '':
178 parentid = ''
179 pageid = pageinfo[0]
180 else:
181 parentid = pageinfo[0]
182 pageid = pageinfo[1]
183 else:
184 parentid = ''
185 pageid = hierarchy
186 if parentid:
187 pageid = parentid + '.' + pageid
188 newdict['text'] = page_text
189 newdict['title'] = pageid + '. ' + toc_text
190 self.hframe.toc.insert(parentid, 'end',
191 text=newdict['title'], tag='title',
192 value = newpageno - 1, iid = pageid)
193 if newpagerex.match(line):
194 hierarchy = line.rstrip()
195 toc_text = []
196 elif not toc_text:
197 toc_text = line.rstrip()
198 page_text = []
199 elif not commentrex.match(line):
200 if not page_text:
201 page_text = line
202 else:
203 page_text += line
204
205 def nextpage(self):
206 # Go to next page
207 if self.pageno < len(self.pages) - 1:
208 self.pageno += 1
209 self.redisplay()
210
211 def prevpage(self):
212 # Go to previous page
213 if self.pageno > 0:
214 self.pageno -= 1
215 self.redisplay()
216
217 def page(self, pagenum):
218 # Go to indicated page
219 if pagenum >= 0 and pagenum < len(self.pages):
220 self.pageno = pagenum
221 self.redisplay()
222
223 def close(self):
224 # pop down help window
225 self.withdraw()
226
227 def open(self):
228 # pop up help window
229 self.deiconify()
230 self.lift()