diff --git a/HISTORY.rst b/HISTORY.rst
index 16e6d57b26a314f5d4b34ccaf7a10581f785de2d..f95e75705cca7b67f0eef5b1156463be8da6ca9e 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -22,3 +22,9 @@ History
 2022.1.0.0 (2022-01-11)
 ------------------
 * New versioning scheme
+
+2023.1.0.0 (2023-04-03)
+------------------
+* Gui updated to PySide2
+* Pmw dependency dropped
+* Version number updated
diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml
index 381116cd7fed15468bf2790021325841a15070c4..ca4f3bffded74467222c47701ca63c0b12b7aad6 100644
--- a/conda.recipe/meta.yaml
+++ b/conda.recipe/meta.yaml
@@ -15,7 +15,7 @@ requirements:
     - pip
   run:
     - python >=3.6
-    - pmw
+    - pyside2
 
 test:
   source_files:
diff --git a/mseedpeek/mseedpeek.py b/mseedpeek/mseedpeek.py
old mode 100755
new mode 100644
index 7383dd085068ad74b6251ac77bc5f2db85530ed2..d820daf24fb851a5f01810ca10480a6e845ce2ac
--- a/mseedpeek/mseedpeek.py
+++ b/mseedpeek/mseedpeek.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+"""
+!/usr/bin/env python
 
 
 # gui for viewing mseed headers
@@ -120,27 +121,40 @@
 #
 # Update versioning scheme
 ################################################################
+#
+# modification
+# version: 2023.1.0.0
+# author: Destiny Kuehn
+#
+# GUI updated to PySide2
+# Pmw dependency dropped
+# Version number updated
+"""
 
-import Pmw
 import sys
+import os
+import itertools
 
 from getopt import getopt
 from glob import glob
 from operator import mod
-from os import *
-from tkinter import *
-from tkinter.filedialog import *
+from PySide2 import QtCore, QtGui, QtWidgets
+
+#from libtrace import *
+#from mseedInfo import *
 
 from mseedpeek.libtrace import *
 from mseedpeek.mseedInfo import *
 
-VERSION = "2022.1.0.0"
+VERSION = "2023.1.0.0"
 SPACE = " "
 
-
 def main():
+    """
+    Main class for mseedpeek
+    """
     # return version number if -# command line option
-    ListInFiles = []
+    file_list = []
     try:
         opts, pargs = getopt(sys.argv[1:], 'f#')
         for flag, arg in opts:
@@ -148,7 +162,7 @@ def main():
                 InFiles = pargs
                 for fl in InFiles:
                     for f in glob(fl):
-                        ListInFiles.append(f)
+                        file_list.append(f)
             if flag == "-#":
                 print(VERSION)
                 sys.exit(0)
@@ -156,638 +170,681 @@ def main():
         print("\nInvalid command line usage\n")
         print("Usage:\nmseedpeek\nmseedpeek -#\nmseedpeek -f file(s)\n")
         sys.exit(1)
-
     print("\n", os.path.basename(sys.argv[0]), VERSION)
 
-    if ListInFiles:
-        mw = MainWindow("mseedpeek %s" % VERSION, ListInFiles)
-        mw.root.geometry("775x545")
-        mw.root.mainloop()
+    app = QtWidgets.QApplication(sys.argv)
+    # mc = main class
+    if file_list:
+        mc = MainWindow("mseedpeek %s" % VERSION, file_list)
     else:
-        mw = MainWindow("mseedpeek %s" % VERSION)
-        mw.root.geometry("775x545")
-        mw.root.mainloop()
+        mc = MainWindow("mseedpeek %s" % VERSION, file_list=None)
+    mc.show()
+    sys.exit(app.exec_())
 
 
-# From "Python and Tkinter Programming", J.E. Grayson, pg.103
-class Command:
-    def __init__(self, func, *args, **kw):
-        self.func = func
-        self.args = args
-        self.kw = kw
+class MainWindow(QtWidgets.QWidget):
+    """
+    Main class for mseedpeek
+    """
+    def __init__(self, title, file_list):
+        """
+        Init everything for startup
+        """
+        super().__init__()
 
-    def __call__(self, *args, **kw):
-        args = self.args + args
-        kw.update(self.kw)
-        self.func(*args, **kw)
+        # window settings
+        self.resize(self.minimumSize())
+        self.setWindowTitle(title)
 
-#
-# Over ride some methods in FileDialog so we only select directories
-# From TraceBuilder.py, auth Steve Azevedo & Lloyd Carothers
-#
+        # init vars
+        self.data_init()
 
+        # set up main window
+        self.create_main_window()
+        self.build_blockettes()
+        self.build_help()
+        self.hide_show("hide")
 
-class DirectoryDialog(FileDialog):
-
-    title = "Directory Select"
-
-    def __init__(self, root):
-        FileDialog.__init__(self, root)
-
-    #   Only allow selection of directories (single click)
-    def files_select_event(self, e):
-        pass
-    #   Double click
-
-    def files_double_event(self, e):
-        pass
-
-    #   Make sure it's a directory and accessable
-    def ok_command(self):
-        ifile = self.get_selection()
-        if not path.isdir(ifile):
-            if not access(ifile, R_OK):
-                self.root.bell()
-                ifile = None
-        self.quit(ifile)
-
-
-class MainWindow:
-    def __init__(self, title='', InFiles=''):
-
-        self.root = Tk()
-        Pmw.initialise(self.root)
-        self.root.title(title)
-
-        self.e_width = 8
-        self.InfoString = StringVar()
-
-        # if files entered on commandline set self.ListInFiles
-        self.ListInFiles = {}
-        if InFiles:
-            self.ListInFiles = InFiles
-        # some standard vars
-        self.DataDirs = StringVar()
-        self.StatSel = StringVar()
-        self.StatSelList = []
-        self.Trace = StringVar()
-        self.SelDir = StringVar()
-        self.SelDir.set("")
-        self.Station = StringVar()
-        self.NetCode = StringVar()
-        self.SampleRate = IntVar()
-        self.Channel = StringVar()
-        self.LocCode = StringVar()
-        self.ByteOrder = StringVar()
-
-        # positional vars
-        self.ByteOffset = IntVar()
-        self.BlkSize = IntVar()
-
-        # dictionaries, lists and misc vars
-        self.BlockNum = IntVar()
-        self.JumpNum = IntVar()
-        self.NumBlocks = IntVar()
-        self.FixedHdrDict = {}
-        self.RateDict = {}
-        self.Blockettes = {}
-        self.BlockettesList = []
-        self.UniqueList = []
-        self.UniqueSelectList = []
-        self.UniqueSelect = StringVar()
-        self.TraceList = []
-        self.TraceListDict = {}
-
-        # file and verbosity vars
-        self.MseedFile = StringVar()
-        self.Blockette = StringVar()
-        self.BlocketteType = StringVar()
-        self.OldMseedFile = StringVar()
-        self.VerbVar = IntVar()
-        self.OldVerbVar = IntVar()
-        self.VerbList = [
-            ["Standard", 0],
-            ["Verbose", 1],
-            ["Very Verbose", 2],
-            ["Unique", 3]
-        ]
-        self.VerbVar.set(0)
-        self.OldVerbVar.set(0)
-
-        # verbosity lists - each builds on the previous
-        self.StandardVars = [
-            ["Station Name:", self.Station],
-            ["Location Code:", self.LocCode],
-            ["Channel:", self.Channel],
-            ["Net Code:", self.NetCode],
-            ["Sps (nominal):", self.SampleRate]
-        ]
+        # if files entered on commandline call build trace
+        if file_list:
+            self.dd_text.setText(':'.join(str(file) for file in file_list))
+            self.build_trace_list(self.dd_text.text())
 
-        self.Year = StringVar()
-        self.Jday = StringVar()
-        self.Hour = StringVar()
-        self.Min = StringVar()
-        self.Sec = StringVar()
-        self.Micro = StringVar()
-        self.VerboseVars = [
-            ["Year:", self.Year],
-            ["Day:", self.Jday],
-            ["Hour:", self.Hour],
-            ["Min:", self.Min],
-            ["Sec:", self.Sec],
-            ["0.0001s:", self.Micro]
-        ]
-        self.VerboseVars = self.StandardVars + self.VerboseVars
-
-        self.SeqNum = StringVar()
-        self.DQual = StringVar()
-        self.Resv = StringVar()
-        self.AddVVVars = [
-            ["Sequence Number:", self.SeqNum],
-            ["Data Hdr/Qaul:", self.DQual],
-            ["Reserved:", self.Resv]
+    def data_init(self):
+        """
+        Init starting vars
+        """
+        self.verb_var = 0
+        self.blk_size = 0
+        self.num_blocks = 0
+        self.dir_list = []
+        self.stat_sel_list = []
+        self.old_mseed_file = ""
+
+        self.standard_vars = [
+            "Station Name:",
+            "Location Code:",
+            "Channel:",
+            "Net Code:",
+            "Sps (nominal):",
         ]
 
-        self.NumSamp = IntVar()
-        self.SampFact = IntVar()
-        self.SampMult = IntVar()
-        self.ActFlag = StringVar()
-        self.IOFlag = StringVar()
-        self.DQFlag = StringVar()
-        self.NumBlockettes = IntVar()
-        self.TimeCorr = IntVar()
-        self.BeginData = IntVar()
-        self.FstBlkett = IntVar()
-        self.VeryVerboseVars = [
-            ["Number Samples:", self.NumSamp],
-            ["Sample Factor:", self.SampFact],
-            ["Sample Multiplier:", self.SampMult],
-            ["Activity Flags:", self.ActFlag],
-            ["I/O & Clk Flags:", self.IOFlag],
-            ["Data Qaul Flags:", self.DQFlag],
-            ["Number Blockettes:", self.NumBlockettes],
-            ["Time Corr:", self.TimeCorr],
-            ["Offet Data:", self.BeginData],
-            ["Offset Blockette:", self.FstBlkett]
+        self.v_vars = [
+            "Year:",
+            "Day:",
+            "Hour:",
+            "Min:",
+            "Sec:",
+            "0.0001s:"
         ]
-        self.VeryVerboseVars = (self.AddVVVars + self.VerboseVars +
-                                self.VeryVerboseVars)
-
-        # set up notebooks
-        self.createMainButtons(self.root)
-        self.createNoteBooks(self.root)
-
-########################################
-    def createMainButtons(self, master):
-        """
-        Build info bar and buttons for root window
-        """
-        self.InfoString_l = Label(master,
-                                  bg="yellow",
-                                  relief="ridge")
-        self.InfoString_l.pack(side='bottom', fill='x')
-
-        self.Button_fm = Frame(master, relief='groove', borderwidth=2)
-        self.Button_fm.pack(side='bottom', pady=5, fill='x')
-
-        self.exit_b = Button(self.Button_fm,
-                             text="Exit",
-                             relief="ridge",
-                             cursor='pirate',
-                             command=Command(self.Exit),
-                             activebackground='red',
-                             activeforeground='black')
-        self.exit_b.pack(side='right', anchor='e')
-
-        self.flush_b = Button(self.Button_fm,
-                              text="Flush Dictionaries",
-                              relief="ridge",
-                              command=Command(self.FlushDict),
-                              activebackground='orange',
-                              activeforeground='black')
-        self.flush_b.pack(side='left', anchor='w')
-
-########################################
-    def createNoteBooks(self, master):
-        """
-        Set up notebooks in root window
-        """
-        nb = Pmw.NoteBook(master)
-        self.buildHdrDisplay(nb)
-        self.buildBlockette(nb)
-        self.buildHelp(nb)
-        nb.pack(padx=5, pady=5, fill='both', expand=1)
-        # If commandline trace input
-        if self.ListInFiles:
-            (self.TraceListDict, NumFiles) = self.IndexFiles(self.ListInFiles)
-            self.UpdateDirList(self.HdrSelect_fm)
-            if NumFiles == 1:
-                vdir = list(self.TraceListDict.keys())[0]
-                self.SelDir.set(vdir)
-                self.UpdateTrcList()
-                trace = self.TraceListDict[vdir][0]
-                self.MseedFile.set(trace)
-                self.ReadHdrs()
-
-            # clear any lingering updates
-            # self.MseedFile.set("")
-            # self.ClearAll(self.VeryVerboseVars)
-            # self.Hdrs_fm.destroy()
-            # self.Blks_fm.destroy()
-
-            self.root.bell()
-            text = "Done. " + str(NumFiles) + " mseed files found."
-            self.addTextInfoBar(self.InfoString_l, text, "green")
-##################################################################
-
-    def buildHdrDisplay(self, master):
-        """
-        Populate HdrDisplay NoteBook
-        """
-        self.FixedHdr_nb = master.add('Trace Headers')
-
-        # data selection frame
-        self.DataDirs_fm = Frame(self.FixedHdr_nb, relief='groove',
-                                 borderwidth=2)
-        self.DataDirs_fm.pack(side='top', pady=5, fill='x')
-        self.DataDirs_l = Label(self.DataDirs_fm, text='Data Directories: ')
-        self.DataDirs_l.pack(side='left')
-        self.DataDirs_e = Entry(self.DataDirs_fm,
-                                selectbackground='yellow',
-                                textvariable=self.DataDirs)
-        self.DataDirs_e.pack(side='left', anchor='w', expand=1, fill='x')
-        self.ClearDataDir_b = Button(self.DataDirs_fm,
-                                     activebackground='orange',
-                                     relief="ridge",
-                                     text="Clear",
-                                     command=Command(self.setValue,
-                                                     self.DataDirs))
-        self.ClearDataDir_b.pack(side='right')
-        self.FindDataDir_b = Button(self.DataDirs_fm,
-                                    activebackground='green',
-                                    relief="ridge",
-                                    text="Find",
-                                    command=Command(self.getPath,
-                                                    self.DataDirs,
-                                                    None))
-        self.FindDataDir_b.pack(side='right')
-        self.DataDirs.set(getcwd())
-
-        self.BuildTrcList_b = Button(self.DataDirs_fm,
-                                     activebackground='green',
-                                     relief="ridge",
-                                     background='lightblue',
-                                     text="Build Trace db",
-                                     command=Command(self.BuildTrcList)
-                                     )
-        self.BuildTrcList_b.pack(side='right')
-
-        # station selection frame and entry box
-        self.StatSel_fm = Frame(self.FixedHdr_nb, relief='groove',
-                                borderwidth=2)
-        self.StatSel_fm.pack(side='top', pady=5, fill='x')
-        self.StatSel_l = Label(self.StatSel_fm,
-                               text='Find only stations (colon separated '
-                                    'list): ')
-        self.StatSel_l.pack(side='left')
-        self.StatSel_e = Entry(self.StatSel_fm,
-                               selectbackground='yellow',
-                               textvariable=self.StatSel)
-        self.StatSel_e.pack(side='left', anchor='w', expand=1, fill='x')
-
-        self.ClearStatSel_b = Button(self.StatSel_fm,
-                                     activebackground='orange',
-                                     relief="ridge",
-                                     text="Clear",
-                                     command=Command(self.setValue,
-                                                     self.StatSel))
-        self.ClearStatSel_b.pack(side='right')
-
-        # verbosity buttons
-        self.RadButtons_fm = Frame(
-            self.FixedHdr_nb, relief='groove', borderwidth=2)
-        self.RadButtons_fm.pack(side='top', pady=5, fill='x')
-
-        for text, value in self.VerbList:
-            Radiobutton(self.RadButtons_fm,
-                        text=text,
-                        value=value,
-                        command=Command(self.ReadHdrs, None),
-                        variable=self.VerbVar).pack(side='left', anchor='e')
-
-        Entry(self.RadButtons_fm,
-              width=self.e_width,
-              background='yellow',
-              relief='ridge',
-              textvariable=self.ByteOrder).pack(side='right', anchor='e')
-        Label(self.RadButtons_fm,
-              text="Header Endianess").pack(side='right', anchor='e')
-
-        # set up frames that get filled when traces are selected
-        self.HdrScale_fm = Frame(self.FixedHdr_nb, borderwidth=2)
-        self.HdrScale_fm.pack(side='bottom', padx=5, pady=5, fill='x')
-
-        self.HdrSelect_fm = Frame(
-            self.FixedHdr_nb, relief='groove', borderwidth=2)
-        self.HdrSelect_fm.pack(side='top', pady=5, fill='x')
-
-        self.Hdrs_fm = Frame(self.FixedHdr_nb, relief='groove', borderwidth=2)
-        self.Hdrs_fm.pack(side='top', pady=5, fill='x')
-
-##################################################################
-    def buildBlockette(self, master):
-        """
-        Populate Blockettes NoteBook
-        """
-        self.Blockette_nb = master.add('Blockettes')
-
-        # these get filled when traces are selected
-        self.BlkScale_fm = Frame(self.Blockette_nb, borderwidth=2)
-        self.BlkScale_fm.pack(side='bottom', padx=5, pady=5, fill='x')
-
-        self.BlksSelect_fm = Frame(
-            self.Blockette_nb, relief='groove', borderwidth=2)
-        self.BlksSelect_fm.pack(side='top', pady=5, fill='x')
-
-        self.BlksTitle_fm = Frame(
-            self.Blockette_nb, relief='groove', borderwidth=2)
-        self.BlksTitle_fm.pack(side='top', pady=5, fill='x')
-
-        self.Blks_fm = Frame(self.Blockette_nb, relief='groove', borderwidth=2)
-        self.Blks_fm.pack(side='top', pady=5, fill='x')
-
-##################################################################
-    def buildBlkInfo(self, blktype, master):
-        """
-        Provide information window for blockettes
-        """
 
-        try:
-            self.tl_State = self.BlkInfo_tl.winfo_exists()
-        except Exception:
-            self.tl_State = 0
+        self.first_vv_vars = [
+            "Sequence Number:",
+            "Data Hdr/Qaul:",
+            "Reserved:"
+        ]
 
-        if self.tl_State == 1:
-            self.BlkInfo_tl.tkraise()
-            # display info on selected block
-            self.BlocketteType.set(blktype)
-            self.displayBlkInfo(blktype)
+        self.vv_vars = [
+            "Number Samples:",
+            "Sample Factor:",
+            "Sample Multiplier:",
+            "Activity Flags:",
+            "I/O & Clk Flags:",
+            "Data Qaul Flags:",
+            "Number Blockettes:",
+            "Time Corr:",
+            "Offet Data:",
+            "Offset Blockette:"
+        ]
 
-        else:
-            self.BlkInfo_tl = Toplevel(master)
-            self.BlkInfo_tl.title("Blockette Information")
-
-            self.BlkInfoSelect_fm = Frame(
-                self.BlkInfo_tl, relief='groove', borderwidth=2)
-            self.BlkInfoSelect_fm.pack(side='top', pady=5, fill='x')
-
-            List = ["Fixed Header", "Data Fields", "BTime", 100, 200, 201,
-                    300, 310, 320, 390, 395, 400, 405, 500, 1000, 1001, 2000]
-            Label(self.BlkInfoSelect_fm, text="Blockette:").grid(row=1,
-                                                                 sticky=W)
-            Pmw.ComboBox(self.BlkInfoSelect_fm,
-                         history=0,
-                         entry_width=self.e_width + 15,
-                         entry_textvariable=self.BlocketteType,
-                         selectioncommand=Command(self.displayBlkInfo),
-                         scrolledlist_items=(List)
-                         ).grid(row=1, column=1, sticky=W)
-
-            self.ExitBlkInfo_b = Button(self.BlkInfo_tl,
-                                        activebackground='red',
-                                        cursor='pirate',
-                                        background='lightblue',
-                                        text="Done",
-                                        command=Command(self.killWindow,
-                                                        self.BlkInfo_tl))
-            self.ExitBlkInfo_b.pack(side='bottom', fill='x', expand=1)
-
-            self.BlkInfoText = Pmw.ScrolledText(self.BlkInfo_tl,
-                                                borderframe=1)
-            self.BlkInfoText.pack(side='bottom', fill='both', expand=1)
-
-            # display info on selected block
-            self.BlocketteType.set(blktype)
-            self.displayBlkInfo(blktype)
-
-##################################################################
-
-    def buildUniqueSelectBox(self, master):
-        """
-        In unique view allows user to select block to jump to
-        """
-        if "*" not in self.UniqueSelectList:
-            self.UniqueSelectList.append("*")
-            self.UniqueSelectList.sort()
-        Label(master, text="Select Keys:").pack(side='top', anchor='w')
-
-        Pmw.ComboBox(master,
-                     history=1,
-                     entry_width=self.e_width + 15,
-                     entry_textvariable=self.UniqueSelect,
-                     selectioncommand=Command(self.SelectKeys),
-                     scrolledlist_items=self.UniqueSelectList
-                     ).pack(side='top', anchor='w')
-        self.UniqueSelect.set("*")
-
-##################################################################
-
-    def buildJumpBox(self, master, numblocks=0):
-        """
-        In unique view allows user to select block to jump to
-        """
-        if self.VerbVar.get() == 3:
-            Label(master, text="Jump To Block #:").pack(side='top', anchor='w')
-        else:
-            Label(master, text="Jump To Block #:").pack(side='top', anchor='n')
-
-        jumpbox_cb = Pmw.ComboBox(master,
-                                  history=1,
-                                  entry_width=self.e_width,
-                                  entry_textvariable=self.JumpNum,
-                                  selectioncommand=Command(self.Jump),
-                                  scrolledlist_items=(list(range(numblocks))))
-        if self.VerbVar.get() == 3:
-            jumpbox_cb.pack(side='top', anchor='w')
-        else:
-            jumpbox_cb.pack(side='top', anchor='n')
-
-##################################################################
-    def Jump(self, value):
-        """
-        Fills hdr values based on block selected in JumpBox
-        """
-        if int(value) < 0:
-            value = 0
-        if int(value) > (self.NumBlocks.get() - 1):
-            value = self.NumBlocks.get() - 1
-        self.BlockNum.set(value)
-        if self.VerbVar.get() == 3:
-            self.VerbVar.set(2)
-        self.ReadHdrs()
-        self.FillHdr(value)
-
-##################################################################
-    def SelectKeys(self, value):
-        """
-        Fills hdr values based on block selected in JumpBox
-        """
-        self.UniqueText.clear()
-        self.UniqueText.tag_config("list", foreground="blue")
-        self.UniqueText.tag_config("odd", backgroun="lightblue")
-
-        self.UniqueText.insert(
-            "end", "Block\tStat\tChan\tLoc\tNet\tRate\n", "list")
-
-        selectkey = self.UniqueSelect.get()
-        c = 0
-        for key in self.UniqueList:
-            testkey = key.split(":")[1:].join(":")
-            if selectkey != "*":
-                if selectkey != testkey:
-                    continue
-            for var in key.split(":"):
-                if c:
-                    self.UniqueText.insert("end", """%s\t""" % var, "odd")
-                else:
-                    self.UniqueText.insert("end", """%s\t""" % var)
-            self.UniqueText.insert("end", """\n""")
-            if c:
-                c = 0
+    def create_main_window(self):
+        """
+        Build tabs and info bar for root window
+        """
+        # tab widget
+        self.tabwidget = QtWidgets.QTabWidget()
+        self.trace_headers_tab = QtWidgets.QWidget()
+        self.blockettes_tab = QtWidgets.QWidget()
+        self.help_tab = QtWidgets.QWidget()
+        self.tabwidget.addTab(self.trace_headers_tab, "Trace Headers")
+        self.tabwidget.addTab(self.blockettes_tab, "Blockettes")
+        self.tabwidget.addTab(self.help_tab, "Help")
+
+        # info bar widget
+        self.infobar = QtWidgets.QLineEdit()
+        self.infobar.setStyleSheet("background-color:yellow")
+        self.infobar.setReadOnly(True)
+        self.infobar.setAlignment(QtGui.Qt.AlignCenter)
+
+        # main window layout
+        self.window_layout = QtWidgets.QVBoxLayout()
+        self.setLayout(self.window_layout)
+
+        # add tab widget and info bar to main window layout
+        self.window_layout.addWidget(self.tabwidget)
+        self.build_trace_headers() # build widgets for Trace Headers tab
+        self.window_layout.addWidget(self.infobar)
+        self.window_layout.setMargin(0) # set spacing
+
+    def build_help(self):
+        """
+        Build Help tab
+        """
+        # init tab layout
+        layout = QtWidgets.QVBoxLayout(self.help_tab)
+
+        # Help textbox
+        Blue = QtGui.QColor(0,0,153)
+        Green = QtGui.QColor(0,100,0)
+        Red = QtGui.QColor(136, 8, 8)
+        Black = QtGui.QColor(0,0,0)
+
+        help_text = QtWidgets.QTextEdit()
+        layout.addWidget(help_text)
+        help_text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
+        help_text.setAcceptRichText(False)
+
+        # Name
+        help_text.setTextColor(Blue)
+        text = "NAME"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = "\n" + SPACE + "mseedpeek - GUI for displaying mseed file headers.\n\n"
+        help_text.insertPlainText(text)
+
+        # Version
+        help_text.setTextColor(Blue)
+        text = "VERSION"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = "\n" + SPACE + str(VERSION) + "\n\n"
+        help_text.insertPlainText(text)
+
+        # Synopsis
+        help_text.setTextColor(Blue)
+        text = "SYNOPSIS"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = "\n" + SPACE + "mseedpeek\n" + SPACE +\
+              "mseedpeek -#\n" + SPACE + "mseedpeek -f file_names\n\n"
+        help_text.insertPlainText(text)
+
+        # Options
+        help_text.setTextColor(Blue)
+        text = "OPTIONS"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = "\n" + SPACE + "-# returns version number\n" + \
+            SPACE + "-f file_name(s) - accepts command line \
+                input for files to inspect (wildcards accepted)\n\n"
+        help_text.insertPlainText(text)
+
+        # Description
+        help_text.setTextColor(Blue)
+        text = "DESCRIPTION"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = "\n" + SPACE + "mseedpeek has three notebooks: "
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Green)
+        text = "[Trace Headers][Blockettes]"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ", and "
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Green)
+        text = "[Help]"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ". The "
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Green)
+        text = "[Trace Headers]\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = SPACE + "notebook displays various the fixed \
+            header in four levels of verbosity. The "
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Green)
+        text = "[Blockettes]\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = SPACE + "notebook displays blockette information.\n\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Green)
+        text = SPACE + "[Trace Headers]\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = SPACE + "General:\n" + SPACE + "    \
+            >> specify/load directories for building trace db\n" + SPACE + \
+                "    >> select trace for header display\n" + SPACE + \
+                    "    >> select level of verbosity for display\n\n" + SPACE + \
+                        "Buttons:\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Build Trace db>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Searchs the directories listed in the \"Data-Directories\" \
+            entry box \n" + SPACE + "    (a colon separated list) and builds a \
+                list of mseed files found indexing them on unique values of\n" + \
+                    SPACE + "    <dir>:<file_name>. It then creates a dropdown menu \
+                        with entries for each data directory\n" + SPACE + "    found.\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Find>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Launches a file browser allowing the user to add directories to \
+            the \"Data Directories\" entry\n" + SPACE + "    box. \
+                Double clicking selects the new directory.\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Clear>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Clears the \"Data Directories\" entry box.\n\n"
+        help_text.insertPlainText(text)
+        text = SPACE + "    By selecting a data directory a dropdown \
+            menu is created for trace selection. Selecting a trace from\n" \
+                + SPACE + "    this menu will create a header display.\n\n"
+        help_text.insertPlainText(text)
+        text = SPACE + "Radio Buttons:\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Standard>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": This is the default. It displays Station, Channel, \
+            Location Code, Net Code, and the\n" + SPACE + \
+                "    nominal Sample Rate.\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Verbose>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Standard display plus time of block.\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Very Verbose>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Verbose plus the rest of the mseed fixed header fields.\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Unique>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": This displays changes in the Standard fields within a mseed file.\n\n"
+        help_text.insertPlainText(text)
+        text = SPACE + "Slider Scale and "
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = "<Jump To Block #> "
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = "Button:\n" + SPACE + "    At the bottom of the page \
+            is a scale bar showing block numbers. Sliding the bar \
+                scans through all\n" + SPACE + \
+                    "    fixed headers for the selected mseed file.\n\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "<Flush Directories>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Clears cached trace header data. As you view \
+            mseed headers, mseedpeek\n" + SPACE + \
+                "    maintains a cache of previously viewed headers \
+                    for quick, future access. If you wish to monitor\n" + \
+                        SPACE + "    changes to mseed files you need to \
+                            flush the dictionaries so that the \
+                                new changes will be displayed.\n\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Green)
+        text = SPACE + "[Blockettes]"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ":\n"
+        help_text.insertPlainText(text)
+        text = SPACE + "    The 'Blockettes' notebook displays all blockettes \
+            found for the select mseed file in a dropdown menu.\n" + SPACE + \
+                "    By selecting a blockette from the dropdown menu, the contents \
+                    of the blockette will be\n" + SPACE + "    displayed.\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Red)
+        text = SPACE + "    <Blockette Info>"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = ": Displays a pop-up window with a definition of the SEED Blockette.\n\n"
+        help_text.insertPlainText(text)
+        text = SPACE + "    At the bottom of the page is a scale bar showing \
+            block numbers and sliding the bar scans through all\n" + SPACE + \
+                "    blockettes for the selected mseed file.\n\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Blue)
+        text = "KEYWORDS\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = SPACE + "mseed; header information\n\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Blue)
+        text = "SEE ALSO\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = SPACE + "SEED manual (pdf), fixhdr, mseedhdr\n\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Blue)
+        text = "AUTHOR\n"
+        help_text.insertPlainText(text)
+        help_text.setTextColor(Black)
+        text = SPACE + "Bruce Beaudoin <bruce@passcal.nmt.edu>"
+        help_text.insertPlainText(text)
+
+    def build_blockettes(self):
+        """
+        Create initial widgets for Blockettes tab
+        """
+        # data boxes
+        self.blktype_box = QtWidgets.QGroupBox()
+        self.blktype_box.setObjectName("Box1")
+
+        self.blkinfo_box = QtWidgets.QGroupBox()
+        self.blkinfo_box.setLayout(QtWidgets.QHBoxLayout())
+        self.blkinfo_box.setObjectName("Box2")
+
+        self.blk_vars_box = QtWidgets.QGroupBox()
+        self.blk_vars_box.setLayout(QtWidgets.QVBoxLayout())
+        self.blk_vars_box.setObjectName("Box3")
+
+        # widgets
+        blk_label = QtWidgets.QLabel("Blockette:")
+        blk_menu = QtWidgets.QComboBox()
+        blk_menu.setObjectName("type_menu")
+
+        self.blkinfo_btn = QtWidgets.QPushButton("Blockette Info")
+        self.blkinfo_btn.setStyleSheet("QPushButton{background-color:lightblue;}\
+                                  QPushButton::hover{background-color:green;}")
+        self.blkinfo_btn.clicked.connect(self.blkinfo_window)
+
+        # box layouts
+        l1 = QtWidgets.QHBoxLayout(self.blktype_box)
+        l1.addWidget(blk_label)
+        l1.addWidget(blk_menu)
+        l1.addStretch()
+
+        # add to tab's main layout
+        main_layout = QtWidgets.QVBoxLayout()
+        main_layout.addWidget(self.blktype_box)
+        main_layout.addWidget(self.blkinfo_box)
+        main_layout.addWidget(self.blk_vars_box)
+        main_layout.addStretch()
+        self.blockettes_tab.setLayout(main_layout)
+
+    def build_trace_headers(self):
+        """
+        Build widgets for Trace Headers tab
+        """
+        # tab layout
+        self.trace_headers_layout = QtWidgets.QVBoxLayout(self.trace_headers_tab)
+
+        # groupboxes for data fields
+        self.datadir_box = QtWidgets.QGroupBox()
+        self.datadir_box.setCheckable(False)
+        sp = self.datadir_box.sizePolicy()
+        sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed)
+        self.datadir_box.setSizePolicy(sp)
+
+        self.stations_box = QtWidgets.QGroupBox()
+        self.stations_box.setCheckable(False)
+        sp = self.stations_box.sizePolicy()
+        sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed)
+        self.stations_box.setSizePolicy(sp)
+
+        self.radio_box = QtWidgets.QGroupBox()
+        self.radio_box.setCheckable(False)
+        sp = self.radio_box.sizePolicy()
+        sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed)
+        self.radio_box.setSizePolicy(sp)
+
+        self.dir_trace_box = QtWidgets.QGroupBox()
+        self.dir_trace_box.setCheckable(False)
+        sp = self.dir_trace_box.sizePolicy()
+        sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed)
+        self.dir_trace_box.setSizePolicy(sp)
+
+        self.flush_exit_box = QtWidgets.QGroupBox()
+        self.flush_exit_box.setCheckable(False)
+        sp = self.flush_exit_box.sizePolicy()
+        sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed)
+        self.flush_exit_box.setSizePolicy(sp)
+        self.window_layout.addWidget(self.flush_exit_box)
+
+        # layouts for groupboxes
+        datadir_layout = QtWidgets.QHBoxLayout(self.datadir_box)
+        stations_layout = QtWidgets.QHBoxLayout(self.stations_box)
+        rbuttons_layout = QtWidgets.QHBoxLayout(self.radio_box)
+        flush_exit_layout = QtWidgets.QHBoxLayout(self.flush_exit_box)
+        flush_exit_layout.setMargin(0)
+        flush_exit_layout.setSpacing(450)
+        dir_trace_layout = QtWidgets.QFormLayout(self.dir_trace_box)
+
+        # fill flush / exit groubpx
+        self.exit_btn = QtWidgets.QPushButton("Exit")
+        self.exit_btn.setStyleSheet("QPushButton::hover{background-color:darkred;}")
+        self.exit_btn.clicked.connect(lambda: quit())
+        self.flush_btn = QtWidgets.QPushButton("Flush Directories")
+        self.flush_btn.clicked.connect(self.flush_dict)
+        self.flush_btn.setStyleSheet("QPushButton::hover{background-color:orange;}")
+        flush_exit_layout.addWidget(self.flush_btn)
+        flush_exit_layout.addWidget(self.exit_btn)
+
+        # fill data dir groupbox
+        self.dd_label = QtWidgets.QLabel("Data Directories:")
+        self.dd_text = QtWidgets.QLineEdit()
+        self.build_trace_btn = QtWidgets.QPushButton("Build Trace db")
+        self.build_trace_btn.setStyleSheet("QPushButton{background-color:lightblue;} \
+                                            QPushButton::hover{background-color:green;}")
+        self.build_trace_btn.clicked.connect(self.clicked_build_trace)
+        self.find_btn = QtWidgets.QPushButton("Find")
+        self.find_btn.clicked.connect(self.clicked_find)
+        self.clear_btn = QtWidgets.QPushButton("Clear")
+        self.clear_btn.clicked.connect(lambda: self.dd_text.clear())
+        datadir_layout.addWidget(self.dd_label)
+        datadir_layout.addWidget(self.dd_text)
+        datadir_layout.addWidget(self.build_trace_btn)
+        datadir_layout.addWidget(self.find_btn)
+        datadir_layout.addWidget(self.clear_btn)
+
+        # stations widgets
+        self.stations_label = QtWidgets.QLabel("Find only stations (colon separated list):")
+        self.stations_text = QtWidgets.QLineEdit()
+        self.stations_clear_btn = QtWidgets.QPushButton("Clear")
+        self.stations_clear_btn.clicked.connect(lambda: self.stations_text.clear())
+        stations_layout.addWidget(self.stations_label)
+        stations_layout.addWidget(self.stations_text)
+        stations_layout.addWidget(self.stations_clear_btn)
+
+        # fill stations groupbox
+        self.standard_rbtn = QtWidgets.QRadioButton("Standard")
+        self.standard_rbtn.setChecked(True)
+        self.standard_rbtn.clicked.connect(lambda: self.clicked_scan_type(0))
+        self.verbose_rbtn = QtWidgets.QRadioButton("Verbose")
+        self.verbose_rbtn.setChecked(False)
+        self.verbose_rbtn.clicked.connect(lambda: self.clicked_scan_type(1))
+        self.vv_rbtn = QtWidgets.QRadioButton("Very Verbose")
+        self.vv_rbtn.setChecked(False)
+        self.vv_rbtn.clicked.connect(lambda: self.clicked_scan_type(2))
+        self.unique_rbtn = QtWidgets.QRadioButton("Unique")
+        self.unique_rbtn.setChecked(False)
+        self.unique_rbtn.clicked.connect(lambda: self.clicked_scan_type(3))
+
+        # spacer item
+        # adds distance between rbuttons and "Header Endianess"
+        spacerItem = QtWidgets.QSpacerItem(250, 0,
+                                           QtWidgets.QSizePolicy.Expanding,
+                                            QtWidgets.QSizePolicy.Minimum)
+
+        self.header_endianess_label = QtWidgets.QLabel("Header Endianess")
+        self.header_endianess_text = QtWidgets.QLineEdit()
+        self.header_endianess_text.setStyleSheet("background-color:yellow")
+
+        rbuttons_layout.addWidget(self.standard_rbtn)
+        rbuttons_layout.addWidget(self.verbose_rbtn)
+        rbuttons_layout.addWidget(self.vv_rbtn)
+        rbuttons_layout.addWidget(self.unique_rbtn)
+        rbuttons_layout.addItem(spacerItem)
+        rbuttons_layout.addWidget(self.header_endianess_label)
+        rbuttons_layout.addWidget(self.header_endianess_text)
+
+        # fill dir / trace groupbox
+        self.dir_label = QtWidgets.QLabel("Directory:")
+        self.dir_menu = QtWidgets.QComboBox()
+        self.dir_menu.activated.connect(lambda: self.select_dir_trace("dir"))
+        self.trace_label = QtWidgets.QLabel("Trace:")
+        self.trace_menu = QtWidgets.QComboBox()
+        self.trace_menu.activated.connect(lambda: self.select_dir_trace("trace"))
+        dir_trace_layout.addRow(self.dir_label, self.dir_menu)
+        dir_trace_layout.addRow(self.trace_label, self.trace_menu)
+        self.dir_trace_box.hide()
+        self.trace_label.hide()
+        self.trace_menu.hide()
+
+        # stacked widget (jump box)
+        self.standard_box = StandardBox(self.standard_vars)
+        self.verbose_box = VerboseBox(self.standard_vars, self.v_vars)
+        self.vv_box = VVBox(self.first_vv_vars, self.standard_vars, self.v_vars, self.vv_vars)
+        self.unique_box = UniqueBox()
+
+        self.jump_box = QtWidgets.QStackedWidget()
+        self.jump_box.setStyleSheet("QGroupBox{border:0;}")
+        self.jump_box.setMinimumSize(0,200)
+        self.jump_box.addWidget(self.standard_box)
+        self.jump_box.addWidget(self.verbose_box)
+        self.jump_box.addWidget(self.vv_box)
+        self.jump_box.addWidget(self.unique_box)
+
+        # slider
+        self.slider_box = SliderBox()
+        self.slider_box.slider.valueChanged.connect(lambda: self.update_slider("slider"))
+        self.slider_box.jump_menu.currentTextChanged.connect(lambda: self.update_slider("menu"))
+        self.unique_box.unique_jump.currentIndexChanged.connect(lambda:
+                                                                self.update_slider("unique"))
+
+        # add everything to trace headers layout
+        self.trace_headers_layout.addWidget(self.datadir_box)
+        self.trace_headers_layout.addWidget(self.stations_box)
+        self.trace_headers_layout.addWidget(self.radio_box)
+        self.trace_headers_layout.addWidget(self.dir_trace_box)
+        self.trace_headers_layout.addWidget(self.jump_box)
+        self.trace_headers_layout.addWidget(self.slider_box)
+
+        # set data directory widget to display cwd
+        default_dir = os.getcwd()
+        self.dd_text.setText(default_dir)
+
+    def clicked_scan_type(self, index):
+        """
+        Show data related to selected scan type
+        """
+        self.verb_var = index
+        self.jump_box.setCurrentIndex(self.verb_var)
+        if self.trace_menu.isHidden():
+            self.jump_box.hide()
+        self.maybe_read_hdrs()
+
+    def clicked_find(self):
+        """
+        Open file dialogue to search for mseed files
+        """
+        search = QtWidgets.QFileDialog.getExistingDirectory()
+        directories = self.dd_text.text()
+
+        if search:
+            if directories:
+                self.dd_text.insert(":" + search)
             else:
-                c += 1
-##########################################
+                self.dd_text.insert(search)
 
-    def UpdateDirList(self, fm):
+    def clicked_build_trace(self):
         """
-        build dropdown for selecting data filled directories
+        Check directories have been provided before building trace list
         """
-        self.DirList = list(self.TraceListDict.keys())
-
-        self.DirList.sort()
-        self.SelDir.set("")
-        if not self.DirList:
-            self.root.bell()
-            self.addTextInfoBar(self.InfoString_l, "No Data Found", 'orange')
-
+        directories = self.dd_text.text()
+        if directories:
+            self.dir_list.clear()
+            self.build_trace_list(directories)
+            self.hide_show("hide")
         else:
-            Label(fm, text="Directory:").grid(row=0, sticky=W)
-            Pmw.ComboBox(fm,
-                         history=0,
-                         entry_width=self.e_width + 40,
-                         entry_textvariable=self.SelDir,
-                         selectioncommand=Command(self.UpdateTrcList),
-                         scrolledlist_items=(self.DirList)
-                         ).grid(row=0, column=1, sticky=W)
-
-##################################################################
-
-    def UpdateTrcList(self, name=""):
-        """
-        create dropdown file list based on selected directory
-        """
-        self.MseedFile.set("")
-        self.TraceList = self.TraceListDict[self.SelDir.get()]
-        self.TraceList.sort()
-        self.ClearAll(self.VeryVerboseVars)
-        if not self.TraceList:
-            self.root.bell()
-            self.addTextInfoBar(self.InfoString_l, "No Data Found", 'orange')
-
-        Label(self.HdrSelect_fm, text="Trace:").grid(row=1, sticky=W)
-        Pmw.ComboBox(self.HdrSelect_fm,
-                     history=0,
-                     entry_width=self.e_width + 40,
-                     entry_textvariable=self.MseedFile,
-                     selectioncommand=Command(self.ReadHdrs),
-                     scrolledlist_items=(self.TraceList)
-                     ).grid(row=1, column=1, sticky=W)
-
-#######################################
-
-    def BuildTrcList(self):
-        """
-        build a trace list using DataDirList as base directories
-        """
-        self.addTextInfoBar(self.InfoString_l)
-
-        self.ByteOrder.set("")
-        DataDirList = []
-        self.StatSelList = []
-        for idir in self.DataDirs.get().split(":"):
-            dirlist = glob(idir)
-            for newdir in dirlist:
-                if not path.isdir(newdir):
-                    err = "***WARNING*** Directory " + newdir + " not found."
-                    self.root.bell()
-                    self.addTextInfoBar(self.InfoString_l, err, "red")
-                    return
-                DataDirList.append(newdir)
-
-        # split station select list if it exists
-        if self.StatSel.get() == "*" or self.StatSel.get() == "":
-            pass
+            error_msg = QtWidgets.QMessageBox()
+            error_msg.setIcon(QtWidgets.QMessageBox.Critical)
+            error_msg.setText("Error")
+            error_msg.setInformativeText("No directories listed.")
+            error_msg.setWindowTitle("Error")
+            error_msg.exec_()
+
+    def build_trace_list(self, directories):
+        """
+        Build trace list from given directories
+        """
+        for dir in str(directories).split(":"):
+            if not os.path.isdir(dir):
+                err = "***WARNING*** Directory " + dir + " not found."
+                self.infobar(err, "red")
+                QtWidgets.QApplication.beep()
+            else:
+                self.dir_list.append(dir)
+
+        stat_sel = self.stations_text.text()
+        if stat_sel:
+            for stat in str(stat_sel).split(":"):
+                statsel = stat.strip()
+                self.stat_sel_list.append(statsel)
+
+        if self.dir_list:
+            (num_files, err_files) = self.find_trace()
+            text = "Done. " + str(num_files) + " mseed files found. ***" \
+            + str(err_files) + " files with errors."
+            self.update_infobar(text, "green")
+
+    def hide_show(self, action):
+        """
+        Hide/show widgets between scans
+        """
+        if action == "hide":
+            widget = self.jump_box.currentWidget()
+            for child in widget.findChildren(QtWidgets.QWidget):
+                if not child.isHidden():
+                    child.hide()
+            for child in self.slider_box.findChildren(QtWidgets.QWidget):
+                if not child.isHidden():
+                    child.hide()
+            widgets = self.blockettes_tab.findChildren(QtWidgets.QGroupBox)
+            for widget in widgets:
+                if not widget.isHidden():
+                    widget.hide()
+            self.trace_label.hide()
+            self.trace_menu.hide()
+            self.blktype_box.hide()
+            self.blkinfo_box.hide()
+            self.blk_vars_box.hide()
         else:
-            for statsel in str(self.StatSel.get()).split(":"):
-                statsel = statsel.strip()
-                self.StatSelList.append(statsel)
-
-        (self.TraceListDict, NumFiles, errfiles) = self.FindTrace(DataDirList)
-        self.UpdateDirList(self.HdrSelect_fm)
-
-        # clear any lingering updates
-        self.MseedFile.set("")
-        self.ClearAll(self.VeryVerboseVars)
-        self.Hdrs_fm.destroy()
-        self.Blks_fm.destroy()
-
-        self.root.bell()
-        text = "Done. " + str(NumFiles) + " mseed files found. ***" \
-            + str(errfiles) + " files with errors."
-        self.addTextInfoBar(self.InfoString_l, text, "green")
-
-#######################################
-
-    def FindTrace(self, DataDir):
+            widget = self.jump_box.currentWidget()
+            for child in widget.findChildren(QtWidgets.QWidget):
+                if child.isHidden():
+                    child.show()
+            for child in self.slider_box.findChildren(QtWidgets.QWidget):
+                if child.isHidden():
+                    child.show()
+            widgets = self.blockettes_tab.findChildren(QtWidgets.QGroupBox)
+            for widget in widgets:
+                if widget.isHidden():
+                    widget.show()
+            self.blktype_box.show()
+            self.blkinfo_box.show()
+            self.blk_vars_box.show()
+
+    def find_trace(self):
         """
         based on traverse routine in "python standard library", Lundh pg 34
         """
         stack = []
-        for k in range(len(DataDir)):
-            stack.append(DataDir[k])
+        for k in range(len(self.dir_list)):
+            stack.append(self.dir_list[k])
+
         file_list = {}
-        NumMseedFiles = 0
-        rwError = 0
+        num_mseed_files = 0
+        rw_error = 0
         cnt = 1
         while stack:
             directory = stack.pop()
-            if not path.isdir(directory):
-                print("\n***WARNING*** Directory \"%s\" not found.\n" %
-                      directory)
-                continue
-
             try:
-                listfiles = listdir(directory)
+                listfiles = os.listdir(directory)
             except Exception as e:
                 print("Directory Read Error: %s" % e)
 
-            for ifile in listfiles:
+            for file in listfiles:
                 if mod(cnt, 25):
                     pass
                 else:
                     self.wait("Examining File: ", cnt)
-                fullname = path.join(directory, ifile)
-                if path.isfile(fullname):
+                fullname = os.path.join(directory, file)
+                if os.path.isfile(fullname):
                     if not os.access(fullname, 6):
                         err = "ERROR: Read/Write permission denied."
                         err1 = "\t File: " + fullname
                         print(err)
                         print(err1)
-                        rwError += 1
+                        rw_error += 1
                         continue
                     try:
                         msfile = Mseed(fullname)
                         if msfile.isMseed():
+                            num_mseed_files += 1
+                            if directory in file_list:
+                                file_list[directory].append(file)
+                            else:
+                                file_list[directory] = []
+                                file_list[directory].append(file)
                             try:
                                 # simple test to determine if correct size file
                                 filesize = msfile.filesize
@@ -800,146 +857,106 @@ class MainWindow:
                                             str(blksize) + "). \n\t File: " +
                                             fullname)
                                     print(warn)
-                                    rwError += 1
+                                    rw_error += 1
                                     continue
                             except Exception:
                                 err = ("ERROR: Cannot determine file and "
                                        "block sizes. \n\t File:" + fullname)
                                 print(err)
-                                rwError += 1
+                                rw_error += 1
                                 continue
-                            NumMseedFiles += 1
-                            stat = msfile.FH.Stat.strip()
-
-                            if self.StatSelList:
-                                if stat not in self.StatSelList:
-                                    continue
-
-                            if directory in file_list:
-                                file_list[directory].append(ifile)
-                            else:
-                                file_list[directory] = []
-                                file_list[directory].append(ifile)
                         msfile.close()
                     except Exception as e:
-                        rwError += 1
+                        rw_error += 1
                         print("File Open Error: %s" % fullname, e)
                 cnt += 1
-
-                if (path.isdir(fullname) or (path.islink(fullname) and
-                                             not path.isfile(fullname))):
+                if (os.path.isdir(fullname) or (os.path.islink(fullname) and
+                                             not os.path.isfile(fullname))):
                     stack.append(fullname)
 
-        return file_list, NumMseedFiles, rwError
+        self.dir_trace_dict = {}
+        self.dir_trace_dict = file_list
+        self.update_dir_list()
+        return num_mseed_files, rw_error
 
-#######################################
-
-    def IndexFiles(self, ListInFiles):
+    def select_dir_trace(self, menu):
         """
-        based on traverse routine in "python standard library", Lundh pg 34
+        If directory menu selected, show trace menu
+        If trace menu selected, read hdrs
         """
-        file_list = {}
-        cnt = 1
-        NumMseedFiles = 0
-        directory = getcwd()
-        self.DataDirs.set(getcwd())
-        for ifile in ListInFiles:
-            if mod(cnt, 25):
-                pass
+        if menu == "dir":
+            dir = self.dir_menu.currentText()
+            if dir:
+                self.update_trace_list(dir)
+                self.trace_label.show()
+                self.trace_menu.show()
             else:
-                self.wait("Examining File: ", cnt)
-            fullname = path.join(directory, ifile)
-            if path.isfile(fullname):
-                try:
-                    newfile = Mseed(fullname)
-                    if newfile.isMseed():
-                        stat = newfile.FH.Stat.strip()
-                        if self.StatSelList:
-                            if stat not in self.StatSelList:
-                                continue
-
-                        NumMseedFiles += 1
-                        if directory in file_list:
-                            file_list[directory].append(ifile)
-                        else:
-                            file_list[directory] = []
-                            file_list[directory].append(ifile)
-                    newfile.close()
-                except Exception as e:
-                    print("File Open Error: %s" % e)
-            cnt += 1
-
-        return file_list, NumMseedFiles
-#######################################
+                self.trace_label.hide()
+                self.trace_menu.hide()
+        else:
+            trace = self.trace_menu.currentText()
+            if trace:
+                dir = self.dir_menu.currentText()
+                self.next_scan(dir, trace)
 
-    def ReadHdrs(self, ifile=""):
+    def next_scan(self, dir, trace):
         """
-        read headers of a given file build dictionary for quick access
+        Prepare for next scan, i.e. reset/clear/hide some widgets
         """
+        self.clear_slider()
+        self.read_hdrs(dir, trace, 0)
+        self.fill_slider()
+        self.hide_show("show")
+        self.header_endianess_text.setText(self.byte_order)
+        self.jump_box.setCurrentIndex(self.verb_var)
+        self.update_infobar("", "yellow")
 
-        # this is a bit of a hack, but I am unable to pass self.MseedFile.get()
-        # from buildHdrDisplay:Radiobutton:command
-        if not ifile:
-            ifile = self.MseedFile.get()
-            # if someone changes VerbVar before selecting file do nothing
-            if not ifile:
-                return
+        # hack, widget was behaving weird for some reason
+        # after showing it
+        self.slider_box.jump_menu.setEnabled(False)
+        self.slider_box.jump_menu.setEnabled(True)
 
-        FileAbsolutePath = path.join(self.SelDir.get(), ifile)
+    def read_hdrs(self, dir, trace, blk):
+        """
+        Read headers of a given file, build dictionary for quick access
+        """
+        file_absolute_path = os.path.join(dir, trace)
 
-        # create object (we've already tested all files for mseed)
-        # and get some base info
-        rdfile = Mseed(FileAbsolutePath)
+        rdfile = Mseed(file_absolute_path)
         if rdfile.isMseed():
             try:
                 filesize = rdfile.filesize
                 blksize = rdfile.blksize
             except Exception:
-                self.ClearAll(self.VeryVerboseVars)
-                self.Hdrs_fm.destroy()
-                self.HdrScale_fm.destroy()
-                self.BlkScale_fm.destroy()
-                self.BlksSelect_fm.destroy()
-                self.BlksTitle_fm.destroy()
-                self.Blks_fm.destroy()
-                err = "Cannot determine file and block sizes. File: " + ifile
-                self.addTextInfoBar(self.InfoString_l, err, 'red')
+                err = "Cannot determine file and block sizes. File: " + trace
+                self.update_infobar(err, "red")
                 rdfile.close()
                 return
-        else:
-            return
 
-        # initialize variables, lists, and dicts for later
-        self.BlkSize.set(blksize)
-        (numblocks, self.odd_size) = divmod(filesize, blksize)
-        self.NumBlocks.set(numblocks)
-        verbose = self.VerbVar.get()
-        if not self.OldMseedFile.get() or \
-           self.OldMseedFile.get() != FileAbsolutePath:
-            self.FixedHdrDict = {}
-            self.RateDict = {}
-            self.Blockettes = {}
-            self.keyList = []
-            self.UniqueList = []
-            self.UniqueSelectList = []
+            self.blk_size = blksize
+            (numblocks, self.odd_size) = divmod(filesize, blksize)
+            self.num_blocks = numblocks
+            verbose = self.verb_var
+
+            self.fixed_hdr_dict = {}
+            self.rate_dict = {}
+            self.blockettes_dict = {}
+            self.key_list = []
+            self.unique_list = []
+            self.unique_select_list = []
             n = 0
 
             # now build a dictionary of all fixed header info keyed to block
             # number looping over total number of blocks in files
             lastkey = -1
             while n < numblocks:
-
                 hdrs = rdfile.fixedhdr(n * blksize)
-                self.FixedHdrDict[n] = hdrs
-                # fact=hdrs[2][1]
-                # mult=hdrs[2][2]
-                # self.RateDict[n]=rdfile.calcrate(mult,fact)
-                self.RateDict[n] = rdfile.rate
+                self.fixed_hdr_dict[n] = hdrs
+                self.rate_dict[n] = rdfile.rate
 
                 # if unique selected build unique list
-                # if verbose == 3:
                 (SeqNum, DHQual, res, Stat, Loc, Chan, Net) = hdrs[0]
-                Rate = str(self.RateDict[n])
+                Rate = str(self.rate_dict[n])
                 Stat = Stat.strip().decode()
                 Chan = Chan.strip().decode()
                 Loc = Loc.strip().decode()
@@ -949,27 +966,25 @@ class MainWindow:
                 if key == lastkey:
                     pass
                 else:
-                    # self.keyList.append(key)
                     lastkey = key
-                    if key not in self.UniqueSelectList:
-                        self.UniqueSelectList.append(key)
-                    key = str(n) + ":" + key
-                    self.UniqueList.append(key)
+                    if key not in self.unique_select_list:
+                        self.unique_select_list.append(key)
+                    key = str(blk) + ":" + key
+                    self.unique_list.append(key)
 
                 # build Blockette dictionary keyed to block number
                 numblk = hdrs[3][3]
                 addseek = hdrs[3][6]
                 b = 0
+
                 # loop over number of blockettes following fixed header at
                 # block n
                 while b < numblk:
                     seekval = (n * blksize) + addseek
                     (blktype, next) = rdfile.typenxt(seekval)
                     # builds command to read specific blockette
-                    # getBlkCmd="blklist=rdfile.blk" + str(blktype) + \
-                    #           "(" + str(seekval) + ")"
                     blklist = eval("rdfile.blk" + str(blktype) +
-                                   "(" + str(seekval) + ")")
+                                "(" + str(seekval) + ")")
                     if blklist:
                         # handle awkward lists w/ muli-byte reserve, array, or
                         # calib fields
@@ -991,581 +1006,587 @@ class MainWindow:
                             tmplist.append(tup)
                             blklist = tmplist
                         # build Blockettes
-                        if n in self.Blockettes:
-                            self.Blockettes[n].append(blklist)
+                        if n in self.blockettes_dict:
+                            self.blockettes_dict[n].append(blklist)
                         else:
-                            self.Blockettes[n] = []
-                            self.Blockettes[n].append(blklist)
-
+                            self.blockettes_dict[n] = []
+                            self.blockettes_dict[n].append(blklist)
                     addseek = next
                     b += 1
                 n += 1
-        # get endianess before closing
-        self.ByteOrder.set(rdfile.byteorder)
-        rdfile.close()
+            # get endianess before closing
+            self.byte_order = rdfile.byteorder
+            rdfile.close()
 
-        # if unique proceed, else set up scales and entry fields.
-        if verbose == 3:
-            self.Unique(numblocks)
-        else:
-            try:
-                self.HdrScale_fm.destroy()
-                self.HdrScale_fm = Frame(self.FixedHdr_nb, borderwidth=2)
-                self.HdrScale_fm.pack(side='bottom', padx=5, pady=5, fill='x')
-                self.BlkScale_fm.destroy()
-                self.BlkScale_fm = Frame(self.Blockette_nb, borderwidth=2)
-                self.BlkScale_fm.pack(side='bottom', padx=5, pady=5, fill='x')
-            except Exception:
-                pass
-            self.buildJumpBox(self.HdrScale_fm, numblocks)
-
-            if FileAbsolutePath != self.OldMseedFile.get():
-                self.BlockNum.set(0)
-                self.JumpNum.set(0)
-
-            Label(self.HdrScale_fm, text='Block Number').pack(
-                side='left', anchor='w')
-
-            Scale(self.HdrScale_fm,
-                  variable=self.BlockNum,
-                  length=625,
-                  orient='horizontal',
-                  from_=0,
-                  to=numblocks - 1,
-                  tickinterval=numblocks / 6,
-                  command=Command(self.FillHdr)
-                  ).pack(side='left', anchor='w')
-
-            Label(self.BlkScale_fm, text='Block Number').pack(
-                side='left', anchor='w')
-            Scale(self.BlkScale_fm,
-                  variable=self.BlockNum,
-                  length=625,
-                  orient='horizontal',
-                  from_=0,
-                  to=numblocks - 1,
-                  tickinterval=numblocks / 6,
-                  command=Command(self.FillHdr)
-                  ).pack(side='left', anchor='w')
-
-            self.SetBlockettes(0)
+            self.set_blockettes(0)
             if not verbose:
-                self.Standard(0, 1)
+                self.fill_standard(int(blk))
             elif verbose == 1:
-                self.Verbose(0, 1)
+                self.fill_verbose(int(blk))
             elif verbose == 2:
-                self.VeryVerbose(0, 1)
-
-        self.OldMseedFile.set(FileAbsolutePath)
-
-#######################################
-    def SetBlockettes(self, key):
-        """
-        setup blockette frames for new key entry
-        """
-        self.BlockettesList = []
-        for blk in self.Blockettes[key]:
-            self.BlockettesList.append(blk[0])
-        self.BlockettesList.sort()
-        self.Blockette.set(self.BlockettesList[0])
-
-        self.BlksSelect_fm.destroy()
-        self.BlksSelect_fm = Frame(
-            self.Blockette_nb, relief='groove', borderwidth=2)
-        self.BlksSelect_fm.pack(side='top', pady=5, fill='x')
-
-        Label(self.BlksSelect_fm, text="Blockette:").grid(row=1, sticky=W)
-        Pmw.ComboBox(self.BlksSelect_fm,
-                     history=0,
-                     entry_width=self.e_width,
-                     entry_textvariable=self.Blockette,
-                     selectioncommand=Command(self.FillSelectBlk, key),
-                     scrolledlist_items=(self.BlockettesList)
-                     ).grid(row=1, column=1, sticky=W)
-
-# fill blockette info for first blockette found
-        self.FillSelectBlk(key, self.BlockettesList[0])
-
-#######################################
-    def VarInit(self, Vars):
-        """
-        clears/initializes entry fields on HdrDisplay
-        """
-
-        self.Hdrs_fm.destroy()
-        self.Hdrs_fm = Frame(self.FixedHdr_nb, relief='groove', borderwidth=2)
-        self.Hdrs_fm.pack(side='top', pady=5, fill='x')
-
-        c = r = n = 0
-        for var in Vars:
-            Label(self.Hdrs_fm, text=var[0]).grid(row=r, column=c, sticky=W)
-            Entry(self.Hdrs_fm,
-                  width=self.e_width,
-                  selectbackground='yellow',
-                  textvariable=var[1]).grid(row=r, column=c + 1, sticky=W)
-            if n == 5:
-                n = r = 0
-                c += 2
+                self.fill_vv(int(blk))
             else:
-                n += 1
-                r += 1
+                self.fill_unique()
 
-#######################################
-    def Unique(self, numblocks=0):
+    def clear_slider(self):
         """
-        setup hdr frames for new unique display
+        Reset blk slider between scans
         """
-        self.ClearAll(self.VeryVerboseVars)
-        self.Hdrs_fm.destroy()
-        self.Hdrs_fm = Frame(self.FixedHdr_nb, relief='groove', borderwidth=2)
-        self.Hdrs_fm.pack(side='top', pady=5, fill='x')
-        self.HdrScale_fm.destroy()
-        self.HdrScale_fm = Frame(self.FixedHdr_nb, borderwidth=2)
-        self.HdrScale_fm.pack(side='bottom', padx=5, pady=5, fill='x')
-        self.buildUniqueSelectBox(self.Hdrs_fm)
-        self.buildJumpBox(self.Hdrs_fm, numblocks)
+        # block/unblock widget signals
+        self.slider_box.slider.blockSignals(True)
+        self.slider_box.jump_menu.blockSignals(True)
+        self.slider_box.slider.setValue(0)
+        self.slider_box.jump_menu.clear()
+        self.slider_box.jump_menu.insertItem(0, "0")
+        self.slider_box.jump_menu.setCurrentIndex(0)
+        self.slider_box.jump_menu.blockSignals(False)
+        self.slider_box.slider.blockSignals(False)
 
-        self.FillUnique()
-
-#######################################
-    def Standard(self, key, init=0):
+    def fill_slider(self):
         """
-        setup standard vars for new key entry
+        Set slider range for chosen trace
         """
-        if init:
-            self.VarInit(self.StandardVars)
-
-        self.FillStandard(key)
+        # block/unblock widget signals
+        self.slider_box.slider.blockSignals(True)
+        self.slider_box.jump_menu.blockSignals(True)
+        self.slider_box.slider.setTickPosition(self.slider_box.slider.TicksBelow)
+        self.slider_box.slider.setRange(0, self.num_blocks-1)
+        i = 0
+        self.slider_box.jump_menu.clear()
+        while i < self.num_blocks:
+            self.slider_box.jump_menu.insertItem(i, str(i))
+            i += 1
+        self.slider_box.slider.setTickInterval(self.slider_box.slider.maximum() / 5)
+        self.slider_box.jump_menu.blockSignals(False)
+        self.slider_box.slider.blockSignals(False)
 
-#######################################
-    def Verbose(self, key, init=0):
+    def set_blockettes(self, key):
         """
-        setup verbose vars for new key entry
+        Setup blockette frames for new key entry
         """
+        self.blockettes_list = []
+        for blk in self.blockettes_dict[key]:
+            self.blockettes_list.append(blk[0])
+        self.blockettes_list.sort()
 
-        if init:
-            self.VarInit(self.VerboseVars)
-
-        self.FillVerbose(key)
+        # fill blockette info for first blockette found
+        self.fill_blockettes_tab(key, self.blockettes_list[0])
 
-#######################################
-    def VeryVerbose(self, key, init=0):
+    def fill_blockettes_tab(self, key, blktype):
         """
-        setup very verbose vars for new key entry
+        clears/initializes entry fields in Blockettes tab
         """
-
-        if init:
-            self.VarInit(self.VeryVerboseVars)
-
-        self.FillVeryVerbose(key)
-
-#######################################
-    def FillHdr(self, value):
-        """
-        fill header field on page based on block number
-        """
-        key = int(value)
-        self.JumpNum.set(value)
-        self.ByteOffset.set(self.BlockNum.get() * self.BlkSize.get())
-        verbose = self.VerbVar.get()
-        self.SetBlockettes(key)
-        if not verbose:
-            self.Standard(key)
-        elif verbose == 1:
-            self.Verbose(key)
-        elif verbose == 2:
-            self.VeryVerbose(key)
-
-        if self.odd_size:
-            info = ("WARNING: File size is not an integer number of block "
-                    "size (" + str(self.BlkSize.get()) + ")")
-            self.addTextInfoBar(self.InfoString_l, info, "orange")
-            self.odd_size = 0
-        else:
-            info = "Byte Offset: " + \
-                   str(self.BlockNum.get() * self.BlkSize.get())
-            self.addTextInfoBar(self.InfoString_l, info)
-
-#######################################
-    def FillSelectBlk(self, key, blktype):
-        """
-        clears/initializes entry fields on Blockette Display
-        """
-        self.BlksTitle_fm.destroy()
-        self.BlksTitle_fm = Frame(self.Blockette_nb, relief='groove',
-                                  borderwidth=2)
-        self.BlksTitle_fm.pack(side='top', pady=5, fill='x')
-
-        self.BlkInfo_b = Button(self.BlksTitle_fm,
-                                activebackground='green',
-                                background='lightblue',
-                                text="Blockette Info",
-                                activeforeground='black',
-                                command=Command(self.buildBlkInfo, blktype,
-                                                self.Blockette_nb))
-        self.BlkInfo_b.grid(row=0, column=1, padx=10)
-
-        self.Blks_fm.destroy()
-        self.Blks_fm = Frame(self.Blockette_nb, relief='groove', borderwidth=2)
-        self.Blks_fm.pack(side='top', pady=5, fill='x')
-
-        for block in self.Blockettes[key]:
+        for block in self.blockettes_dict[key]:
             if block[0] == blktype:
                 blocktuple = block
-
-        Label(self.BlksTitle_fm, text=BlkVars[blktype][0]).grid(
-            row=0, column=0)
-
-        c = r = n = 0
-        for var in range(len(BlkVars[blktype]) - 1):
-            Label(self.Blks_fm,
-                  text=BlkVars[blktype][var + 1]).grid(row=r, column=c,
-                                                       sticky=W)
-            Label(self.Blks_fm,
-                  text=blocktuple[var]).grid(row=r, column=c + 1, sticky=W)
-            if n == 5:
-                n = r = 0
-                c += 2
-            else:
-                n += 1
-                r += 1
-
-#######################################
-    def FillUnique(self):
-        """
-        Fills unique info on HdrDisplay
-        """
-        self.UniqueText = Pmw.ScrolledText(self.Hdrs_fm,
-                                           borderframe=1)
-        self.UniqueText.pack(side='bottom', fill='both', expand=1)
-
-        self.UniqueText.tag_config("list", foreground="blue")
-        self.UniqueText.tag_config("odd", backgroun="lightblue")
-
-        self.UniqueText.insert("end", "Block\tStat\tChan\tLoc\tNet\tRate\n",
-                               "list")
-
-        c = 0
-        for key in self.UniqueList:
-            for var in key.split(":"):
-                if c:
-                    self.UniqueText.insert("end", """%s\t""" % var, "odd")
-                else:
-                    self.UniqueText.insert("end", """%s\t""" % var)
-            self.UniqueText.insert("end", """\n""")
-            if c:
-                c = 0
-            else:
-                c += 1
-
-#######################################
-    def FillStandard(self, key):
+        for key, values in BlkVars.items():
+            if blktype == key:
+                boxes = self.blockettes_tab.findChildren(QtWidgets.QGroupBox)
+                for box in boxes:
+                    if box.objectName() == "Box1":
+                        menu = box.findChild(QtWidgets.QComboBox, "type_menu")
+                        menu.clear()
+                        menu.insertItem(0, str(blktype))
+                    elif box.objectName() == "Box2":
+                        layout = box.layout()
+                        # delete previous labels if they exist
+                        if layout is not None:
+                            while layout.count():
+                                item = layout.takeAt(0)
+                                widget = item.widget()
+                                if widget is not None:
+                                    widget.setParent(None)
+                        # create new labels
+                        label = QtWidgets.QLabel()
+                        label.setText(str(values[0]))
+                        layout.addWidget(label)
+                        layout.addWidget(self.blkinfo_btn)
+                        layout.addStretch()
+                    else:
+                        layout = box.layout()
+                        # delete previous labels if they exist
+                        if layout is not None:
+                            while layout.count():
+                                item = layout.takeAt(0)
+                                widget = item.widget()
+                                if widget is not None:
+                                    widget.setParent(None)
+                        # create new labels
+                        for x in range(1, len(values)):
+                            label = QtWidgets.QLabel()
+                            label.setText(str(values[x]) + " " + str(blocktuple[x-1]))
+                            layout.addWidget(label)
+
+    def blkinfo_window(self):
+        """
+        Popup window for blk info button
+        """
+        self.info_window = QtWidgets.QWidget()
+        self.info_window.resize(650,400)
+        self.info_window.setWindowTitle("Blockette Information")
+
+        # widgets
+        blk_label = QtWidgets.QLabel("Blockette:")
+        blk_menu = QtWidgets.QComboBox()
+        blk_menu.activated.connect(lambda: info_box.setText(
+            BlkInfoDict[int(blk_menu.currentText())])\
+                                   if blk_menu.currentText().isdigit() else \
+                                    info_box.setText(BlkInfoDict[blk_menu.currentText()]))
+        info_box = QtWidgets.QTextEdit()
+        done_btn = QtWidgets.QPushButton("Done")
+        done_btn.setStyleSheet("QPushButton{background-color:lightblue;}\
+                                QPushButton::hover{background-color:red;}")
+        done_btn.clicked.connect(lambda: self.info_window.close())
+
+        top_layout = QtWidgets.QHBoxLayout()
+        top_layout.addWidget(blk_label)
+        top_layout.addWidget(blk_menu)
+        top_layout.addStretch()
+
+        main_layout = QtWidgets.QVBoxLayout(self.info_window)
+        main_layout.addLayout(top_layout)
+        main_layout.addWidget(info_box)
+        main_layout.addWidget(done_btn)
+
+        for key in BlkInfoDict.keys():
+            blk_menu.addItem(str(key))
+        blk_menu.setCurrentText(str(self.blockettes_list[0]))
+
+        info_box.setText(BlkInfoDict[self.blockettes_list[0]])
+
+        self.info_window.show()
+
+    def fill_standard(self, key):
         """
         Fills standard info on HdrDisplay
         """
+        try:
+            standard_widgets = self.standard_box.findChildren(QtWidgets.QLineEdit)
+            rate = self.rate_dict[key]
+            vars = []
+            # SeqNum, DHQual, res, Stat, Loc, Chan, Net
+            vars.append(self.fixed_hdr_dict[key][0])
+            vars = list(itertools.chain.from_iterable(vars))
+            vars = vars[3:] # remove SeqNum, DHQual, res
+            vars.append(rate)
+
+            for x in range(len(vars)):
+                widget = standard_widgets[x]
+                var = vars[x]
+                try:
+                    var = var.strip().decode()
+                except Exception:
+                    pass
+                widget.setText(str(var))
 
-        # cleanup existing vars and reset to new key location
-        self.ClearAll(self.StandardVars)
-        (SeqNum, DHQual, res, Stat, Loc, Chan, Net) = self.FixedHdrDict[key][0]
-        self.SeqNum.set(SeqNum)
-        self.DQual.set(DHQual)
-        self.Resv.set(res)
-        self.Station.set(Stat)
-        self.Channel.set(Chan)
-        self.LocCode.set(Loc)
-        self.NetCode.set(Net)
-        (numsamp, sampfact, sampmult) = self.FixedHdrDict[key][2]
-        rate = self.RateDict[key]
-        self.SampleRate.set(rate)
+        # if user inputs invalid blk num
+        except Exception:
+            return
 
-#######################################
-    def FillVerbose(self, key):
+    def fill_verbose(self, key):
         """
         Fills verbose info on HdrDisplay
         """
+        try:
+            verbose_widgets = self.verbose_box.findChildren(QtWidgets.QLineEdit)
+            rate = self.rate_dict[key]
+            vars = []
+            # SeqNum, DHQual, res, Stat, Loc, Chan, Net
+            vars.append(self.fixed_hdr_dict[key][0])
+            vars.append([str(rate)])
+            # Year, Day, Hour, Min, Sec, junk, Micro
+            vars.append(self.fixed_hdr_dict[key][1])
+            vars = list(itertools.chain.from_iterable(vars))
+            vars = vars[3:] # remove SeqNum, DHQual, res
+            del vars[-2] # remove junk
+
+            for x in range(len(vars)):
+                widget = verbose_widgets[x]
+                var = vars[x]
+                try:
+                    var = var.strip().decode()
+                except Exception:
+                    pass
+                widget.setText(str(var))
 
-        # cleanup existing vars and reset to new key location
-        self.ClearAll(self.VerboseVars)
-        self.FillStandard(key)
-        (Year, Day, Hour, Min, Sec, junk, Micro) = self.FixedHdrDict[key][1]
-        self.Year.set(Year)
-        self.Jday.set(Day)
-        self.Hour.set(Hour)
-        self.Min.set(Min)
-        self.Sec.set(Sec)
-        self.Micro.set(Micro)
+        # if user inputs invalid blk num
+        except Exception:
+            return
 
-#######################################
-    def FillVeryVerbose(self, key):
+    def fill_vv(self, key):
         """
         Fills very verbose info on HdrDisplay
         """
+        try:
+            vv_widgets = self.vv_box.findChildren(QtWidgets.QLineEdit)
+            rate = self.rate_dict[key]
+            vars = []
+            # SeqNum, DHQual, res, Stat, Loc, Chan, Net
+            vars.append(self.fixed_hdr_dict[key][0])
+            vars.append([str(rate)])
+            # Year, Day, Hour, Min, Sec, junk, Micro
+            vars.append(self.fixed_hdr_dict[key][1])
+            # NumSamp, SampFact, SampMult
+            vars.append(self.fixed_hdr_dict[key][2])
+            # act, io, DQual, numblk, timcorr, bdata, bblock
+            vars.append(self.fixed_hdr_dict[key][3])
+            vars = list(itertools.chain.from_iterable(vars))
+            del vars[-12] # remove junk
+
+            for x in range(len(vars)):
+                widget = vv_widgets[x]
+                var = vars[x]
+                try:
+                    var = var.strip().decode()
+                except Exception:
+                    pass
+                widget.setText(str(var))
 
-        # cleanup existing vars and reset to new key location
-        self.ClearAll(self.VeryVerboseVars)
-        self.FillVerbose(key)
-        (NumSamp, SampFact, SampMult) = self.FixedHdrDict[key][2]
-        (act, io, DQual, numblk, timcorr, bdata,
-         bblock) = self.FixedHdrDict[key][3]
-        self.NumSamp.set(NumSamp)
-        self.SampFact.set(SampFact)
-        self.SampMult.set(SampMult)
-        self.ActFlag.set(act)
-        self.IOFlag.set(io)
-        self.DQFlag.set(DQual)
-        self.NumBlockettes.set(numblk)
-        self.TimeCorr.set(timcorr)
-        self.BeginData.set(bdata)
-        self.FstBlkett.set(bblock)
-
-##########################################
-    def FlushDict(self):
-        """
-        clears dictionaries and OldMseedFile. Allows user to apply a reset and
-        dynamically monitor changes to mseed files.
-        """
-
-        # clear selected directory and file
-        self.MseedFile.set("")
-        self.SelDir.set("")
-
-        # clear variables and destroy frames
-        self.ClearAll(self.VeryVerboseVars)
-        self.Hdrs_fm.destroy()
-        self.HdrScale_fm.destroy()
-        self.BlkScale_fm.destroy()
-        self.BlksSelect_fm.destroy()
-        self.BlksTitle_fm.destroy()
-        self.Blks_fm.destroy()
-
-        # now clear dictionaries and set OldMseedFile to blank
-        self.OldMseedFile.set("")
-        self.FixedHdrDict = {}
-        self.RateDict = {}
-        self.Blockettes = {}
-        self.keyList = []
-        self.UniqueList = []
-
-##########################################
-
-    def getPath(self, var, clear=1):
-        """
-        Concatonate paths
-        """
-        self.var = var
-        if clear:
-            self.var.set('')
-        newpath_dd = DirectoryDialog(self.root)
-        self.path = newpath_dd.go(dir_or_file=getcwd())
-        if self.path is not None:
-            if self.var.get():
-                self.var.set(self.var.get() + ':')
-            if len(self.path) == 1 and self.path[0] == "/":
-                self.var.set(self.var.get() + self.path)
-            elif self.path[-1] == "/":
-                self.var.set(self.var.get() + self.path[:-1])
-            else:
-                self.var.set(self.var.get() + self.path)
-
-##################################################################
+        # if user inputs invalid blk num
+        except Exception:
+            return
 
-    def ClearTxt(self, var):
+    def fill_unique(self):
         """
-        clear text
+        Fills unique info on HdrDisplay
         """
-        var.clear()
-
-##################################################################
+        # text colors
+        Blue = QtGui.QColor(0,0,153)
+        Black = QtGui.QColor(0,0,0)
+
+        # fill drop down menus
+        self.unique_box.keys_menu.clear()
+        self.unique_box.keys_menu.addItem("*")
+        self.unique_box.keys_menu.addItem(f'{self.unique_select_list[0]}')
+
+        self.unique_box.unique_jump.blockSignals(True)
+        i = 0
+        while i < self.num_blocks:
+            self.unique_box.unique_jump.addItem(str(i))
+            i += 1
+        self.unique_box.unique_jump.blockSignals(False)
+
+        # fill text box
+        text = "Block\tStat\tChan\tLoc\tNet\tRate"
+        self.unique_box.unique_infobox.setTextColor(Blue)
+        self.unique_box.unique_infobox.setText(text)
+        self.unique_box.unique_infobox.setTextColor(Black)
+        data = []
+        data.append(self.unique_list[0].split(":"))
+        data = list(itertools.chain.from_iterable(data))
+        data = '\t'.join(str(i) for i in data)
+        self.unique_box.unique_infobox.append(data)
 
-    def ClearAll(self, varlist):
+    def wait(self, words, cnt):
         """
-        clear a variable list
+        routine to put words on info bar, used to count traces
+        being examined
         """
-        self.addTextInfoBar(self.InfoString_l)
-        for var in varlist:
-            self.setValue(var[1])
-
-#######################################
+        text = words + str(cnt)
+        self.update_infobar(text, "lightblue")
 
-    def setValue(self, var, value=''):
+    def update_dir_list(self):
         """
-        Sets Value of var
+        Update directory list for each scan
         """
-        var.set(value)
+        self.dir_menu.clear()
+        self.dir_menu.insertItem(0, "")
+        for key in self.dir_trace_dict:
+            self.dir_menu.addItem(key)
+        self.dir_trace_box.show()
 
-#######################################
-
-    def addTextInfoBar(self, widget, str='', bg='yellow'):
+    def update_trace_list(self, dir):
         """
-        Adds Text To InfoBar
+        Update trace list for each scan
         """
-        widget.configure(background=bg, text=str)
+        self.trace_menu.clear()
+        self.trace_menu.insertItem(0, "")
+        for key, values in self.dir_trace_dict.items():
+            if dir == key:
+                values.sort()
+                for trace in values:
+                    self.trace_menu.addItem(trace)
 
-##################################################################
+    def update_infobar(self, text, color):
+        """
+        Update info bar when certain actions happen
+        """
+        self.infobar.setText(text)
+        self.infobar.setStyleSheet("background-color:" + color)
+        QtWidgets.QApplication.beep()
 
-    def killWindow(self, widget):
+    def update_slider(self, widget):
         """
-        Destroy Widget and Set InfoBar to Default
+        Get new blk number if any of the slider related widgets
+        are toggled, and update hdr info
         """
-        widget.destroy()
-        self.addTextInfoBar(self.InfoString_l)
+        try:
+            if widget == "slider":
+                value = self.slider_box.slider.value()
+                self.slider_box.jump_menu.setCurrentText(str(value))
+                self.unique_box.unique_jump.setCurrentText(str(value))
+            elif widget == "menu":
+                value = self.slider_box.jump_menu.currentText()
+                self.slider_box.slider.setValue(int(value))
+                self.unique_box.unique_jump.setCurrentText(str(value))
+            else:
+                value = self.unique_box.unique_jump.currentText()
+                self.slider_box.slider.setValue(int(value))
+                self.slider_box.jump_menu.setCurrentText(str(value))
+                self.vv_rbtn.setChecked(True)
+                self.verb_var = 2
+                self.jump_box.setCurrentIndex(2)
+
+            # update hdr info & info bar
+            self.maybe_read_hdrs()
+            byte_offset = int(value) * int(self.blk_size)
+            text = "Byte Offset: " + str(byte_offset)
+            self.update_infobar(text, "yellow")
+
+        # if user inputs invalid blk num
+        except Exception:
+            return
 
-#######################################
+    def maybe_read_hdrs(self):
+        """
+        If certain conditions are met, call read hdrs
+        """
+        if not self.dir_menu.isHidden():
+            dir = self.dir_menu.currentText()
+            if dir:
+                if not self.trace_menu.isHidden():
+                    trace = self.trace_menu.currentText()
+                    if trace:
+                        blk = self.slider_box.jump_menu.currentText()
+                        self.read_hdrs(dir, trace, blk)
 
-    def wait(self, words, cnt):
+    def flush_dict(self):
         """
-        routine to put words on info bar, used to count traces
-        being examined
+        clears dictionaries. Allows user to apply a reset and
+        dynamically monitor changes to mseed files.
         """
+        self.fixed_hdr_dict = {}
+        self.rate_dict = {}
+        self.blockettes_dict = {}
+        self.key_list = []
+        self.unique_list = []
+        self.clear_slider()
+        self.header_endianess_text.clear()
+        self.hide_show("hide")
+        QtWidgets.QApplication.beep()
+
+class SliderBox(QtWidgets.QGroupBox):
+    """
+    Box that holds all the blockette slider widgets
+    """
+    def __init__(self):
+        """
+        Init widgets for blockette parsing
+        """
+        super().__init__()
+        self.setStyleSheet("QGroupBox{border:0;}")
+        # widgets
+        label1 = QtWidgets.QLabel("Jump To Block #:")
+        self.jump_menu = QtWidgets.QComboBox()
+        self.jump_menu.setMinimumWidth(100)
+        self.jump_menu.setEditable(True)
+        self.jump_menu.insertItem(0, "0")
+        label2 = QtWidgets.QLabel("Block Number")
+        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
+        self.slider.setTickPosition(self.slider.NoTicks)
+
+        # layouts
+        main_layout = QtWidgets.QVBoxLayout(self)
+        menu_layout = QtWidgets.QVBoxLayout()
+        slider_layout = QtWidgets.QHBoxLayout()
+        menu_layout.addWidget(label1, alignment=QtCore.Qt.AlignCenter)
+        menu_layout.addWidget(self.jump_menu, alignment=QtCore.Qt.AlignCenter)
+        slider_layout.addWidget(label2)
+        slider_layout.addWidget(self.slider)
+
+        # add to main layout
+        main_layout.addLayout(menu_layout)
+        main_layout.addLayout(slider_layout)
+
+class StandardBox(QtWidgets.QGroupBox):
+    """
+    Box that holds all the standard info widgets
+    """
+    def __init__(self, standard_vars):
+        """
+        Create standard widgets
+        """
+        super().__init__()
+
+        # layout
+        v_layout = QtWidgets.QVBoxLayout(self)
+        h_layout = QtWidgets.QHBoxLayout()
+        col1 = QtWidgets.QVBoxLayout()
+        col2 = QtWidgets.QVBoxLayout()
+
+        # widgets
+        for x in range(len(standard_vars)):
+            label = QtWidgets.QLabel(str(standard_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
+
+            col1.addWidget(label)
+            col2.addWidget(line_edit)
+
+        # add to layout
+        h_layout.addLayout(col1)
+        h_layout.addLayout(col2)
+        v_layout.addLayout(h_layout)
+
+        v_layout.addStretch()
+
+class VerboseBox(QtWidgets.QGroupBox):
+    """
+    Box that holds all the verbose info widgets
+    """
+    def __init__(self, standard_vars, v_vars):
+        """
+        Create verbose widgets
+        """
+        super().__init__()
+        # layout
+        v_layout = QtWidgets.QVBoxLayout(self)
+        h_layout = QtWidgets.QHBoxLayout()
+        col1 = QtWidgets.QVBoxLayout()
+        col2 = QtWidgets.QVBoxLayout()
+        col3 = QtWidgets.QVBoxLayout()
+        col4 = QtWidgets.QVBoxLayout()
+
+        # widgets
+        for x in range(len(standard_vars)):
+            label = QtWidgets.QLabel(str(standard_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
+
+            col1.addWidget(label)
+            col2.addWidget(line_edit)
+
+        for x in range(len(v_vars)):
+            label = QtWidgets.QLabel(str(v_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
+
+            if x == 0:
+                col1.addWidget(label)
+                col2.addWidget(line_edit)
+            else:
+                col3.addWidget(label)
+                col4.addWidget(line_edit)
+
+        col3.addSpacing(25)
+        col4.addSpacing(25)
+
+        # add to layout
+        h_layout.addLayout(col1)
+        h_layout.addLayout(col2)
+        h_layout.addLayout(col3)
+        h_layout.addLayout(col4)
+        v_layout.addLayout(h_layout)
+        v_layout.addStretch()
+
+class VVBox(QtWidgets.QGroupBox):
+    """
+    Box that holds all the very verbose info widgets
+    """
+    def __init__(self, first_vv_vars, standard_vars, v_vars, vv_vars):
+        """
+        Create very verbose widgets
+        """
+        super().__init__()
+        # layout
+        v_layout = QtWidgets.QVBoxLayout(self)
+        h_layout = QtWidgets.QHBoxLayout()
+        col1 = QtWidgets.QVBoxLayout()
+        col2 = QtWidgets.QVBoxLayout()
+        col3 = QtWidgets.QVBoxLayout()
+        col4 = QtWidgets.QVBoxLayout()
+        col5 = QtWidgets.QVBoxLayout()
+        col6 = QtWidgets.QVBoxLayout()
+        col7 = QtWidgets.QVBoxLayout()
+        col8 = QtWidgets.QVBoxLayout()
+
+        # widgets
+        for x in range(len(first_vv_vars)):
+            label = QtWidgets.QLabel(str(first_vv_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
+
+            col1.addWidget(label)
+            col2.addWidget(line_edit)
+
+        for x in range(len(standard_vars)):
+            label = QtWidgets.QLabel(str(standard_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
+
+            if x <= 2:
+                col1.addWidget(label)
+                col2.addWidget(line_edit)
+            else:
+                col3.addWidget(label)
+                col4.addWidget(line_edit)
+
+        for x in range(len(v_vars)):
+            label = QtWidgets.QLabel(str(v_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
 
-        txt = words + str(cnt)
-        self.root.update()
-        self.addTextInfoBar(self.InfoString_l, txt, 'lightblue')
-
-##################################################################
-
-    def Exit(self):
-        """
-        a no questions asked exit
-        """
-        sys.exit(0)
-
-##################################################################
-
-    def displayBlkInfo(self, type):
-        text = BlkInfoDict[type]
-        self.BlkInfoText.settext(text)
-
-##################################################################
-    def buildHelp(self, master):
-        """
-        Populate Help NoteBook
-        """
-        self.Help_nb = master.add('Help')
-
-        self.HelpText = Pmw.ScrolledText(self.Help_nb,
-                                         borderframe=1)
-        self.HelpText.pack(side='bottom', fill='both', expand=1)
-
-        self.HelpText.tag_config("hdr1", foreground="blue")
-        self.HelpText.tag_config("hdr2", foreground="darkgreen")
-        self.HelpText.tag_config("bttn", foreground="red")
-
-        self.HelpText.insert("end", "NAME", "hdr1")
-        self.HelpText.insert("end", """
-   mseedpeek - GUI for displaying mseed file headers.\n""")
-
-        self.HelpText.insert("end", "\nVERSION", "hdr1")
-        self.HelpText.insert("end", """
-   %s\n""" % VERSION)
-
-        self.HelpText.insert("end", "\nSYNOPSIS", "hdr1")
-        self.HelpText.insert("end", """
-   mseedpeek
-   mseedpeek -#
-   mseedpeek -f file_names\n""")
-
-        self.HelpText.insert("end", "\nOPTIONS", "hdr1")
-        self.HelpText.insert("end", """
-   -# returns version number
-   -f file_name(s) - accepts command line input for files to inspect (wildcards accepted)\n""")  # noqa: E501
-
-        self.HelpText.insert("end", "\nDESCRIPTION", "hdr1")
-        self.HelpText.insert("end", """
-   mseedpeek has three notebooks: """)
-        self.HelpText.insert("end", "[Trace Headers]", "hdr2")
-        self.HelpText.insert("end", "[Blockettes]", "hdr2")
-        self.HelpText.insert("end", """, and """)
-        self.HelpText.insert("end", "[Help]", "hdr2")
-        self.HelpText.insert("end", """.""")
-
-        self.HelpText.insert("end", """
-   The """)
-        self.HelpText.insert("end", "[Trace Headers]", "hdr2")
-        self.HelpText.insert("end", """ notebook displays various the fixed
-   header in four levels of verbosity.\n   The """)
-        self.HelpText.insert("end", "[Blockettes]", "hdr2")
-        self.HelpText.insert("end", """ notebook displays blockette information.\n""")  # noqa: E501
-
-        self.HelpText.insert("end", "\n   [Trace Headers]", "hdr2")
-        self.HelpText.insert("end", """
-   General:
-      >> specify/load directories for building trace db
-      >> select trace for header display
-      >> select level of verbosity for display
-
-   Buttons:\n""")
-        self.HelpText.insert("end", "      <Build Trace db>", "bttn")
-        self.HelpText.insert("end", """: Searchs the directories listed in the "Data-
-         Directories" entry box (a colon separated list) and builds a list of mseed
-         files found indexing them on unique values of <dir>:<file_name>. It then
-         creates a dropdown menu with entries for each data directory found.\n""")  # noqa: E501
-        self.HelpText.insert("end", "      <Find>", "bttn")
-        self.HelpText.insert("end", """: Launches a file browser allowing the user to
-         add directories to the "Data Directories" entry box. Double clicking selects
-         the new directory.\n""")  # noqa: E501
-        self.HelpText.insert("end", "      <Clear>", "bttn")
-        self.HelpText.insert(
-            "end", """: Clears the "Data Directories" entry box.\n""")
-
-        self.HelpText.insert("end", """
-        By selecting a data directory a dropdown menu is created for
-        trace selection. Selecting a trace from this menu will create
-        a header display.
-
-   Radio Buttons:\n""")
-        self.HelpText.insert("end", "      <Standard>", "bttn")
-        self.HelpText.insert("end", """: This is the default. It displays Station, Channel, Location Code,
-        Net Code, and the nominal Sample Rate.\n""")  # noqa: E501
-        self.HelpText.insert("end", "      <Verbose>", "bttn")
-        self.HelpText.insert(
-            "end", """: Standard display plus time of block.\n""")
-        self.HelpText.insert("end", "      <Very Verbose>", "bttn")
-        self.HelpText.insert(
-            "end", """: Verbose plus the rest of the mseed fixed header fields.\n""")  # noqa: E501
-        self.HelpText.insert("end", "      <Unique>", "bttn")
-        self.HelpText.insert(
-            "end", """: This displays changes in the Standard fields within a mseed file.\n""")  # noqa: E501
-        self.HelpText.insert("end", """
-
-   Slider Scale and """)
-        self.HelpText.insert("end", "<Jump To Block #>", "bttn")
-        self.HelpText.insert("end", """ Button:
-        At the bottom of the page is a scale bar showing block numbers. Sliding
-        the bar scans through all fixed headers for the selected mseed file.\n""")  # noqa: E501
-
-        self.HelpText.insert("end", "\n   <Flush Dictionaries>", "bttn")
-        self.HelpText.insert("end", """: Clears cached trace header data.
-        As you view mseed headers, mseedpeek maintains a cache of previously
-        viewed headers for quick, future access. If you wish to monitor changes
-        to mseed files you need to flush the dictionaries so that the new
-        changes will be displayed.\n\n""")
-
-        self.HelpText.insert("end", "   [Blockettes]", "hdr2")
-        self.HelpText.insert("end", """:
-        The 'Blockettes' notebook displays all blockettes found for the select
-        mseed file in a dropdown menu. By selecting a blockette from the dropdown
-        menu, the contents of the blockette will be displayed.\n""")  # noqa: E501
-
-        self.HelpText.insert("end", "      <Blockette Info>", "bttn")
-        self.HelpText.insert("end", """: Displays a pop-up window with a definition of the SEED Blockette.
-
-        At the bottom of the page is a scale bar showing block numbers and
-        Sliding the bar scans through all blockettes for the selected mseed file.\n""")  # noqa: E501
-
-        self.HelpText.insert("end", "\nKEYWORDS", "hdr1")
-        self.HelpText.insert("end", """
-   mseed; header information\n""")
-
-        self.HelpText.insert("end", "\nSEE ALSO", "hdr1")
-        self.HelpText.insert("end", """
-   SEED manual (pdf), fixhdr, mseedhdr\n""")
-
-        self.HelpText.insert("end", "\nAUTHOR", "hdr1")
-        self.HelpText.insert("end", """
-   Bruce Beaudoin <bruce@passcal.nmt.edu>
-""")
-
-
-if __name__ == '__main__':
+            if x <= 3:
+                col3.addWidget(label)
+                col4.addWidget(line_edit)
+            else:
+                col5.addWidget(label)
+                col6.addWidget(line_edit)
+
+        for x in range(len(vv_vars)):
+            label = QtWidgets.QLabel(str(vv_vars[x]))
+            line_edit = QtWidgets.QLineEdit()
+
+            if x <= 3:
+                col5.addWidget(label)
+                col6.addWidget(line_edit)
+            elif x > 3 and x <= 6:
+                col7.addWidget(label)
+                col8.addWidget(line_edit)
+            else:
+                col7.addWidget(label)
+                col8.addWidget(line_edit)
+
+        # add to layout
+        h_layout.addLayout(col1)
+        h_layout.addLayout(col2)
+        h_layout.addLayout(col3)
+        h_layout.addLayout(col4)
+        h_layout.addLayout(col5)
+        h_layout.addLayout(col6)
+        h_layout.addLayout(col7)
+        h_layout.addLayout(col8)
+        v_layout.addLayout(h_layout)
+        v_layout.addStretch()
+
+class UniqueBox(QtWidgets.QGroupBox):
+    """
+    Box that holds all the unique info widgets
+    """
+    def __init__(self):
+        """
+        Create unique widgets
+        """
+        super().__init__()
+        layout = QtWidgets.QVBoxLayout(self)
+        select_keys_label = QtWidgets.QLabel("Select Keys:")
+        self.keys_menu = QtWidgets.QComboBox()
+        self.keys_menu.setEditable(True)
+        jump_label = QtWidgets.QLabel("Jump To Block #:")
+        self.unique_jump = QtWidgets.QComboBox()
+        self.unique_jump.setEditable(True)
+        self.unique_infobox = QtWidgets.QTextEdit()
+
+        layout.addWidget(select_keys_label)
+        layout.addWidget(self.keys_menu)
+        layout.addWidget(jump_label)
+        layout.addWidget(self.unique_jump)
+        layout.addWidget(self.unique_infobox)
+        layout.addStretch()
+
+if __name__ == "__main__":
     main()
diff --git a/setup.py b/setup.py
index fb8a9dfaee4cca263abc99e1c54dd22fc51a6a1a..d7bb59b483afa0674989d2a417613d989360060e 100644
--- a/setup.py
+++ b/setup.py
@@ -30,12 +30,13 @@ setup(
             'mseedpeek=mseedpeek.mseedpeek:main',
         ],
     },
-    install_requires=['Pmw @ https://github.com/schrodinger/pmw-patched/archive/master.tar.gz'],
+    install_requires=['pyside2'],
     setup_requires=[],
     extras_require={
         'dev': [
             'flake8',
             'tox',
+            'pyside2',
         ]
     },
     license="GNU General Public License v3",
@@ -45,6 +46,6 @@ setup(
     name='mseedpeek',
     packages=find_packages(include=['mseedpeek']),
     url='https://git.passcal.nmt.edu/passoft/mseedpeek',
-    version='2022.1.0.0',
+    version='2023.1.0.0',
     zip_safe=False,
 )