diff --git a/HISTORY.rst b/HISTORY.rst
index a11eba1dbaaf89fe3edd23aef4f0ce3f323948b5..cc55785c82c0e320b44944cc5b4fac2e0d37e20e 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -6,3 +6,8 @@ History
 --------
 
 * First release
+
+2023.1.0.1
+--------
+
+* Fixed a problem with SOHViewer not fitting on smaller resolutions
diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml
index 62621b47e87de2ea12d6334f6c0437ebba27707b..85c88f6da3497683abd645dd3caf947c640ec730 100644
--- a/conda.recipe/meta.yaml
+++ b/conda.recipe/meta.yaml
@@ -1,6 +1,6 @@
 package:
   name: sohviewer
-  version: 2023.1.0.0
+  version: 2023.1.0.1
 
 source:
   path: ../
diff --git a/setup.py b/setup.py
index c1e87d5a3c4b8d50f5b49600df7619c752abdb22..f39f957cfba0bbc849b3a904505f8e172cb4304b 100644
--- a/setup.py
+++ b/setup.py
@@ -51,6 +51,6 @@ setup(
     name='sohstationviewer',
     packages=find_packages(include=['sohstationviewer*']),
     url='https://git.passcal.nmt.edu/software_public/passoft/sohstationviewer',
-    version='2023.1.0.0',
+    version='2023.1.0.1',
     zip_safe=False,
 )
diff --git a/sohstationviewer/conf/constants.py b/sohstationviewer/conf/constants.py
index 887062311ad6caced57d3e2729d62e45f55a108b..eaa03f70e9de9a08e258a826332c182bcb828994 100644
--- a/sohstationviewer/conf/constants.py
+++ b/sohstationviewer/conf/constants.py
@@ -1,7 +1,7 @@
 from typing import Literal
 
 # The current version of SOHStationViewer
-SOFTWARE_VERSION = '2023.1.0.0'
+SOFTWARE_VERSION = '2023.1.0.1'
 
 # waveform pattern
 WF_1ST = 'A-HLM-V'
diff --git a/sohstationviewer/database/extract_data.py b/sohstationviewer/database/extract_data.py
index 55997e90a683cc8d119fa26aebc419ebb0abe3ff..2a49d557064a2e5c78f127f6bc1e9f13c86bc7d4 100755
--- a/sohstationviewer/database/extract_data.py
+++ b/sohstationviewer/database/extract_data.py
@@ -160,3 +160,35 @@ def get_color_ranges():
             clr_labels[idx].append("+/- {:,} counts".format(cnt))
         clr_labels[idx].append("> {:,} counts".format(cnt))
     return range_names, all_square_counts, clr_labels
+
+
+def create_assign_string_for_db_query(col: str, val: str) -> str:
+    """
+    Create assign db string that assign value in single quote signs if val is
+    a string or to NULL if val is empty str
+    :param col: column name in the db table
+    :param val: value to be assigned to the column
+    :return: the assign db string
+    """
+    return f"{col}='{val}'" if val != '' else f"{col}=NULL"
+
+
+def get_params():
+    # get parameter list from database
+    param_rows = execute_db("SELECT param from parameters")
+    return sorted([d[0] for d in param_rows])
+
+
+def get_channel_info(chan_id: str, data_type: str):
+    # get channel info from DB
+    sql = f"SELECT * FROM Channels " \
+          f"WHERE channel='{chan_id}' AND dataType='{data_type}'"
+    chan_info = execute_db_dict(sql)[0]
+    return chan_info
+
+
+def get_param_info(param: str):
+    # get all info of a param from DB
+    sql = f"SELECT * FROM Parameters WHERE param='{param}'"
+    param_info = execute_db_dict(sql)[0]
+    return param_info
diff --git a/sohstationviewer/images/edit_icon_black_background.png b/sohstationviewer/images/edit_icon_black_background.png
new file mode 100644
index 0000000000000000000000000000000000000000..12b52393c45fc4d156d15a83e6f4156542dec75a
Binary files /dev/null and b/sohstationviewer/images/edit_icon_black_background.png differ
diff --git a/sohstationviewer/images/edit_icon_white_background.png b/sohstationviewer/images/edit_icon_white_background.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f374595e8ed857d346ba0af0fc3e37fb1863447
Binary files /dev/null and b/sohstationviewer/images/edit_icon_white_background.png differ
diff --git a/sohstationviewer/main.py b/sohstationviewer/main.py
index a25d1b15a3f6e3d3e04707a131472287d279c00d..e09e707700dec1f93cad45a377edd9c7b663dbf0 100755
--- a/sohstationviewer/main.py
+++ b/sohstationviewer/main.py
@@ -6,6 +6,7 @@ import traceback
 from pathlib import Path
 
 from PySide2 import QtWidgets
+from PySide2.QtGui import QGuiApplication
 from PySide2.QtWidgets import QMessageBox
 
 from sohstationviewer.view.main_window import MainWindow
@@ -14,7 +15,6 @@ from sohstationviewer.conf.config_processor import (
     BadConfigError,
 )
 
-
 # Enable Layer-backing for MacOs version >= 11
 # Only needed if using the pyside2 library with version>=5.15.
 # Layer-backing is always enabled in pyside6.
@@ -26,47 +26,91 @@ if os_name == 'macOS':
     os.environ['QT_MAC_WANTS_LAYER'] = '1'
 
 
-def main():
-    # Change the working directory so that relative paths work correctly.
+def fix_relative_paths() -> None:
+    """
+    Change the working directory so that the relative paths in the code work
+    correctly.
+    """
     current_file_path = os.path.abspath(__file__)
     current_file_dir = Path(current_file_path).parent
     os.chdir(current_file_dir)
 
+
+def resize_windows(main_window: MainWindow):
+    """
+    Resize the plotting windows in the program so that they fit well on all
+    screen resolutions.
+    """
+    screen_size = QtWidgets.QApplication.primaryScreen().size().toTuple()
+    screen_width, screen_height = screen_size
+    main_window.resize(screen_width * 1, screen_height * 1)
+    main_window.waveform_dlg.resize(screen_width * (2 / 3),
+                                    screen_height * (2 / 3))
+    main_window.tps_dlg.resize(screen_width * (2 / 3), screen_height * (2 / 3))
+
+    main_right_x = (main_window.x() + main_window.frameSize().width())
+    # This offset is based on the hard-coded geometry previously assigned to
+    # the waveform and TPS dialogs
+    wf_tps_x_offset = 50
+    # We are moving the TPS dialog so that it is slightly offset from the right
+    # edge of the main window
+    tps_dlg_x = main_right_x - main_window.tps_dlg.width() - wf_tps_x_offset
+    wf_tps_y = 50
+    main_window.waveform_dlg.move(wf_tps_x_offset, wf_tps_y)
+    main_window.tps_dlg.move(tps_dlg_x, wf_tps_y)
+
+    gps_dlg_y = main_window.height() / 5
+    main_window.gps_dialog.move(main_window.gps_dialog.y(), gps_dlg_y)
+
+
+def check_if_user_want_to_reset_config() -> bool:
+    """
+    Show a dialog asking the user if they want to reset the config.
+    :return: whether the user wants to reset the config.
+    """
+    bad_config_dialog = QMessageBox()
+    bad_config_dialog.setText('Something went wrong when reading the '
+                              'config.')
+    bad_config_dialog.setDetailedText(traceback.format_exc())
+    bad_config_dialog.setInformativeText('Do you want to reset the config '
+                                         'file?')
+    bad_config_dialog.setStandardButtons(QMessageBox.Ok |
+                                         QMessageBox.Close)
+    bad_config_dialog.setDefaultButton(QMessageBox.Ok)
+    bad_config_dialog.setIcon(QMessageBox.Critical)
+    reset_choice = bad_config_dialog.exec_()
+    return reset_choice == QMessageBox.Ok
+
+
+def main():
+    # Change the working directory so that relative paths work correctly.
+    fix_relative_paths()
+
     app = QtWidgets.QApplication(sys.argv)
     wnd = MainWindow()
+
     config = ConfigProcessor()
     config.load_config()
-    need_reset = False
+    do_reset = None
     try:
         config.validate_config()
         config.apply_config(wnd)
     except (BadConfigError, ValueError) as e:
-        bad_config_dialog = QMessageBox()
-        bad_config_dialog.setText('Something went wrong when reading the '
-                                  'config.')
-        bad_config_dialog.setDetailedText(traceback.format_exc())
-        bad_config_dialog.setInformativeText('Do you want to reset the config '
-                                             'file?')
-        bad_config_dialog.setStandardButtons(QMessageBox.Ok |
-                                             QMessageBox.Close)
-        bad_config_dialog.setDefaultButton(QMessageBox.Ok)
-        bad_config_dialog.setIcon(QMessageBox.Critical)
-        reset_choice = bad_config_dialog.exec_()
-        if reset_choice == QMessageBox.Ok:
-            need_reset = True
-        else:
-            sys.exit(1)
-    if need_reset:
+        do_reset = check_if_user_want_to_reset_config()
+    if do_reset:
         try:
             config.reset()
         except OSError:
             QMessageBox.critical(None, 'Cannot reset config',
-                                 'Config file cannot be reset.  Please '
-                                 'ensure that it is not opened in another '
-                                 'program.',
+                                 'Config file cannot be reset.  Please ensure '
+                                 'that it is not opened in another program.',
                                  QMessageBox.Close)
             sys.exit(1)
+    elif do_reset is not None:
+        sys.exit(1)
     config.apply_config(wnd)
+
+    resize_windows(wnd)
     wnd.show()
     sys.exit(app.exec_())
 
diff --git a/sohstationviewer/view/db_config/add_edit_single_channel_dialog.py b/sohstationviewer/view/db_config/add_edit_single_channel_dialog.py
new file mode 100755
index 0000000000000000000000000000000000000000..26c3b30db1ced1aa2de65890f15d3cf4483ec083
--- /dev/null
+++ b/sohstationviewer/view/db_config/add_edit_single_channel_dialog.py
@@ -0,0 +1,351 @@
+import sys
+import platform
+import os
+from typing import Optional, Dict
+
+from PySide2 import QtWidgets, QtGui
+from PySide2.QtWidgets import QWidget, QDialog
+
+from sohstationviewer.database.process_db import execute_db
+from sohstationviewer.database.extract_data import (
+    get_params, get_channel_info, create_assign_string_for_db_query
+)
+
+from sohstationviewer.view.db_config.edit_single_param_dialog import \
+    EditSingleParamDialog
+
+from sohstationviewer.conf.dbSettings import modify_db_path
+
+
+def add_separation_line(layout):
+    """
+    Add a line for separation to the given layout.
+    :param layout: QLayout - the layout that contains the line
+    """
+    label = QtWidgets.QLabel()
+    label.setFrameStyle(QtWidgets.QFrame.HLine | QtWidgets.QFrame.Sunken)
+    label.setLineWidth(1)
+    layout.addWidget(label)
+
+
+class AddEditSingleChannelDialog(QDialog):
+    """
+    Dialog to add info for channel not in database or edit the existing channel
+    """
+    def __init__(self, parent: Optional[QWidget],
+                 chan_id: str, data_type: str):
+        """
+        :param parent: the parent widget
+        :param chan_id: name of channel to be added/edited
+        :param data_type: type of the data being processed
+        """
+        self.parent = parent
+        # name of the channel
+        self.chan_id = chan_id
+        # data_type of the channel
+        self.data_type = data_type
+
+        # param of the channel
+        self.param: str = 'Default'
+        # True if this channel isn't in DB yet
+        self.is_new_db_channel: bool = False
+        # To skip on_param_chkbox_changed() when param is changed by the
+        # program at the beginning
+        self.param_changed_by_signal: bool = False
+        # database info of the channel
+        self.channel_info: Dict = {}
+        # database info of the channel's parameter
+        self.param_info: Dict = {}
+        super(AddEditSingleChannelDialog, self).__init__(parent)
+
+        # short name of the channel
+        self.channel_name_lnedit = QtWidgets.QLineEdit(self)
+        self.channel_name_lnedit.setReadOnly(True)
+
+        # description added to channel name
+        self.label_lnedit = QtWidgets.QLineEdit(self)
+        self.label_lnedit.setPlaceholderText(
+            "added to channel name to be displayed")
+
+        # convert factor to change from count to actual value
+        self.conversion_lnedit = QtWidgets.QLineEdit(self)
+        self.conversion_lnedit.setPlaceholderText(
+            "to convert from count to actual value"
+        )
+        validator = QtGui.QDoubleValidator(0.0, 5.0, 6)
+        validator.setNotation(QtGui.QDoubleValidator.StandardNotation)
+        self.conversion_lnedit.setValidator(validator)
+        self.conversion_lnedit.setText('1')
+
+        # channel's unit
+        self.unit_lnedit = QtWidgets.QLineEdit(self)
+
+        # dedimal point for channel's value
+        self.fix_point_spnbox = QtWidgets.QSpinBox()
+        self.fix_point_spnbox.setToolTip("Decimal point that allow in display")
+        self.fix_point_spnbox.setMinimum(0)
+        self.fix_point_spnbox.setMaximum(5)
+
+        # data_type
+        self.data_type_lnedit = QtWidgets.QLineEdit(self)
+        self.data_type_lnedit.setReadOnly(True)
+
+        # channel's parameter which decides how channel is plotted
+        self.param_cbobox = QtWidgets.QComboBox(self)
+        self.param_cbobox.addItems(get_params())
+
+        # button to edit param
+        self.edit_param_btn = QtWidgets.QPushButton("EDIT PARAMETER", self)
+        # button to save changes to DB
+        self.save_btn = QtWidgets.QPushButton("SAVE CHANNEL", self)
+        # button to save changes and replot channel
+        self.save_replot_btn = QtWidgets.QPushButton("SAVE & REPLOT", self)
+        # button to close dialog without doing anything
+        self.cancel_btn = QtWidgets.QPushButton('CANCEL', self)
+
+        self.setup_ui()
+        self.set_channel_info()
+        self.connect_signals()
+
+    def setup_ui(self) -> None:
+        dlg_type = 'Add' if 'DEFAULT' in self.chan_id else 'Edit'
+        self.setWindowTitle(f"{dlg_type} channel {self.chan_id}"
+                            f" - {self.data_type}")
+
+        main_layout = QtWidgets.QVBoxLayout()
+        self.setLayout(main_layout)
+
+        instruction = (
+            f"This dialog is to {dlg_type} channel {self.chan_id}.\n"
+            "Parameter need to be any value different than 'Default' to be "
+            "saved.")
+        main_layout.addWidget(QtWidgets.QLabel(instruction))
+
+        channel_layout = QtWidgets.QGridLayout()
+        main_layout.addLayout(channel_layout)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Name'), 0, 0, 1, 1)
+        channel_layout.addWidget(self.channel_name_lnedit, 0, 1, 1, 1)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Label'), 1, 0, 1, 1)
+        channel_layout.addWidget(self.label_lnedit, 1, 1, 1, 1)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Conversion'), 2, 0, 1, 1)
+        channel_layout.addWidget(self.conversion_lnedit, 2, 1, 1, 1)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Unit'), 3, 0, 1, 1)
+        channel_layout.addWidget(self.unit_lnedit, 3, 1, 1, 1)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Fix Point'), 4, 0, 1, 1)
+        channel_layout.addWidget(self.fix_point_spnbox, 4, 1, 1, 1)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Data Type'), 5, 0, 1, 1)
+        channel_layout.addWidget(self.data_type_lnedit, 5, 1, 1, 1)
+
+        channel_layout.addWidget(QtWidgets.QLabel('Parameter'), 6, 0, 1, 1)
+        channel_layout.addWidget(self.param_cbobox, 6, 1, 1, 1)
+
+        channel_layout.addWidget(self.save_btn, 7, 0, 1, 1)
+        channel_layout.addWidget(self.save_replot_btn, 7, 1, 1, 1)
+
+        channel_layout.addWidget(self.edit_param_btn, 8, 1, 1, 1)
+        channel_layout.addWidget(self.cancel_btn, 8, 0, 1, 1)
+        self.save_replot_btn.setFocus()
+
+    def connect_signals(self) -> None:
+        self.param_cbobox.currentTextChanged.connect(
+            self.on_param_cbobox_changed)
+        self.cancel_btn.clicked.connect(self.close)
+        self.save_btn.clicked.connect(self.on_save)
+        self.save_replot_btn.clicked.connect(self.on_save_replot)
+        self.edit_param_btn.clicked.connect(self.on_edit_param)
+
+    def set_channel_info(self):
+        """
+        Add all Channel related info according to information got from DB.
+        In case Channel isn't in the DB, use the info of DEFAULT channel.
+        Call set_param_info to set Parameter related info.
+        """
+        try:
+            self.channel_info = get_channel_info(self.chan_id, self.data_type)
+        except IndexError:
+            self.is_new_db_channel = True
+            self.channel_info = get_channel_info('DEFAULT', 'Default')
+
+        self.channel_name_lnedit.setText(self.chan_id)
+
+        self.label_lnedit.setText(self.channel_info['label'])
+
+        self.conversion_lnedit.setText(
+            str(float(self.channel_info['convertFactor'])))
+
+        self.unit_lnedit.setText(self.channel_info['unit'])
+
+        if self.channel_info['fixPoint'] is not None:
+            self.fix_point_spnbox.setValue(self.channel_info['fixPoint'])
+
+        self.data_type_lnedit.setText(self.data_type)
+
+        self.param_cbobox.setCurrentText(self.channel_info['param'])
+        self.param = self.channel_info['param']
+        self.set_buttons_enabled()
+
+    def on_param_cbobox_changed(self):
+        """
+        + Check self.param_changed_by_signal to make sure the signal come from
+            user selecting a parameter from param_cbobox, not the signal from
+            changing back to original value when condition not pass fo the set
+            value
+        + Not allow parameter 'Default' to be select because it is only the
+            parameter for the channel that has no record in DB
+        + If the channel already has a record in DB, give a warning when user's
+            trying to change its parameter.
+        """
+        if self.param_changed_by_signal:
+            self.param_changed_by_signal = False
+            return
+        new_param = self.param_cbobox.currentText()
+        if new_param == 'Default':
+            # Parameter Default is only for channel that has no record in DB.
+            # So it isn't allowed to be selected
+            self.param_changed_by_signal = True
+            self.param_cbobox.setCurrentText(self.param)
+            return
+        if not self.is_new_db_channel:
+            msg = ("ARE YOU SURE YOU WANT TO CHANGE PARAMETER FOR CHANNEL "
+                   f"'{self.chan_id}'?")
+            result = QtWidgets.QMessageBox.question(
+                self, "Confirmation", msg,
+                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
+            if result == QtWidgets.QMessageBox.No:
+                self.param_changed_by_signal = True
+                self.param_cbobox.setCurrentText(self.param)
+                return
+        self.param = new_param
+        self.set_buttons_enabled()
+
+    def save(self):
+        """
+        Save info from GUI to DB
+        """
+        if self.is_new_db_channel:
+            self.insert_channel_info()
+        else:
+            self.update_channel_info()
+
+    def on_save(self):
+        """
+        Save new channel info to DB
+        """
+        self.save()
+        self.close()
+
+    def on_save_replot(self):
+        """
+        Save new channel info to DB
+        TODO: Replot the channel in the plotting area
+        """
+        self.save()
+        print("Do REPLOT")
+        self.close()
+
+    def set_buttons_enabled(self):
+        """
+        Disable the 3 buttons to save and to edit parameters so that user are
+        forced to change param before they want to continue.
+        """
+        if self.param == 'Default':
+            self.edit_param_btn.setEnabled(False)
+            self.save_btn.setEnabled(False)
+            self.save_replot_btn.setEnabled(False)
+        else:
+            self.edit_param_btn.setEnabled(True)
+            self.save_btn.setEnabled(True)
+            self.save_replot_btn.setEnabled(True)
+
+    def on_edit_param(self):
+        """
+        Give user a warning when they want to change parameter's info then
+        open EditSingleParamDialog for user to edit parameter's info after
+        they give their confirmation.
+        """
+        msg = ("Changing parameter will affect all of other channels that "
+               "have the same parameter.\n\n"
+               "Are you sure you want to continue?")
+        result = QtWidgets.QMessageBox.question(
+            self, "Confirmation", msg,
+            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
+        if result == QtWidgets.QMessageBox.No:
+            return
+        win = EditSingleParamDialog(self, self.param_cbobox.currentText())
+        win.exec_()
+
+    def update_para_info(self, param):
+        """
+        Save parameter related info to Parameters table
+        :param param: param condition string
+        """
+        plot_type = create_assign_string_for_db_query(
+            'plotType', self.plot_type_cbo_box.currentText())
+        value_colorb = create_assign_string_for_db_query(
+            'valueColorsB', self.value_colorb_widget.text())
+        value_colorw = create_assign_string_for_db_query(
+            'valueColorsW', self.value_colorw_widget.text())
+        height = f"height={self.height_spnbox.value()}"
+        sql = (f"UPDATE Parameters SET {plot_type}, {value_colorb}, "
+               f"{value_colorw}, {height} WHERE {param}")
+        execute_db(sql)
+
+    def insert_channel_info(self):
+        sql = ("INSERT INTO Channels VALUES ("
+               f"'{self.channel_name_lnedit.text()}', "
+               f"'{self.label_lnedit.text()}', "
+               f"'{self.param_cbobox.currentText()}', "
+               f"NULL, "       # linkedChan for RT130 only and won't be changed
+               f"{self.conversion_lnedit.text()}, "
+               f"'{self.unit_lnedit.text()}', "
+               f"{self.fix_point_spnbox.value()}, "
+               f"'{self.data_type_lnedit.text()}')")
+        execute_db(sql)
+
+    def update_channel_info(self):
+        channel = f"channel='{self.channel_name_lnedit.text()}'"
+        label = f"label='{self.label_lnedit.text()}'"
+        param = f"param='{self.param_cbobox.currentText()}'"
+        linked_chan = "linkedChan=NULL"
+        convert_factor = f"convertFactor={self.conversion_lnedit.text()}"
+        unit = f"unit='{self.unit_lnedit.text()}'"
+        fix_point = f"fixPoint={self.fix_point_spnbox.value()}"
+        data_type = f"dataType='{self.data_type_lnedit.text()}'"
+        sql = (f"UPDATE Channels SET {label}, {param}, {linked_chan}, "
+               f"{convert_factor}, {unit}, {fix_point}, {data_type} "
+               f"WHERE {channel}")
+        execute_db(sql)
+
+
+if __name__ == '__main__':
+    modify_db_path()
+    os_name, version, *_ = platform.platform().split('-')
+    if os_name == 'macOS':
+        os.environ['QT_MAC_WANTS_LAYER'] = '1'
+    app = QtWidgets.QApplication(sys.argv)
+
+    # test new channel
+    # test = AddEditSingleChannelDialog(None, 'VEE', 'Q330')
+
+    # test linesDots. Ex: param: Input power supply current
+    # test = AddEditSingleChannelDialog(None, 'VEC', 'Q330')
+
+    # test MultiColorDotsLowerBound. Ex: param:Backup volt
+    # test = AddEditSingleChannelDialog(None, 'Backup Volt', 'RT130')
+
+    # test MultiColorDotsUpperBound. Ex: param:GNSS status
+    test = AddEditSingleChannelDialog(None, 'VST', 'Pegasus')
+
+    # test UpDownDots. Ex: param. Ex: param:Net Up/down
+    # test = AddEditSingleChannelDialog(None, 'Net Up/Down', 'RT130')
+
+    # test TriColorLInes. Ex: param. Ex: param:Error/warning
+    # test = AddEditSingleChannelDialog(None, 'Error/Warning', 'RT130')
+    test.exec_()
+    sys.exit(app.exec_())
diff --git a/sohstationviewer/view/db_config/edit_single_param_dialog.py b/sohstationviewer/view/db_config/edit_single_param_dialog.py
new file mode 100755
index 0000000000000000000000000000000000000000..57ccae061d33867e21124237b22e72798b78b407
--- /dev/null
+++ b/sohstationviewer/view/db_config/edit_single_param_dialog.py
@@ -0,0 +1,169 @@
+import sys
+import platform
+import os
+from typing import Optional, Dict
+
+from PySide2 import QtWidgets
+from PySide2.QtWidgets import QWidget, QDialog, QLineEdit
+
+from sohstationviewer.view.util.plot_func_names import plot_functions
+
+from sohstationviewer.database.process_db import execute_db
+from sohstationviewer.database.extract_data import (
+    get_param_info, create_assign_string_for_db_query
+)
+
+from sohstationviewer.conf.dbSettings import modify_db_path
+
+
+class EditSingleParamDialog(QDialog):
+    """
+    Dialog to add info for channel not in database or edit the existing channel
+    """
+    def __init__(self, parent: Optional[QWidget],
+                 param: str):
+        """
+        :param parent: the parent widget
+        :param chan_id: name of channel to be added/edited
+        :param data_type: type of the data being processed
+        """
+        self.param = param
+        # # To skip on_param_chkbox_changed() when param is changed by the
+        # # program at the beginning
+        # self.param_changed_by_signal = False
+        # database info of the channel
+        self.channel_info: Dict = {}
+        # database info of the channel's parameter
+        self.param_info: Dict = {}
+        super(EditSingleParamDialog, self).__init__(parent)
+
+        # parameter's plot type which decides the shape of the plot
+        self.plot_type_cbo_box = QtWidgets.QComboBox(self)
+        self.plot_type_cbo_box.addItems([""] + list(plot_functions.keys()))
+
+        # value color in black mode
+        self.value_colorb_widget = QLineEdit(self)
+        self.value_colorb_widget.setPlaceholderText(
+            "Click edit button to add value color string")
+        self.value_colorb_widget.setToolTip("Priority from left to right")
+        # value, color in white mode
+        self.value_colorw_widget = QLineEdit(self)
+        self.value_colorw_widget.setPlaceholderText(
+            "Click edit button to add value color string")
+        self.value_colorw_widget.setToolTip("Priority from left to right")
+
+        # height of the plot
+        self.height_spnbox = QtWidgets.QSpinBox()
+        self.height_spnbox.setMinimum(0)
+        self.height_spnbox.setMaximum(8)
+        self.height_spnbox.setToolTip("Relative height of the plot")
+
+        # button to save change to DB
+        self.save_param_btn = QtWidgets.QPushButton(
+            "SAVE PARAMETER", self)
+        # button to close dialog without doing anything
+        self.cancel_btn = QtWidgets.QPushButton('CANCEL', self)
+
+        self.setup_ui()
+        self.set_param_info()
+        self.connect_signals()
+
+    def setup_ui(self) -> None:
+        self.setWindowTitle(f"Edit Parameter {self.param}")
+
+        main_layout = QtWidgets.QVBoxLayout()
+        self.setLayout(main_layout)
+
+        param_layout = QtWidgets.QGridLayout()
+        main_layout.addLayout(param_layout)
+
+        param_layout.addWidget(QtWidgets.QLabel('Plot Type'), 0, 0, 1, 1)
+        param_layout.addWidget(self.plot_type_cbo_box, 0, 1, 1, 1)
+
+        param_layout.addWidget(QtWidgets.QLabel(
+            'Value Color (black)'), 1, 0, 1, 1)
+        param_layout.addWidget(self.value_colorb_widget, 1, 1, 1, 1)
+
+        param_layout.addWidget(QtWidgets.QLabel(
+            'Value Color (white)'), 2, 0, 1, 1)
+        param_layout.addWidget(self.value_colorw_widget, 2, 1, 1, 1)
+
+        param_layout.addWidget(QtWidgets.QLabel('Height'), 3, 0, 1, 1)
+        param_layout.addWidget(self.height_spnbox, 3, 1, 1, 1)
+
+        param_layout.addWidget(self.cancel_btn, 4, 0, 1, 1)
+        param_layout.addWidget(self.save_param_btn, 4, 1, 1, 1)
+
+    def connect_signals(self) -> None:
+        self.plot_type_cbo_box.currentTextChanged.connect(self.set_plot_type)
+        self.cancel_btn.clicked.connect(self.close)
+        self.save_param_btn.clicked.connect(self.on_save_param)
+
+    def set_param_info(self) -> None:
+        """
+        Fill up all info boxes
+        """
+        self.param_info = get_param_info(self.param)
+        self.set_plot_type(self.param_info['plotType'])
+        self.height_spnbox.setValue(self.param_info['height'])
+
+    def set_plot_type(self, plot_type: str) -> None:
+        """
+        Add Plot Type, Value Color strings.
+        If there is no Plot Type, no Value Color or Height because no plot.
+        :param plot_type: name of Plot Type
+        """
+        if plot_type in ["", None]:
+            self.plot_type_cbo_box.setCurrentText('')
+            self.value_colorb_widget.setEnabled(False)
+            self.value_colorb_widget.clear()
+            self.value_colorw_widget.setEnabled(False)
+            self.value_colorw_widget.clear()
+            self.height_spnbox.setValue(0)
+        else:
+            self.plot_type_cbo_box.setCurrentText(plot_type)
+            value_color_b = self.param_info['valueColorsB']
+            value_color_w = self.param_info['valueColorsW']
+            self.value_colorb_widget.setText(value_color_b)
+            self.value_colorw_widget.setText(value_color_w)
+
+    def on_save_param(self):
+        """
+        Save parameter info to Parameters table
+        """
+        plot_type = create_assign_string_for_db_query(
+            'plotType', self.plot_type_cbo_box.currentText())
+        value_colorb = create_assign_string_for_db_query(
+            'valueColorsB', self.value_colorb_widget.text())
+        value_colorw = create_assign_string_for_db_query(
+            'valueColorsW', self.value_colorw_widget.text())
+        height = f"height={self.height_spnbox.value()}"
+        sql = (f"UPDATE Parameters SET {plot_type}, {value_colorb}, "
+               f"{value_colorw}, {height} WHERE param='{self.param}'")
+        execute_db(sql)
+        self.close()
+
+
+if __name__ == '__main__':
+    modify_db_path()
+    os_name, version, *_ = platform.platform().split('-')
+    if os_name == 'macOS':
+        os.environ['QT_MAC_WANTS_LAYER'] = '1'
+    app = QtWidgets.QApplication(sys.argv)
+
+    # test linesDots. Ex: param: Input power supply current
+    test = EditSingleParamDialog(None, 'Input power supply current')
+
+    # test MultiColorDotsLowerBound. Ex: param:Backup volt
+    # test = EditSingleParamDialog(None, 'Backup Volt', 'RT130')
+
+    # test MultiColorDotsUpperBound. Ex: param:GNSS status
+    # test = EditSingleParamDialog(None, 'GNSS status')
+
+    # test UpDownDots. Ex: param. Ex: param:Net Up/down
+    # test = EditSingleParamDialog(None, 'Net Up/Down', 'RT130')
+
+    # test TriColorLInes. Ex: param. Ex: param:Error/warning
+    # test = EditSingleParamDialog(None, 'Error/Warning', 'RT130')
+    test.exec_()
+    sys.exit(app.exec_())
diff --git a/sohstationviewer/view/db_config/value_color_helper/value_color_widget.py b/sohstationviewer/view/db_config/value_color_helper/value_color_widget.py
new file mode 100644
index 0000000000000000000000000000000000000000..914655d5f2e22b25606e5dad769056aedd2b2287
--- /dev/null
+++ b/sohstationviewer/view/db_config/value_color_helper/value_color_widget.py
@@ -0,0 +1,136 @@
+import sys
+import platform
+import os
+from pathlib import Path
+from typing import Optional
+
+from PySide2 import QtWidgets, QtGui, QtCore
+from PySide2.QtCore import Qt
+from PySide2.QtWidgets import QWidget, QDialog, QTextEdit
+
+from sohstationviewer.view.db_config.value_color_helper.functions import \
+    convert_value_color_str, prepare_value_color_html
+
+
+class ValueColorWidget(QTextEdit):
+    def __init__(self, parent: Optional[QWidget], background: str):
+        """
+        Widget to display valueColors and call a dialog to edit tha value
+        :param parent: the parent widget
+        :param background: 'B'/'W': flag indicating background color
+        """
+        QtWidgets.QTextEdit.__init__(self, parent)
+        self.set_background(background)
+        # string for value color to be saved in DB
+        self.value_color_str: str = ''
+        # dialog that pop up when clicking on edit_button to help edit color
+        # and value
+        self.edit_value_color_dialog: Optional[QWidget] = None
+        # type of channel's plot
+        self.plot_type: str = ''
+
+        self.setReadOnly(True)
+        # change cursor to Arrow so user know they can't edit directly
+        self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
+        # to see all info
+        self.setFixedHeight(28)
+        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+        self.verticalScrollBar().setDisabled(True)
+
+        self.edit_button = QtWidgets.QToolButton(self)
+        self.edit_button.setCursor(Qt.PointingHandCursor)
+        current_file_path = os.path.abspath(__file__)
+        root_path = Path(current_file_path).parent.parent.parent.parent
+        if background == 'B':
+            img_file = f"{root_path}/images/edit_icon_black_background.png"
+        else:
+            img_file = f"{root_path}/images/edit_icon_white_background.png"
+        self.edit_button.setIcon(QtGui.QIcon(img_file))
+        self.edit_button.setStyleSheet(
+            "background: transparent; border: none;")
+        self.edit_button.clicked.connect(self.on_edit)
+
+        layout = QtWidgets.QHBoxLayout(self)
+        layout.addWidget(self.edit_button, 0, Qt.AlignRight)
+
+        layout.setSpacing(0)
+        layout.setMargin(5)
+
+    def set_background(self, background: str):
+        """
+        Set black background for user to have better feeling how the colors
+            displayed on black background. Text and PlaceholderText's colors
+            have to be changed to be readable on the black background too.
+        :param background: 'B'/'W': sign for background color
+        """
+        palette = self.palette()
+        if background == 'B':
+            palette.setColor(QtGui.QPalette.Text, Qt.white)
+            palette.setColor(QtGui.QPalette.Base, Qt.black)
+            palette.setColor(QtGui.QPalette.PlaceholderText, Qt.lightGray)
+            self.setPalette(palette)
+
+    def set_value_color(self, plot_type: str, value_color_str: str) \
+            -> None:
+        """
+        Set value_color_str, value_color_edit_dialog and display value color
+            string in html to show color for user to have the feeling.
+        :param plot_type: type of channel's plot
+        :param value_color_str: string for value color to be saved in DB
+        """
+
+        self.plot_type = plot_type
+        # Won't need to convert after database's valueColors are changed
+        self.value_color_str = convert_value_color_str(
+            plot_type, value_color_str)
+        value_color_html = prepare_value_color_html(self.value_color_str)
+        self.setHtml(value_color_html)
+
+    def on_edit(self):
+        print('edit value color')
+
+
+class TestDialog(QDialog):
+    def __init__(self):
+        super(TestDialog, self).__init__(None)
+        main_layout = QtWidgets.QVBoxLayout()
+        self.setLayout(main_layout)
+
+        self.value_colorb_widget = ValueColorWidget(self, 'B')
+        main_layout.addWidget(self.value_colorb_widget)
+        self.value_colorw_widget = ValueColorWidget(self, 'W')
+        main_layout.addWidget(self.value_colorw_widget)
+
+        # linesDots
+        self.value_colorb_widget.set_value_color('linesDots', 'L:R|D:G')
+        self.value_colorw_widget.set_value_color('linesDots', 'L:R|D:G')
+
+        # triColorLines
+        # self.value_colorb_widget.set_value_color(
+        #     'triColorLines', '-1:M|0:R|1:G')
+        # self.value_colorw_widget.set_value_color(
+        #     'triColorLines', '-1:M|0:R|1:G')
+
+        # multiColorDotsEqualOnUpperBound
+        # self.value_colorb_widget.set_value_color(
+        #     'multiColorDotsEqualOnUpperBound', '0:R|1:Y|2:G|+2:M')
+        # self.value_colorw_widget.set_value_color(
+        #     'multiColorDotsEqualOnUpperBound', '0:R|1:Y|2:G|+2:M')
+
+        # multiColorDotsEqualOnLowerBound
+        # self.value_colorb_widget.set_value_color('multiColorDotsEqualOnLowerBound',
+        #                               '3:R|3.3:Y|=3.3:G')
+        # self.value_colorw_widget.set_value_color('multiColorDotsEqualOnLowerBound',
+        #                               '3:R|3.3:Y|=3.3:G')
+
+
+if __name__ == '__main__':
+    os_name, version, *_ = platform.platform().split('-')
+    if os_name == 'macOS':
+        os.environ['QT_MAC_WANTS_LAYER'] = '1'
+    app = QtWidgets.QApplication(sys.argv)
+
+    test = TestDialog()
+    test.exec_()
+    sys.exit(app.exec_())
diff --git a/sohstationviewer/view/plotting/gps_plot/gps_dialog.py b/sohstationviewer/view/plotting/gps_plot/gps_dialog.py
index ebdc9d4f1500493ea850ff21ae6a40b69196a0ac..c1be4ff05b1d799e85ddd9748ff1f36e2bff72b9 100644
--- a/sohstationviewer/view/plotting/gps_plot/gps_dialog.py
+++ b/sohstationviewer/view/plotting/gps_plot/gps_dialog.py
@@ -3,7 +3,7 @@ import sys
 import os
 import traceback
 from pathlib import Path
-from typing import List, Optional, Literal, Iterable
+from typing import List, Optional, Literal, Iterable, Any
 
 from PySide2 import QtWidgets, QtCore
 from matplotlib.axes import Axes
@@ -31,7 +31,7 @@ class GPSWidget(QtWidgets.QWidget):
         # one point for each coordinate.
         self.unique_gps_points: Optional[List[GPSPoint]] = None
 
-        self.fig = Figure(figsize=(6, 6), dpi=100)
+        self.fig = Figure(figsize=(6, 6), dpi=100, facecolor='#ECECEC')
         self.canvas = Canvas(self.fig)
         self.canvas.mpl_connect('pick_event', self.on_pick_event)
 
@@ -156,7 +156,7 @@ class GPSWidget(QtWidgets.QWidget):
         self.repaint()
         self.tracking_box.clear()
 
-    def on_pick_event(self, event) -> None:
+    def on_pick_event(self, event) -> Any:
         """
         On a GPS point being picked, display the data of that point on the
         tracking box.
@@ -172,13 +172,13 @@ class GPSWidget(QtWidgets.QWidget):
         # and longitude follows correspondingly.
         lat_dir = 'N' if picked_point.latitude > 0 else 'S'
         long_dir = 'E' if picked_point.longitude > 0 else 'W'
-        meta_separator = ' ' * 22
-        loc_separator = ' ' * 10
+        meta_separator = ' ' * 7
+        loc_separator = ' ' * 5
         msg = (
-            f'Mark: {picked_point.last_timemark}{meta_separator}'
+            f' Mark: {picked_point.last_timemark}{meta_separator}'
             f'Fix: {picked_point.fix_type}{meta_separator}'
             f'Sats: {picked_point.num_satellite_used}<br>'
-            f'Lat: {lat_dir}{abs(picked_point.latitude):.6f}{loc_separator}'
+            f' Lat: {lat_dir}{abs(picked_point.latitude):.6f}{loc_separator}'
             f'Long: {long_dir}{abs(picked_point.longitude):.6f}{loc_separator}'
             f'Elev: {picked_point.height}{picked_point.height_unit}'
         )
@@ -254,7 +254,7 @@ class GPSDialog(QtWidgets.QWidget):
 
         bottom_layout = QtWidgets.QVBoxLayout()
         bottom_layout.addLayout(button_layout)
-        self.info_text_browser.setFixedHeight(42)
+        self.info_text_browser.setFixedHeight(45)
         bottom_layout.addWidget(self.info_text_browser)
         main_layout.addLayout(bottom_layout)
 
diff --git a/sohstationviewer/view/plotting/time_power_square/time_power_squared_dialog.py b/sohstationviewer/view/plotting/time_power_square/time_power_squared_dialog.py
index 36d2bcde405a21b652770413cf67ab81b20efb03..97244a870fcdd70bee47f311e16419487d2dcc54 100755
--- a/sohstationviewer/view/plotting/time_power_square/time_power_squared_dialog.py
+++ b/sohstationviewer/view/plotting/time_power_square/time_power_squared_dialog.py
@@ -40,7 +40,6 @@ class TimePowerSquaredDialog(QtWidgets.QWidget):
         """
         self.date_format: str = 'YYYY-MM-DD'
 
-        self.setGeometry(50, 50, 1200, 800)
         self.setWindowTitle("TPS Plot")
 
         main_layout = QtWidgets.QVBoxLayout()
diff --git a/sohstationviewer/view/plotting/time_power_square/time_power_squared_widget.py b/sohstationviewer/view/plotting/time_power_square/time_power_squared_widget.py
index b82e7cb8fe591ff9ad18b4ad829308cb0c7fe491..9b475c7af53f20032d35c8be55351149f367796e 100644
--- a/sohstationviewer/view/plotting/time_power_square/time_power_squared_widget.py
+++ b/sohstationviewer/view/plotting/time_power_square/time_power_squared_widget.py
@@ -231,7 +231,7 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
         ax = self.create_axes(self.plotting_bot, plot_h)
         ax.spines[['right', 'left', 'top', 'bottom']].set_visible(False)
         ax.text(
-            -0.12, 1,
+            -0.15, 1,
             f"{get_seismic_chan_label(chan_id)} {c_data['samplerate']}sps",
             horizontalalignment='left',
             verticalalignment='top',
diff --git a/sohstationviewer/view/plotting/waveform_dialog.py b/sohstationviewer/view/plotting/waveform_dialog.py
index 28ad89de67668eccf4bb78efc7c885c0f5381425..f6d8334504aa11c4e6a50ee26f3965984fe8bcba 100755
--- a/sohstationviewer/view/plotting/waveform_dialog.py
+++ b/sohstationviewer/view/plotting/waveform_dialog.py
@@ -77,7 +77,6 @@ class WaveformDialog(QtWidgets.QWidget):
          date_format: format for date
         """
         self.date_format: str = 'YYYY-MM-DD'
-        self.setGeometry(50, 10, 1600, 700)
         self.setWindowTitle("Raw Data Plot")
 
         main_layout = QtWidgets.QVBoxLayout()
diff --git a/sohstationviewer/view/ui/main_ui.py b/sohstationviewer/view/ui/main_ui.py
index 02e92845edcc28646a4869b7181cb4fd96c5579c..c1e13a3003f4bca9c6f4977aa87da20a96d576ba 100755
--- a/sohstationviewer/view/ui/main_ui.py
+++ b/sohstationviewer/view/ui/main_ui.py
@@ -7,6 +7,7 @@ from PySide2.QtWidgets import (
     QMainWindow, QWidget, QTextBrowser, QPushButton, QLineEdit, QDateEdit,
     QListWidget, QCheckBox, QRadioButton, QMenu, QLabel, QFrame,
     QVBoxLayout, QHBoxLayout, QGridLayout, QAbstractItemView, QButtonGroup,
+    QSplitter,
 )
 from PySide2.QtWidgets import (
     QAction, QActionGroup, QShortcut
@@ -279,7 +280,6 @@ class UIMainWindow(object):
         :param main_window: QMainWindow - main GUI for user to interact with
         """
         self.main_window = main_window
-        main_window.resize(1798, 1110)
         main_window.setWindowTitle("SOH Station Viewer")
         self.central_widget = QWidget(main_window)
         main_window.setCentralWidget(self.central_widget)
@@ -294,8 +294,6 @@ class UIMainWindow(object):
         self.set_first_row(main_layout)
         self.set_second_row(main_layout)
 
-        self.tracking_info_text_browser.setFixedHeight(80)
-        main_layout.addWidget(self.tracking_info_text_browser)
         self.create_menu_bar(main_window)
         self.connect_signals(main_window)
         self.create_shortcuts(main_window)
@@ -352,7 +350,7 @@ class UIMainWindow(object):
         left_widget = QWidget(self.central_widget)
         h_layout.addWidget(left_widget)
         left_widget.setFixedWidth(240)
-        left_widget.setMinimumHeight(650)
+        # left_widget.setMinimumHeight(650)
         left_layout = QVBoxLayout()
         left_layout.setContentsMargins(0, 0, 0, 0)
         left_layout.setSpacing(0)
@@ -360,12 +358,22 @@ class UIMainWindow(object):
 
         self.set_control_column(left_layout)
 
+        plot_splitter = QSplitter(QtCore.Qt.Orientation.Vertical)
+        h_layout.addWidget(plot_splitter, 2)
+
         self.plotting_widget = SOHWidget(self.main_window,
                                          self.tracking_info_text_browser,
                                          'SOH',
                                          self.main_window)
+        plot_splitter.addWidget(self.plotting_widget)
 
-        h_layout.addWidget(self.plotting_widget, 2)
+        self.tracking_info_text_browser.setMinimumHeight(60)
+        self.tracking_info_text_browser.setMaximumHeight(80)
+        plot_splitter.addWidget(self.tracking_info_text_browser)
+        tracking_browser_idx = plot_splitter.indexOf(
+            self.tracking_info_text_browser
+        )
+        plot_splitter.setCollapsible(tracking_browser_idx, False)
 
     def set_control_column(self, left_layout):
         """