"""
A simple periodic table widget that allows the user to select a single element.
Example usage:
    self.table_dialog = PeriodicTableDialog(self)
    self.table_dialog.exec_()
    symbol = self.periodic_table_dlg.getSymbol()
Copyright Schrodinger, LLC. All rights reserved.
"""
from schrodinger.infra import mm
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import swidgets
[docs]class PeriodicTableDialog(swidgets.SDialog):
    """
    A simple periodic table widget that allows the user to select a single
    element.
    """
    # Each item in ELEMENTS is (Name, Symbol, Column, Row). Column and Row are
    # 0-indexed, and Row is the physical location of the button, not
    # necessarily the Periodic Table row - so the lanthanides have a different
    # Row value than Lanthanum, for instance
    ELEMENTS = [
        ('Hydrogen', 'H', 0, 0),
        ('Helium', 'He', 17, 0),
        ('Lithium', 'Li', 0, 1),
        ('Beryllium', 'Be', 1, 1),
        ('Boron', 'B', 12, 1),
        ('Carbon', 'C', 13, 1),
        ('Nitrogen', 'N', 14, 1),
        ('Oxygen', 'O', 15, 1),
        ('Fluorine', 'F', 16, 1),
        ('Neon', 'Ne', 17, 1),
        ('Sodium', 'Na', 0, 2),
        ('Magnesium', 'Mg', 1, 2),
        ('Aluminium', 'Al', 12, 2),
        ('Silicon', 'Si', 13, 2),
        ('Phosphorus', 'P', 14, 2),
        ('Sulphur', 'S', 15, 2),
        ('Chlorine', 'Cl', 16, 2),
        ('Argon', 'Ar', 17, 2),
        ('Potassium', 'K', 0, 3),
        ('Calcium', 'Ca', 1, 3),
        ('Scandium', 'Sc', 2, 3),
        ('Titanium', 'Ti', 3, 3),
        ('Vanadium', 'V', 4, 3),
        ('Chromium', 'Cr', 5, 3),
        ('Manganese', 'Mn', 6, 3),
        ('Iron', 'Fe', 7, 3),
        ('Cobalt', 'Co', 8, 3),
        ('Nickel', 'Ni', 9, 3),
        ('Copper', 'Cu', 10, 3),
        ('Zinc', 'Zn', 11, 3),
        ('Gallium', 'Ga', 12, 3),
        ('Germanium', 'Ge', 13, 3),
        ('Arsenic', 'As', 14, 3),
        ('Selenium', 'Se', 15, 3),
        ('Bromine', 'Br', 16, 3),
        ('Krypton', 'Kr', 17, 3),
        ('Rubidium', 'Rb', 0, 4),
        ('Strontium', 'Sr', 1, 4),
        ('Yttrium', 'Y', 2, 4),
        ('Zirconium', 'Zr', 3, 4),
        ('Niobium', 'Nb', 4, 4),
        ('Molybdenum', 'Mo', 5, 4),
        ('Technetium', 'Tc', 6, 4),
        ('Ruthenium', 'Ru', 7, 4),
        ('Rhodium', 'Rh', 8, 4),
        ('Palladium', 'Pd', 9, 4),
        ('Silver', 'Ag', 10, 4),
        ('Cadmium', 'Cd', 11, 4),
        ('Indium', 'In', 12, 4),
        ('Tin', 'Sn', 13, 4),
        ('Antimony', 'Sb', 14, 4),
        ('Tellurium', 'Te', 15, 4),
        ('Iodine', 'I', 16, 4),
        ('Xenon', 'Xe', 17, 4),
        ('Cesium', 'Cs', 0, 5),
        ('Barium', 'Ba', 1, 5),
        ('Lanthanum', 'La', 2, 5),
        ('Cerium', 'Ce', 3, 9),
        ('Praseodymium', 'Pr', 4, 9),
        ('Neodymium', 'Nd', 5, 9),
        ('Promethium', 'Pm', 6, 9),
        ('Samarium', 'Sm', 7, 9),
        ('Europium', 'Eu', 8, 9),
        ('Gadolinium', 'Gd', 9, 9),
        ('Terbium', 'Tb', 10, 9),
        ('Dysprosium', 'Dy', 11, 9),
        ('Holmium', 'Ho', 12, 9),
        ('Erbium', 'Er', 13, 9),
        ('Thulium', 'Tm', 14, 9),
        ('Ytterbium', 'Yb', 15, 9),
        ('Lutetium', 'Lu', 16, 9),
        ('Hafnium', 'Hf', 3, 5),
        ('Tantalum', 'Ta', 4, 5),
        ('Tungsten', 'W', 5, 5),
        ('Rhenium', 'Re', 6, 5),
        ('Osmium', 'Os', 7, 5),
        ('Iridium', 'Ir', 8, 5),
        ('Platinum', 'Pt', 9, 5),
        ('Gold', 'Au', 10, 5),
        ('Mercury', 'Hg', 11, 5),
        ('Thallium', 'Tl', 12, 5),
        ('Lead', 'Pb', 13, 5),
        ('Bismuth', 'Bi', 14, 5),
        ('Polonium', 'Po', 15, 5),
        ('Astatine', 'At', 16, 5),
        ('Radon', 'Rn', 17, 5),
        ('Francium', 'Fr', 0, 6),
        ('Radium', 'Ra', 1, 6),
        ('Actinium', 'Ac', 2, 6),
        ('Thorium', 'Th', 3, 10),
        ('Protactinium', 'Pa', 4, 10),
        ('Uranium', 'U', 5, 10),
        ('Neptunium', 'Np', 6, 10),
        ('Plutonium', 'Pu', 7, 10),
        ('Americium', 'Am', 8, 10),
        ('Curium', 'Cm', 9, 10),
        ('Berkelium', 'Bk', 10, 10),
        ('Californium', 'Cf', 11, 10),
        ('Einsteinium', 'Es', 12, 10),
        ('Fermium', 'Fm', 13, 10),
        ('Mendelevium', 'Md', 14, 10),
        ('Nobelium', 'No', 15, 10),
        ('Lawrencium', 'Lr', 16, 10),
        ('Rutherfordium', 'Rf', 3, 6),
        ('Dubnium', 'Db', 4, 6),
        ('Seaborgium', 'Sg', 5, 6),
        ('Bohrium', 'Bh', 6, 6),
        ('Hassium', 'Hs', 7, 6),
        ('Meitnerium', 'Mt', 8, 6),
        ('Darmstadtium', 'Ds', 9, 6),
        ('Roentgenium', 'Rg', 10, 6),
        ('Copernicium', 'Cn', 11, 6),
        ('Nihonium', 'Nh', 12, 6),
        ('Flerovium', 'Fl', 13, 6),
        ('Moscovium', 'Mc', 14, 6),
        ('Livermorium', 'Lv', 15, 6),
        ('Tennessine', 'Ts', 16, 6),
        ('Oganesson', 'Og', 17, 6)
    ] # yapf: disable
    DU_SYMBOL, DU_ELEMENT, DU_BUTTON_ID = 'DU', -2, 500
[docs]    def __init__(self,
                 parent=None,
                 default_element=6,
                 max_element=mm.MMELEMENTS_MAX,
                 title='Choose Element',
                 dummy_name=''):
        """
        Create a PeriodicTable instance
        :type parent: QWidget
        :param parent: Dialog's parent.
        :type default_element: int
        :param default_element: Default selected element.
        :type max_element: int
        :param max_element: Number of elements displayed in the widget.
        :type title: str
        :param title: The Dialog window title
        :type dummy_name: str
        :param show_dummy: Dummy name, if showing of dummy element is desired
        """
        self.max_element = max_element
        self.dummy_name = dummy_name
        swidgets.SDialog.__init__(self, parent, title=title)
        self.current_element = default_element
        self.button_group.button(default_element).setChecked(True) 
[docs]    def layOut(self):
        """
        Lay out the periodic table
        """
        def addButton(number, symbol, name, button_id, colors, row, column):
            """
            Add button to self.button_group and self.grid_layout
            :type number: int
            :param number: Atomic number used in button tip
            :type symbol: str
            :param symbol: Atom symbol used in button label
            :type name: str
            :param name: Atom name used in button tip
            :type button_id: int
            :param button_id: Button ID used in self.button_group
            :type colors: tuple(str)
            :param colors: Colors when button is unchecked and checked
            :type row: int
            :param row: Row in the self.grid_layout to place the button
            :type column: int
            :param column: Column in the self.grid_layout to place the button
            """
            tip = str(number) + '\n' + name
            but = ElementButton(symbol, tip, colors)
            self.button_group.addButton(but)
            self.button_group.setId(but, button_id)
            self.grid_layout.addWidget(but, row, column)
        self.grid_layout = QtWidgets.QGridLayout()
        self.grid_layout.setSpacing(0)
        self.mylayout.addLayout(self.grid_layout)
        self.button_group = QtWidgets.QButtonGroup()
        todo = self.ELEMENTS[:self.max_element]
        max_row = 0
        for atomic_number, element_data in enumerate(todo, 1):
            name, symbol, column, row = element_data
            max_row = max(max_row, row)
            # Each color tuple is (normal, depressed)
            if row > 8:
                colors = ('#80FF80', '#50CC50')
            elif column < 2:
                colors = ('#7ADDEE', '#4AAABB')
            elif column < 12:
                colors = ('#EEBABA', '#CC9999')
            else:
                colors = ('#EEDD7A', '#CCBB5A')
            addButton(atomic_number, symbol, name, atomic_number, colors, row,
                      column)
        if self.dummy_name:
            colors = ('#DADADA', '#9B9B9B')
            self.grid_layout.addWidget(QtWidgets.QLabel(""), max_row + 1, 0)
            addButton(self.DU_ELEMENT, self.dummy_name, self.dummy_name,
                      self.DU_BUTTON_ID, colors, max_row + 2, 0)
        self.button_group.buttonClicked[int].connect(self.buttonChecked)
        # This puts a space between the main table and the lanthanides
        self.grid_layout.addWidget(QtWidgets.QLabel(""), 7, 0) 
[docs]    def showEvent(self, event):
        """
        Reimplemented showEvent event. Checks self.current_button.
        :type event: QShowEvent
        :param event: Show event.
        """
        self.button_group.button(self.getButtonId()).setChecked(True)
        return super(PeriodicTableDialog, self).showEvent(event) 
[docs]    def getElement(self):
        """
        Returns atomic number of a selected element.
        :rtype: int
        :return: Atomic number of a selected element.
        """
        return self.current_element 
[docs]    def getSymbol(self):
        """
        Returns symbol of a selected element.
        :rtype: str
        :return: Symbol of a selected element.
        """
        if self.current_element == self.DU_ELEMENT:
            return self.DU_SYMBOL
        return self.ELEMENTS[self.current_element - 1][1] 
 
[docs]class PeriodicTableDialogSingleClick(PeriodicTableDialog):
    """
    This provides a version of the Periodic Table widget that doesn't have
    OK/Cancel buttons, and will emit a signal and close itself when an
    element is toggled.
    """
    elementSelected = QtCore.pyqtSignal(str)
[docs]    def __init__(
            self,
            parent=None,
            default_element=6,
            max_element=len(PeriodicTableDialog.ELEMENTS),  # noqa: M511
            title='Choose Element'):
        super(PeriodicTableDialogSingleClick,
              self).__init__(parent, default_element, max_element, title)  #noqa
        self.dbb.hide()  # Hide the OK/Cancel buttons
        self.button_group.buttonClicked[int].connect(self.emitElementSelected) 
[docs]    def emitElementSelected(self, button_index):
        element_tuple = PeriodicTableDialog.ELEMENTS[button_index - 1]
        element_short = element_tuple[1]
        self.elementSelected.emit(element_short)  
if __name__ == '__main__':
    from schrodinger.ui.qt import style as qtstyle
    app = QtWidgets.QApplication([])
    qtstyle.apply_styles()
    dialog = PeriodicTableDialog()
    dialog.exec_()
    print(dialog.getSymbol(), dialog.getElement())