emayecs | 5656b2b | 2021-08-04 12:44:13 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
emayecs | 5966a53 | 2021-07-29 10:07:02 -0400 | [diff] [blame] | 2 | # |
| 3 | # Simple ttk treeview with split view, scrollbar, and |
| 4 | # row of callback buttons |
| 5 | |
| 6 | import os |
| 7 | import re |
| 8 | import itertools |
| 9 | |
| 10 | import tkinter |
| 11 | from tkinter import ttk |
| 12 | |
| 13 | #------------------------------------------------------ |
| 14 | # Tree view used as a multi-column list box |
| 15 | #------------------------------------------------------ |
| 16 | |
| 17 | class TreeViewSplit(ttk.Frame): |
| 18 | def __init__(self, parent, fontsize=11, *args, **kwargs): |
| 19 | ttk.Frame.__init__(self, parent, *args, **kwargs) |
| 20 | s = ttk.Style() |
| 21 | s.configure('normal.TLabel', font=('Helvetica', fontsize)) |
| 22 | s.configure('title.TLabel', font=('Helvetica', fontsize, 'bold')) |
| 23 | s.configure('normal.TButton', font=('Helvetica', fontsize), |
| 24 | border = 3, relief = 'raised') |
| 25 | s.configure('Treeview.Heading', font=('Helvetica', fontsize, 'bold')) |
| 26 | s.configure('Treeview.Column', font=('Helvetica', fontsize)) |
| 27 | self.fontsize = fontsize |
| 28 | |
| 29 | # Last item is a list of 2-item lists, each containing the name of a button |
| 30 | # to place along the button bar at the bottom, and a callback function to |
| 31 | # run when the button is pressed. |
| 32 | |
| 33 | def populate(self, title1="", item1list=[], title2="", item2list=[], buttons=[], height=10): |
| 34 | self.item1list = item1list[:] |
| 35 | self.item2list = item2list[:] |
| 36 | columns = [0, 1] |
| 37 | |
| 38 | treeFrame = ttk.Frame(self) |
| 39 | treeFrame.pack(side='top', padx=5, pady=5, fill='both', expand='true') |
| 40 | |
| 41 | scrollBar = ttk.Scrollbar(treeFrame) |
| 42 | scrollBar.pack(side='right', fill='y') |
| 43 | self.treeView = ttk.Treeview(treeFrame, selectmode='browse', columns=columns, height=height) |
| 44 | self.treeView.pack(side='left', fill='both', expand='true') |
| 45 | scrollBar.config(command=self.treeView.yview) |
| 46 | self.treeView.config(yscrollcommand=scrollBar.set) |
| 47 | self.treeView.column('#0', width=120, stretch='false') |
| 48 | self.treeView.heading(0, text=title1, anchor='w') |
| 49 | self.treeView.heading(1, text=title2, anchor='w') |
| 50 | buttonFrame = ttk.Frame(self) |
| 51 | buttonFrame.pack(side='bottom', fill='x') |
| 52 | |
| 53 | self.treeView.tag_configure('select',background='darkslategray',foreground='white') |
| 54 | |
| 55 | # Test type tags |
| 56 | self.treeView.tag_configure('error', font=('Helvetica', self.fontsize - 1), foreground = 'red') |
| 57 | self.treeView.tag_configure('clean', font=('Helvetica', self.fontsize - 1), foreground = 'green3') |
| 58 | self.treeView.tag_configure('normal', font=('Helvetica', self.fontsize - 1), foreground = 'black') |
| 59 | self.treeView.tag_configure('prep', font=('Helvetica', self.fontsize, 'bold italic'), |
| 60 | foreground = 'black', anchor = 'center') |
| 61 | self.treeView.tag_configure('header1', font=('Helvetica', self.fontsize, 'bold italic'), |
| 62 | foreground = 'brown', anchor = 'center') |
| 63 | self.treeView.tag_configure('header2', font=('Helvetica', self.fontsize - 1, 'bold'), |
| 64 | foreground = 'blue', anchor = 'center') |
| 65 | self.treeView.tag_configure('header3', font=('Helvetica', self.fontsize - 1, 'bold'), |
| 66 | foreground = 'green2', anchor = 'center') |
| 67 | self.treeView.tag_configure('header4', font=('Helvetica', self.fontsize - 1), |
| 68 | foreground = 'purple', anchor = 'center') |
| 69 | |
| 70 | |
| 71 | self.func_buttons = [] |
| 72 | for button in buttons: |
| 73 | func = button[2] |
| 74 | # Each func_buttons entry is a list of two items; first is the |
| 75 | # button widget, and the second is a boolean that is True if the |
| 76 | # button is to be present always, False if the button is only |
| 77 | # present when there are entries in the itemlists. |
| 78 | self.func_buttons.append([ttk.Button(buttonFrame, text=button[0], |
| 79 | style = 'normal.TButton', |
| 80 | command = lambda func=func: self.func_callback(func)), |
| 81 | button[1]]) |
| 82 | |
| 83 | self.selectcallback = None |
| 84 | self.lastselected = None |
| 85 | self.lasttag = None |
| 86 | self.repopulate(item1list, item2list) |
| 87 | |
| 88 | def get_button(self, index): |
| 89 | if index >= 0 and index < len(self.func_buttons): |
| 90 | return self.func_buttons[index][0] |
| 91 | else: |
| 92 | return None |
| 93 | |
| 94 | def set_title(self, title): |
| 95 | self.treeView.heading('#0', text=title, anchor='w') |
| 96 | |
| 97 | def repopulate(self, item1list=[], item2list=[]): |
| 98 | |
| 99 | # Remove all children of treeview |
| 100 | self.treeView.delete(*self.treeView.get_children()) |
| 101 | |
| 102 | self.item1list = item1list[:] |
| 103 | self.item2list = item2list[:] |
| 104 | lines = max(len(self.item1list), len(self.item2list)) |
| 105 | |
| 106 | # Parse the information coming from comp.out. This is preferably |
| 107 | # handled from inside netgen, but that requires development in netgen. |
| 108 | # Note: A top-level group is denoted by an empty string. |
| 109 | |
| 110 | nested = [''] |
| 111 | if lines > 0: |
| 112 | # print("Create item ID 0 parent = ''") |
| 113 | self.treeView.insert(nested[-1], 'end', text='-', iid='0', |
| 114 | value=['Initialize', 'Initialize'], tags=['prep']) |
| 115 | nested.append('0') |
| 116 | tagstyle = 'header1' |
| 117 | |
| 118 | emptyrec = re.compile('^[\t ]*$') |
| 119 | subrex = re.compile('Subcircuit summary') |
| 120 | cktrex = re.compile('Circuit[\t ]+[12]:[\t ]+([^ \t]+)') |
| 121 | netrex = re.compile('NET mismatches') |
| 122 | devrex = re.compile('DEVICE mismatches') |
| 123 | seprex = re.compile('-----') |
| 124 | sumrex = re.compile('Netlists ') |
| 125 | matchrex = re.compile('.*\*\*Mismatch\*\*') |
| 126 | incircuit = False |
| 127 | watchgroup = False |
| 128 | groupnum = 0 |
| 129 | |
| 130 | for item1, item2, index in zip(self.item1list, self.item2list, range(lines)): |
| 131 | # Remove blank lines from the display |
| 132 | lmatch = emptyrec.match(item1) |
| 133 | if lmatch: |
| 134 | lmatch = emptyrec.match(item2) |
| 135 | if lmatch: |
| 136 | continue |
| 137 | index = str(index + 1) |
| 138 | # Parse text to determine how to structure and display it. |
| 139 | tagstyle = 'normal' |
| 140 | nextnest = None |
| 141 | lmatch = subrex.match(item1) |
| 142 | if lmatch: |
| 143 | nested = [''] # pop back to topmost level |
| 144 | nextnest = index |
| 145 | tagstyle = 'header1' |
| 146 | incircuit = False |
| 147 | watchgroup = False |
| 148 | groupnum = 0 |
| 149 | item1 = 'Layout compare' |
| 150 | item2 = 'Schematic compare' |
| 151 | cname1 = 'Layout' # Placeholder |
| 152 | cname2 = 'Schematic' # Placeholder |
| 153 | else: |
| 154 | lmatch = cktrex.match(item1) |
| 155 | if lmatch and not incircuit: |
| 156 | # Pick up circuit names and replace them in the title, then use them |
| 157 | # for all following titles. |
| 158 | cname1 = lmatch.group(1) |
| 159 | lmatch = cktrex.match(item2) |
| 160 | cname2 = lmatch.group(1) |
| 161 | print("Circuit names " + cname1 + " " + cname2) |
| 162 | # Rewrite title |
| 163 | cktitem = self.treeView.item(nested[-1], values=[cname1 + ' compare', |
| 164 | cname2 + ' compare']) |
| 165 | nextnest = index |
| 166 | tagstyle = 'header2' |
| 167 | incircuit = True |
| 168 | item1 = cname1 + ' Summary' |
| 169 | item2 = cname2 + ' Summary' |
| 170 | elif lmatch: |
| 171 | continue |
| 172 | else: |
| 173 | lmatch = netrex.match(item1) |
| 174 | if lmatch: |
| 175 | if watchgroup: |
| 176 | nested = nested[0:-1] |
| 177 | nested = nested[0:-1] |
| 178 | nextnest = index |
| 179 | tagstyle = 'header2' |
| 180 | groupnum = 1 |
| 181 | watchgroup = True |
| 182 | item1 = cname1 + ' Net mismatches' |
| 183 | item2 = cname2 + ' Net mismatches' |
| 184 | else: |
| 185 | lmatch = devrex.match(item1) |
| 186 | if lmatch: |
| 187 | if watchgroup: |
| 188 | nested = nested[0:-1] |
| 189 | nested = nested[0:-1] |
| 190 | nextnest = index |
| 191 | tagstyle = 'header2' |
| 192 | groupnum = 1 |
| 193 | watchgroup = True |
| 194 | item1 = cname1 + ' Device mismatches' |
| 195 | item2 = cname2 + ' Device mismatches' |
| 196 | else: |
| 197 | lmatch = seprex.match(item1) |
| 198 | if lmatch: |
| 199 | if watchgroup: |
| 200 | tagstyle = 'header3' |
| 201 | item1 = 'Group ' + str(groupnum) |
| 202 | item2 = 'Group ' + str(groupnum) |
| 203 | if groupnum > 1: |
| 204 | nested = nested[0:-1] |
| 205 | groupnum += 1 |
| 206 | nextnest = index |
| 207 | watchgroup = False |
| 208 | else: |
| 209 | if groupnum > 0: |
| 210 | watchgroup = True |
| 211 | continue |
| 212 | else: |
| 213 | lmatch = sumrex.match(item1) |
| 214 | if lmatch: |
| 215 | if watchgroup: |
| 216 | nested = nested[0:-1] |
| 217 | nested = nested[0:-1] |
| 218 | watchgroup = False |
| 219 | tagstyle = 'header2' |
| 220 | groupnum = 0 |
| 221 | |
| 222 | lmatch1 = matchrex.match(item1) |
| 223 | lmatch2 = matchrex.match(item2) |
| 224 | if lmatch1 or lmatch2: |
| 225 | tagstyle='error' |
| 226 | |
| 227 | # print("Create item ID " + str(index) + " parent = " + str(nested[-1])) |
| 228 | self.treeView.insert(nested[-1], 'end', text=index, iid=index, value=[item1, item2], |
| 229 | tags=[tagstyle]) |
| 230 | |
| 231 | if nextnest: |
| 232 | nested.append(nextnest) |
| 233 | |
| 234 | for button in self.func_buttons: |
| 235 | button[0].pack_forget() |
| 236 | |
| 237 | if lines == 0: |
| 238 | self.treeView.insert('', 'end', text='-', value=['(no items)', '(no items)']) |
| 239 | for button in self.func_buttons: |
| 240 | if button[1]: |
| 241 | button[0].pack(side='left', padx = 5) |
| 242 | else: |
| 243 | for button in self.func_buttons: |
| 244 | button[0].pack(side='left', padx = 5) |
| 245 | |
| 246 | # Special routine to pull in the JSON file data produced by netgen-1.5.72 |
| 247 | def json_repopulate(self, lvsdata): |
| 248 | |
| 249 | # Remove all children of treeview |
| 250 | self.treeView.delete(*self.treeView.get_children()) |
| 251 | |
| 252 | # Parse the information coming from comp.out. This is preferably |
| 253 | # handled from inside netgen, but that requires development in netgen. |
| 254 | # Note: A top-level group is denoted by an empty string. |
| 255 | |
| 256 | index = 0 |
| 257 | errtotal = {} |
| 258 | errtotal['net'] = 0 |
| 259 | errtotal['netmatch'] = 0 |
| 260 | errtotal['device'] = 0 |
| 261 | errtotal['devmatch'] = 0 |
| 262 | errtotal['property'] = 0 |
| 263 | errtotal['pin'] = 0 |
| 264 | ncells = len(lvsdata) |
| 265 | for c in range(0, ncells): |
| 266 | cellrec = lvsdata[c] |
| 267 | if c == ncells - 1: |
| 268 | topcell = True |
| 269 | else: |
| 270 | topcell = False |
| 271 | |
| 272 | errcell = {} |
| 273 | errcell['net'] = 0 |
| 274 | errcell['netmatch'] = 0 |
| 275 | errcell['device'] = 0 |
| 276 | errcell['devmatch'] = 0 |
| 277 | errcell['property'] = 0 |
| 278 | errcell['pin'] = 0; |
| 279 | |
| 280 | # cellrec is a dictionary. Parse the cell summary, then failing nets, |
| 281 | # devices, and properties, and finally pins. |
| 282 | |
| 283 | if 'name' in cellrec: |
| 284 | names = cellrec['name'] |
| 285 | cname1 = names[0] |
| 286 | cname2 = names[1] |
| 287 | |
| 288 | item1 = cname1 |
| 289 | item2 = cname2 |
| 290 | tagstyle = 'header1' |
| 291 | index += 1 |
| 292 | nest0 = index |
| 293 | self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2], |
| 294 | tags=[tagstyle]) |
| 295 | else: |
| 296 | # Some cells have pin comparison but are missing names (needs to be |
| 297 | # fixed in netgen. Regardless, if there's no name, then ignore. |
| 298 | continue |
| 299 | |
| 300 | if 'devices' in cellrec or 'nets' in cellrec: |
| 301 | item1 = cname1 + " Summary" |
| 302 | item2 = cname2 + " Summary" |
| 303 | tagstyle = 'header2' |
| 304 | index += 1 |
| 305 | nest1 = index |
| 306 | self.treeView.insert(nest0, 'end', text=index, iid=index, value=[item1, item2], |
| 307 | tags=[tagstyle]) |
| 308 | |
| 309 | if 'devices' in cellrec: |
| 310 | item1 = cname1 + " Devices" |
| 311 | item2 = cname2 + " Devices" |
| 312 | tagstyle = 'header3' |
| 313 | index += 1 |
| 314 | nest2 = index |
| 315 | self.treeView.insert(nest1, 'end', text=index, iid=index, value=[item1, item2], |
| 316 | tags=[tagstyle]) |
| 317 | |
| 318 | devices = cellrec['devices'] |
| 319 | devlist = [val for pair in zip(devices[0], devices[1]) for val in pair] |
| 320 | devpair = list(devlist[p:p + 2] for p in range(0, len(devlist), 2)) |
| 321 | for dev in devpair: |
| 322 | c1dev = dev[0] |
| 323 | c2dev = dev[1] |
| 324 | |
| 325 | item1 = c1dev[0] + "(" + str(c1dev[1]) + ")" |
| 326 | item2 = c2dev[0] + "(" + str(c2dev[1]) + ")" |
| 327 | |
| 328 | diffdevs = abs(c1dev[1] - c2dev[1]) |
| 329 | if diffdevs == 0: |
| 330 | tagstyle = 'normal' |
| 331 | else: |
| 332 | tagstyle = 'error' |
| 333 | errcell['device'] += diffdevs |
| 334 | if topcell: |
| 335 | errtotal['device'] += diffdevs |
| 336 | index += 1 |
| 337 | nest2 = index |
| 338 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 339 | value=[item1, item2], tags=[tagstyle]) |
| 340 | |
| 341 | if 'nets' in cellrec: |
| 342 | item1 = cname1 + " Nets" |
| 343 | item2 = cname2 + " Nets" |
| 344 | tagstyle = 'header3' |
| 345 | index += 1 |
| 346 | nest2 = index |
| 347 | self.treeView.insert(nest1, 'end', text=index, iid=index, value=[item1, item2], |
| 348 | tags=[tagstyle]) |
| 349 | |
| 350 | nets = cellrec['nets'] |
| 351 | |
| 352 | item1 = nets[0] |
| 353 | item2 = nets[1] |
| 354 | diffnets = abs(nets[0] - nets[1]) |
| 355 | if diffnets == 0: |
| 356 | tagstyle = 'normal' |
| 357 | else: |
| 358 | tagstyle = 'error' |
| 359 | errcell['net'] = diffnets |
| 360 | if topcell: |
| 361 | errtotal['net'] += diffnets |
| 362 | index += 1 |
| 363 | nest2 = index |
| 364 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 365 | value=[item1, item2], tags=[tagstyle]) |
| 366 | |
| 367 | if 'badnets' in cellrec: |
| 368 | badnets = cellrec['badnets'] |
| 369 | |
| 370 | if len(badnets) > 0: |
| 371 | item1 = cname1 + " Net Mismatches" |
| 372 | item2 = cname2 + " Net Mismatches" |
| 373 | tagstyle = 'header2' |
| 374 | index += 1 |
| 375 | nest1 = index |
| 376 | self.treeView.insert(nest0, 'end', text=index, iid=index, |
| 377 | value=[item1, item2], tags=[tagstyle]) |
| 378 | |
| 379 | groupnum = 0 |
| 380 | for group in badnets: |
| 381 | groupc1 = group[0] |
| 382 | groupc2 = group[1] |
| 383 | nnets = len(groupc1) |
| 384 | |
| 385 | groupnum += 1 |
| 386 | tagstyle = 'header3' |
| 387 | index += 1 |
| 388 | nest2 = index |
| 389 | item1 = "Group " + str(groupnum) + ' (' + str(nnets) + ' nets)' |
| 390 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 391 | value=[item1, item1], tags=[tagstyle]) |
| 392 | |
| 393 | tagstyle = 'error' |
| 394 | errcell['netmatch'] += nnets |
| 395 | if topcell: |
| 396 | errtotal['netmatch'] += nnets |
| 397 | |
| 398 | for netnum in range(0, nnets): |
| 399 | if netnum > 0: |
| 400 | item1 = "" |
| 401 | index += 1 |
| 402 | nest3 = index |
| 403 | self.treeView.insert(nest2, 'end', text=index, iid=index, |
| 404 | value=[item1, item1], tags=[tagstyle]) |
| 405 | |
| 406 | net1 = groupc1[netnum] |
| 407 | net2 = groupc2[netnum] |
| 408 | tagstyle = 'header4' |
| 409 | item1 = net1[0] |
| 410 | item2 = net2[0] |
| 411 | index += 1 |
| 412 | nest3 = index |
| 413 | self.treeView.insert(nest2, 'end', text=index, iid=index, |
| 414 | value=[item1, item2], tags=[tagstyle]) |
| 415 | |
| 416 | # Pad shorter device list to the length of the longer one |
| 417 | netdevs = list(itertools.zip_longest(net1[1], net2[1])) |
| 418 | for devpair in netdevs: |
| 419 | devc1 = devpair[0] |
| 420 | devc2 = devpair[1] |
| 421 | tagstyle = 'normal' |
| 422 | if devc1 and devc1[0] != "": |
| 423 | item1 = devc1[0] + '/' + devc1[1] + ' = ' + str(devc1[2]) |
| 424 | else: |
| 425 | item1 = "" |
| 426 | if devc2 and devc2[0] != "": |
| 427 | item2 = devc2[0] + '/' + devc2[1] + ' = ' + str(devc2[2]) |
| 428 | else: |
| 429 | item2 = "" |
| 430 | index += 1 |
| 431 | nest3 = index |
| 432 | self.treeView.insert(nest2, 'end', text=index, iid=index, |
| 433 | value=[item1, item2], tags=[tagstyle]) |
| 434 | |
| 435 | if 'badelements' in cellrec: |
| 436 | badelements = cellrec['badelements'] |
| 437 | |
| 438 | if len(badelements) > 0: |
| 439 | item1 = cname1 + " Device Mismatches" |
| 440 | item2 = cname2 + " Device Mismatches" |
| 441 | tagstyle = 'header2' |
| 442 | index += 1 |
| 443 | nest1 = index |
| 444 | self.treeView.insert(nest0, 'end', text=index, iid=index, |
| 445 | value=[item1, item2], tags=[tagstyle]) |
| 446 | |
| 447 | groupnum = 0 |
| 448 | for group in badelements: |
| 449 | groupc1 = group[0] |
| 450 | groupc2 = group[1] |
| 451 | ndevs = len(groupc1) |
| 452 | |
| 453 | groupnum += 1 |
| 454 | tagstyle = 'header3' |
| 455 | index += 1 |
| 456 | nest2 = index |
| 457 | item1 = "Group " + str(groupnum) + ' (' + str(ndevs) + ' devices)' |
| 458 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 459 | value=[item1, item1], tags=[tagstyle]) |
| 460 | |
| 461 | tagstyle = 'error' |
| 462 | errcell['devmatch'] += ndevs |
| 463 | if topcell: |
| 464 | errtotal['devmatch'] += ndevs |
| 465 | |
| 466 | for elemnum in range(0, ndevs): |
| 467 | if elemnum > 0: |
| 468 | item1 = "" |
| 469 | index += 1 |
| 470 | nest3 = index |
| 471 | self.treeView.insert(nest2, 'end', text=index, iid=index, |
| 472 | value=[item1, item1], tags=[tagstyle]) |
| 473 | |
| 474 | elem1 = groupc1[elemnum] |
| 475 | elem2 = groupc2[elemnum] |
| 476 | tagstyle = 'header4' |
| 477 | item1 = elem1[0] |
| 478 | item2 = elem2[0] |
| 479 | index += 1 |
| 480 | nest3 = index |
| 481 | self.treeView.insert(nest2, 'end', text=index, iid=index, |
| 482 | value=[item1, item2], tags=[tagstyle]) |
| 483 | |
| 484 | # Pad shorter pin list to the length of the longer one |
| 485 | elempins = list(itertools.zip_longest(elem1[1], elem2[1])) |
| 486 | for pinpair in elempins: |
| 487 | pinc1 = pinpair[0] |
| 488 | pinc2 = pinpair[1] |
| 489 | tagstyle = 'normal' |
| 490 | if pinc1 and pinc1[0] != "": |
| 491 | item1 = pinc1[0] + ' = ' + str(pinc1[1]) |
| 492 | else: |
| 493 | item1 = "" |
| 494 | if pinc2 and pinc2[0] != "": |
| 495 | item2 = pinc2[0] + ' = ' + str(pinc2[1]) |
| 496 | else: |
| 497 | item2 = "" |
| 498 | index += 1 |
| 499 | nest3 = index |
| 500 | self.treeView.insert(nest2, 'end', text=index, iid=index, |
| 501 | value=[item1, item2], tags=[tagstyle]) |
| 502 | |
| 503 | if 'properties' in cellrec: |
| 504 | properties = cellrec['properties'] |
| 505 | numproperr = len(properties) |
| 506 | if numproperr > 0: |
| 507 | item1 = cname1 + " Properties" |
| 508 | item2 = cname2 + " Properties" |
| 509 | tagstyle = 'header2' |
| 510 | index += 1 |
| 511 | nest1 = index |
| 512 | self.treeView.insert(nest0, 'end', text=index, iid=index, value=[item1, item2], |
| 513 | tags=[tagstyle]) |
| 514 | errcell['property'] = numproperr |
| 515 | errtotal['property'] += numproperr |
| 516 | |
| 517 | for prop in properties: |
| 518 | |
| 519 | if prop != properties[0]: |
| 520 | item1 = "" |
| 521 | index += 1 |
| 522 | nest2 = index |
| 523 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 524 | value=[item1, item1], tags=[tagstyle]) |
| 525 | |
| 526 | propc1 = prop[0] |
| 527 | propc2 = prop[1] |
| 528 | |
| 529 | tagstyle = 'header3' |
| 530 | item1 = propc1[0] |
| 531 | item2 = propc2[0] |
| 532 | index += 1 |
| 533 | nest2 = index |
| 534 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 535 | value=[item1, item2], tags=[tagstyle]) |
| 536 | |
| 537 | # Pad shorter property list to the length of the longer one |
| 538 | elemprops = list(itertools.zip_longest(propc1[1], propc2[1])) |
| 539 | for proppair in elemprops: |
| 540 | perrc1 = proppair[0] |
| 541 | perrc2 = proppair[1] |
| 542 | tagstyle = 'normal' |
| 543 | if perrc1 and perrc1[0] != "": |
| 544 | item1 = perrc1[0] + ' = ' + str(perrc1[1]) |
| 545 | else: |
| 546 | item1 = "" |
| 547 | if perrc2 and perrc2[0] != "": |
| 548 | item2 = perrc2[0] + ' = ' + str(perrc2[1]) |
| 549 | else: |
| 550 | item2 = "" |
| 551 | index += 1 |
| 552 | nest2 = index |
| 553 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 554 | value=[item1, item2], tags=[tagstyle]) |
| 555 | |
| 556 | if 'pins' in cellrec: |
| 557 | item1 = cname1 + " Pins" |
| 558 | item2 = cname2 + " Pins" |
| 559 | tagstyle = 'header2' |
| 560 | index += 1 |
| 561 | nest1 = index |
| 562 | self.treeView.insert(nest0, 'end', text=index, iid=index, value=[item1, item2], |
| 563 | tags=[tagstyle]) |
| 564 | |
| 565 | pins = cellrec['pins'] |
| 566 | pinlist = [val for pair in zip(pins[0], pins[1]) for val in pair] |
| 567 | pinpair = list(pinlist[p:p + 2] for p in range(0, len(pinlist), 2)) |
| 568 | for pin in pinpair: |
| 569 | item1 = re.sub('!$', '', pin[0].lower()) |
| 570 | item2 = re.sub('!$', '', pin[1].lower()) |
| 571 | if item1 == item2: |
| 572 | tagstyle = 'header4' |
| 573 | else: |
| 574 | tagstyle = 'error' |
| 575 | errcell['pin'] += 1 |
| 576 | if topcell: |
| 577 | errtotal['pin'] += 1 |
| 578 | index += 1 |
| 579 | nest2 = index |
| 580 | self.treeView.insert(nest1, 'end', text=index, iid=index, |
| 581 | value=[item1, item2], tags=[tagstyle]) |
| 582 | |
| 583 | allcellerror = errcell['net'] + errcell['device'] + errcell['property'] + errcell['pin'] + errcell['netmatch'] + errcell['devmatch'] |
| 584 | if allcellerror > 0: |
| 585 | item1 = 'Errors: Net = ' + str(errcell['net']) + ', Device = ' + str(errcell['device']) + ', Property = ' + str(errcell['property']) + ', Pin = ' + str(errcell['pin']) + ', Net match = ' + str(errcell['netmatch']) + ', Device match = ' + str(errcell['devmatch']) |
| 586 | tagstyle = 'error' |
| 587 | else: |
| 588 | item1 = 'LVS Clean' |
| 589 | tagstyle = 'clean' |
| 590 | |
| 591 | item2 = "" |
| 592 | index += 1 |
| 593 | nest0 = index |
| 594 | self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2], |
| 595 | tags=[tagstyle]) |
| 596 | |
| 597 | item1 = "Final LVS result:" |
| 598 | item2 = "" |
| 599 | tagstyle = 'header1' |
| 600 | index += 1 |
| 601 | nest0 = index |
| 602 | self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2], |
| 603 | tags=[tagstyle]) |
| 604 | |
| 605 | allerror = errtotal['net'] + errtotal['device'] + errtotal['property'] + errtotal['pin'] + errtotal['netmatch'] + errtotal['devmatch'] |
| 606 | if allerror > 0: |
| 607 | item1 = 'Errors: Net = ' + str(errtotal['net']) + ', Device = ' + str(errtotal['device']) + ', Property = ' + str(errtotal['property']) + ', Pin = ' + str(errtotal['pin']) + ', Net match = ' + str(errtotal['netmatch']) + ', Device match = ' + str(errtotal['devmatch']) |
| 608 | tagstyle = 'error' |
| 609 | else: |
| 610 | item1 = 'LVS Clean' |
| 611 | tagstyle = 'clean' |
| 612 | |
| 613 | item2 = "" |
| 614 | index += 1 |
| 615 | nest0 = index |
| 616 | self.treeView.insert('', 'end', text=index, iid=index, value=[item1, item2], |
| 617 | tags=[tagstyle]) |
| 618 | |
| 619 | for button in self.func_buttons: |
| 620 | button[0].pack_forget() |
| 621 | |
| 622 | if index == 0: |
| 623 | self.treeView.insert('', 'end', text='-', value=['(no items)', '(no items)']) |
| 624 | for button in self.func_buttons: |
| 625 | if button[1]: |
| 626 | button[0].pack(side='left', padx = 5) |
| 627 | else: |
| 628 | for button in self.func_buttons: |
| 629 | button[0].pack(side='left', padx = 5) |
| 630 | |
| 631 | # Return values from the treeview |
| 632 | def getlist(self): |
| 633 | return self.treeView.get_children() |
| 634 | |
| 635 | def func_callback(self, callback, event=None): |
| 636 | callback(self.treeView.item(self.treeView.selection())) |
| 637 | |
| 638 | def bindselect(self, callback): |
| 639 | self.selectcallback = callback |
| 640 | |
| 641 | def setselect(self, value): |
| 642 | self.treeView.selection_set(value) |
| 643 | |
| 644 | def selected(self): |
| 645 | value = self.treeView.item(self.treeView.selection()) |
| 646 | if value['values']: |
| 647 | return value |
| 648 | else: |
| 649 | return None |