Ejemplo n.º 1
0
class BookmarkWidget(QFrame):
    SPELL_TAB = 0
    DICE_TAB = 1

    def __init__(self, monster_table, monster_viewer, spell_table, spell_viewer):
        super().__init__()
        self.monster_table = monster_table
        self.spell_table = spell_table
        self.monster_viewer = monster_viewer
        self.spell_viewer = spell_viewer
        self.bookmark_frame = QFrame()
        self.bookmark_frame.setMaximumHeight(300)
        self.button_bar = QFrame()
        self.button_bar.setLayout(QHBoxLayout())
        bookmark_layout = QHBoxLayout()
        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum))

        self.spell_bookmark = LinkedSpellTable(self.spell_table, self.spell_viewer)
        self.monster_bookmark = LinkedMonsterTable(self.monster_table, self.monster_viewer)
        self.monster_tabWidget = QTabWidget()
        self.monster_tabWidget.addTab(self.monster_bookmark, "Monster")

        self.spell_tabWidget = QTabWidget()
        self.spell_tabWidget.addTab(self.spell_bookmark, "Spell")

        self.dice_bookmark = QFrame()
        dice_layout = QVBoxLayout()
        for i in range(5):
            dice_layout.addWidget(DiceBox().frame)
        dice_help_button = QPushButton("Help")
        dice_help_button.clicked.connect(self.dice_instructions)
        dice_layout.addWidget(dice_help_button)
        self.dice_bookmark.setLayout(dice_layout)
        self.spell_tabWidget.addTab(self.dice_bookmark, "Dice")

        bookmark_layout.addWidget(self.monster_tabWidget)
        bookmark_layout.addWidget(self.spell_tabWidget)
        self.bookmark_frame.setLayout(bookmark_layout)

        self.clear_bookmark_button = QPushButton("Clear Bookmark")
        self.toggle_bookmark_button = QPushButton("Toggle Bookmark")
        self.button_bar.layout().setContentsMargins(0, 0, 0, 0)
        self.button_bar.layout().addWidget(self.clear_bookmark_button)
        self.button_bar.layout().addWidget(self.toggle_bookmark_button)

        self.layout().addWidget(self.bookmark_frame)
        self.layout().addWidget(self.button_bar)

        self.bookmark_frame.setHidden(True)
        self.hidden = True

    def dice_instructions(self):
        sNexus.printSignal.emit("\nEither input diceroll in format xdy+z, AttackBonus|DamageRoll, or"
                                    " AttackBonus, DamageRoll\nExample: 1d20+6\n5|2d6+3\n5, 2d6+3\n")
    def toggle_hide(self):
        self.hidden = not self.hidden
        self.bookmark_frame.setHidden(self.hidden)
Ejemplo n.º 2
0
class Ui_ConfigureRPCserversDlg(object):
    def setupUi(self, ConfigureRPCserversDlg):
        ConfigureRPCserversDlg.setModal(True)
        ## -- Layout
        self.layout = QVBoxLayout(ConfigureRPCserversDlg)
        self.layout.setSpacing(10)
        ## -- Servers List
        self.serversBox = QListWidget()
        self.layout.addWidget(self.serversBox)
        ## -- 'Add Server' button
        self.addServer_btn = QPushButton("Add RPC Server")
        self.layout.addWidget(self.addServer_btn)
        ## -- 'Close' button
        hBox = QHBoxLayout()
        hBox.addStretch(1)
        self.close_btn = QPushButton("Close")
        hBox.addWidget(self.close_btn)
        self.layout.addLayout(hBox)
        ## -- Edit section
        self.editFrame = QFrame()
        frameLayout = QFormLayout()
        frameLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        frameLayout.setContentsMargins(5, 10, 5, 5)
        frameLayout.setSpacing(7)
        self.user_edt = QLineEdit()
        frameLayout.addRow(QLabel("Username"), self.user_edt)
        self.passwd_edt = QLineEdit()
        frameLayout.addRow(QLabel("Password"), self.passwd_edt)
        hBox = QHBoxLayout()
        self.protocol_select = QComboBox()
        self.protocol_select.addItems(['http', 'https'])
        hBox.addWidget(self.protocol_select)
        hBox.addWidget(QLabel("://"))
        self.host_edt = QLineEdit()
        self.host_edt.setPlaceholderText('myserver.net:8080')
        hBox.addWidget(self.host_edt)
        frameLayout.addRow(QLabel("URL"), hBox)
        hBox2 = QHBoxLayout()
        self.cancel_btn = QPushButton("Cancel")
        self.save_btn = QPushButton("Save")
        hBox2.addWidget(self.cancel_btn)
        hBox2.addWidget(self.save_btn)
        frameLayout.addRow(hBox2)
        self.editFrame.setLayout(frameLayout)
        self.layout.addWidget(self.editFrame)
        self.editFrame.setHidden(True)
        ConfigureRPCserversDlg.setMinimumWidth(500)
        ConfigureRPCserversDlg.setMinimumHeight(500)
        # Connect main buttons
        self.addServer_btn.clicked.connect(
            lambda: ConfigureRPCserversDlg.onAddServer())
        self.close_btn.clicked.connect(
            lambda: ConfigureRPCserversDlg.onClose())
        self.cancel_btn.clicked.connect(
            lambda: ConfigureRPCserversDlg.onCancel())
        self.save_btn.clicked.connect(lambda: ConfigureRPCserversDlg.onSave())
Ejemplo n.º 3
0
class DownloaderDialog(JDialog):
    def __init__(self):
        super().__init__()
        self.setWindowIcon(QIcon('GUI\jinndl.ico'))
        self.setInitialSize(800, 800)

        self.initUi()
        self.setActions()

    def initUi(self):
        self.setWindowTitle("Download Jinn")
        self.windowLayout = QVBoxLayout(self)

        # Advanced options
        # Stored in a QFrame, this is hidden or shown by self.btnAdvancedOptions
        self.topBar = QHBoxLayout()
        self.btnAdvancedOptions = QPushButton("Show advanced options")

        self.comboBranch = LabelledComboBox("Choose branch:")
        self.comboBranch.cb.addItems(["HJinn", "LJinn", "master"])
        self.advancedOptionsLayout = QHBoxLayout()
        self.advancedOptionsLayout.addWidget(self.comboBranch)

        self.advancedOptionsFrame = QFrame()
        self.advancedOptionsFrame.setHidden(True)
        self.advancedOptionsFrame.setLayout(self.advancedOptionsLayout)
        self.topBar.addWidget(self.btnAdvancedOptions)
        self.topBar.addWidget(self.advancedOptionsFrame)

        self.updateLog = JTextEdit(
            "Press 'Download' below to download the latest Jinn code to the USB memory stick"
        )

        self.statusLayout = QVBoxLayout()
        self.statusLayout.addWidget(self.updateLog)

        self.btnDownload = JPushButton("Download")
        self.btnCancel = JCancelButton("Cancel")
        self.buttonBtm = QHBoxLayout()
        self.buttonBtm.addWidget(self.btnDownload)
        self.buttonBtm.addWidget(self.btnCancel)

        self.windowLayout.addLayout(self.topBar)
        self.windowLayout.addLayout(self.statusLayout)
        self.windowLayout.addLayout(self.buttonBtm)

    def setActions(self):
        self.btnAdvancedOptions.clicked.connect(self.showAdvancedOptions)
        self.btnDownload.clicked.connect(self.doDownload)
        self.btnCancel.clicked.connect(self.reject)

    def showAdvancedOptions(self):
        if self.advancedOptionsFrame.isHidden():
            self.advancedOptionsFrame.show()
            self.btnAdvancedOptions.setText("Hide advanced options")
        else:
            self.advancedOptionsFrame.hide()
            self.btnAdvancedOptions.setText("Show advanced options")

    def getBranch(self):
        return self.comboBranch.cb.currentText()

    def doDownload(self):
        branch = self.getBranch()
        updateVariables = UpdateVariables(branch)
        try:
            cwd = os.getcwd()
            dirname = os.path.basename(cwd)
            if dirname.upper() == updateVariables.codeDir.upper():
                raise Exception(
                    "This script must not be run with the current directory being \"{}\""
                    ", because it needs to replace that directory".format(cwd))

            # compute the root directory (`Jinn`) via where this script is being run from
            stdOut = setRootDir()

            updateJTextEdit(self.updateLog, stdOut)
            # download the zip file from github to the `Jinn` directory
            downloadZipFile(self.updateLog, updateVariables)

            # extract from the zip file to create `Jinn-master` directory in `Jinn` directory
            extractFromZipFile(self.updateLog, updateVariables)

            updateJTextEdit(
                self.updateLog,
                "Finished downloading and extracting latest Jinn code. Please insert the USB into your "
                "work computer and run the installer.")
        except Exception as ex:
            raise ex
        InfoMsgBox(
            "Finished",
            "Download has finished. You can now close the downloader and remove the USB stick. To continue "
            "upgrading Jinn plug this USB stick into your work PC and run the 'Jinn updater' shortcut",
            "Download finished").exec()
Ejemplo n.º 4
0
class WidgetGallery(QDialog):
    def __init__(self, parent=None):
        super(WidgetGallery, self).__init__(parent)

        self.originalPalette = QApplication.palette()

        right_layout = self.create_right_layout()
        self.create_top_left_group_box()
        self.create_bottom_left_group_box()
        self.create_center_group_box()

        mainLayout = QGridLayout()
        mainLayout.addLayout(right_layout, 0, 2, 0, 1)
        mainLayout.addLayout(self.top_left_group_box, 0, 0)
        mainLayout.addWidget(self.bottom_left_group_box, 1, 0)
        mainLayout.addWidget(self.center_group_box, 1, 1)

        self.setLayout(mainLayout)

        self.setWindowTitle("Styles")

    def create_right_layout(self):
        # create list view
        self.my_list_widget = FaceList()
        self.my_list_widget.setFixedWidth(constant.RIGHT_LAYOUT_WIDTH)
        get_face_detect(self.my_list_widget)

        # create label
        label = QLabel()
        label.setText("Face Recognition")

        # create button
        add_face_button = QPushButton()
        add_face_button.setText("Add Face")
        add_face_button.clicked.connect(self.add_face_dialog)

        right_layout = QVBoxLayout()
        right_layout.addWidget(label)
        # right_layout.addStretch()
        right_layout.addWidget(self.my_list_widget)
        right_layout.addWidget(add_face_button)

        return right_layout

    def create_top_left_group_box(self):
        self.top_left_group_box = QGridLayout()
        face_recognition = QPushButton()
        face_recognition.setText("Face Recognition")
        face_recognition.clicked.connect(lambda: btn_face_recognition())

        self.top_left_group_box.addWidget(face_recognition)

    def create_bottom_left_group_box(self):
        self.bottom_left_group_box = QGroupBox("control")
        self.bottom_left_group_box.setFixedWidth(constant.LEFT_LAYOUT_WIDTH)

        tree = QTreeWidget()
        recorders = 1
        cams = 2
        for i in range(recorders):
            parent = QTreeWidgetItem(tree)
            parent.setText(0, "Recorder {}".format(i + 1))
            parent.setFlags(parent.flags() | Qt.ItemIsTristate
                            | Qt.ItemIsUserCheckable)
            for x in range(cams):
                child = QTreeWidgetItem(parent)
                child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
                child.setText(0, "Cam {}".format(x + 1))
                child.setCheckState(0, Qt.Unchecked)

        show = QPushButton()
        show.setText("Show")
        show.clicked.connect(
            lambda: btn_show(all_link_camera, self.grid_layout, tree))

        # TODO
        layout = QVBoxLayout()
        layout.addWidget(show)
        layout.addWidget(tree)
        self.bottom_left_group_box.setLayout(layout)

    def create_center_group_box(self):
        self.center_group_box = QGroupBox("Show")
        self.center_group_box.setMinimumWidth(300)

        # TODO
        self.grid_layout = QGridLayout()
        self.center_group_box.setLayout(self.grid_layout)

    def add_face_dialog(self):
        self.image = QLabel()

        # button Browse face file
        browse_button = QPushButton()
        browse_button.setText("Browse File")
        browse_button.clicked.connect(self.browse_image)

        # text box input name
        name = QLabel()
        name.setText("Name")
        self.name_input = QLineEdit()

        hbox = QHBoxLayout()
        hbox.addWidget(name)
        hbox.addWidget(self.name_input)

        save = QPushButton()
        save.setText("Save")
        save.clicked.connect(self.save_image)

        vbox_sub = QVBoxLayout()
        vbox_sub.addLayout(hbox)
        vbox_sub.addWidget(save)

        self.frame = QFrame()
        self.frame.setLayout(vbox_sub)
        self.frame.setHidden(True)

        vbox_main = QVBoxLayout()
        vbox_main.addWidget(browse_button)
        vbox_main.addWidget(self.image)
        vbox_main.addWidget(self.frame)

        d = QDialog()
        d.setGeometry(0, 0, 300, 400)
        d.setLayout(vbox_main)
        d.setWindowTitle("Dialog")
        d.setWindowModality(Qt.ApplicationModal)
        d.exec_()

    def browse_image(self):
        file_dialog = QFileDialog()
        file_dialog.setNameFilters(
            ["Text files (*.txt)", "Images (*.png *.jpg)"])
        file_dialog.selectNameFilter("Images (*.png *.jpg)")

        filename = file_dialog.getOpenFileName()
        self.src_image = filename[0]
        pixmap = QPixmap(self.src_image).scaledToWidth(300)
        self.image.setPixmap(pixmap)
        self.frame.setHidden(False)

    def save_image(self):
        name = self.name_input.text()
        print({Path(__file__).parent.parent})
        path = f"{Path(__file__).parent.parent}/core/dataset/new_face/{name}"
        if not os.path.exists(path):
            os.mkdir(path)
        count = len([name for name in os.listdir('.') if os.path.isfile(name)])
        copyfile(self.src_image, f"{path}/{os.path.basename(self.src_image)}")
        send_data_socket(constant.TRAIN_NEW_FACE_MESSAGE)
Ejemplo n.º 5
0
class QCollapsibleFrame(QWidget):
    def __init__(self, title, parent):
        super().__init__(parent)
        self.widget = None
        self.headerWidget = None
        self.contentsFrame = None
        self.mainLayout = QVBoxLayout()
        self.mainLayout.setSpacing(0)
        self.mainLayout.setContentsMargins(2, 2, 2, 2)
        self.setLayout(self.mainLayout)

        self.SetHeaderWidget(CCollapsibleFrameHeader(title, self))

    def getWidget(self):
        return self.widget

    def getDragHandler(self):
        return self.headerWidget.collapseButton

    def setWidget(self, widget):
        if not self.contentsFrame:
            self.contentsFrame = QFrame(self)
            frameLayout = QVBoxLayout()
            frameLayout.setSpacing(0)
            frameLayout.setContentsMargins(2, 2, 2, 2)
            self.contentsFrame.setLayout(frameLayout)
            self.layout().addWidget(self.contentsFrame)

        mainLayout = self.contentsFrame.layout()

        if self.widget:
            mainLayout.removeWidget(self.widget)
            self.widget.deleteLater()

        self.widget = widget
        if self.widget:
            mainLayout.addWidget(self.widget)
            self.contentsFrame.setHidden(self.headerWidget.bCollapsed)

    def setClosable(self, closable):
        self.headerWidget.setClosable(closable)

    def closable(self):
        return self.headerWidget.closable()

    def setTitle(self, title):
        self.headerWidget.setTitle(title)

    def collapsed(self):
        return self.headerWidget.bCollapsed

    def setCollapsed(self, bCollapsed):
        self.headerWidget.setCollapsed(bCollapsed)

    def setCollapsedStateChangeCallback(self, callback):
        self.headerWidget.onCollapsedStateChanged = callback

    def paintEvent(self, e):
        opt = QStyleOption()
        opt.initFrom(self)
        painter = QPainter(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)

    def setHearderWidget(self, header):
        self.headerWidget = header
        self.layout().addWidget(header)
        self.headerWidget.closeButton.clicked.connect(self.onCloseRequested)

    def onCloseRequested(self):
        self.closeRequested(self)

    def closeRequested(self, caller):
        pass
Ejemplo n.º 6
0
class Filter:
    locks = dict()

    def __init__(self, filter_content):
        self.filter_content = filter_content
        self.filter = dict()
        self.frame = QFrame()
        self.frame.setObjectName("Filter_frame")
        self.frame.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        actual_layout = QVBoxLayout()
        widget_frame = QFrame()
        self.layout = QVBoxLayout()
        widget_frame.setLayout(self.layout)
        actual_layout.addWidget(widget_frame)
        actual_layout.addStretch(1)
        self.filter_names = []
        self.frame.setLayout(actual_layout)
        self.frame.setHidden(True)

    def add_range(self, name, capitalize=False):
        min_input = QLineEdit()
        max_input = QLineEdit()
        min_input.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        min_input.setMaximumWidth(50)
        max_input.setMaximumWidth(50)
        if capitalize:
            name = name.capitalize()
        title = QLabel(name)
        dash = QLabel("-")
        frame = QFrame()
        layout = QHBoxLayout()
        layout.addWidget(min_input)
        layout.addStretch(0)
        layout.addWidget(dash)
        layout.addStretch(0)
        layout.addWidget(max_input)
        frame.setLayout(layout)
        # frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.layout.addWidget(title)
        self.layout.addWidget(frame)

        min_input.textChanged.connect(
            lambda: self.set_range_filter(name, min_input, max_input))
        max_input.textChanged.connect(
            lambda: self.set_range_filter(name, min_input, max_input))

    def set_range_filter(self, name, min_input, max_input):
        name = name.lower()
        minimum = -9001
        maximum = 9001
        try:
            minimum = int(min_input.text())
        except:
            pass
        try:
            maximum = int(max_input.text())
        except:
            pass

        if minimum == -9001 and maximum == 9001:
            if name in self.filter.keys():
                del self.filter[name]
        else:
            self.filter[name] = [minimum, maximum]
        self.filter_content()

    def add_dropdown(self,
                     name,
                     options,
                     suboptions=None,
                     default=None,
                     alphabetical=True):
        if alphabetical:
            options.sort()
        combo_box = QComboBox()
        combo_box.addItem("Any")
        combo_box.addItems(options)
        if suboptions is not None:
            sub_combo_box = QComboBox()
            sub_combo_box.setHidden(True)
        else:
            sub_combo_box = None
        label = QLabel(name)
        self.filter_names.append(name)
        self.layout.addWidget(label)
        self.layout.addWidget(combo_box)
        if suboptions is not None:
            self.layout.addWidget(sub_combo_box)
            sub_combo_box.currentIndexChanged.connect(
                lambda: self.set_sub_filters(name, combo_box, sub_combo_box))
        combo_box.currentIndexChanged.connect(lambda: self.set_filters(
            name, combo_box, sub_combo_box, suboptions))

        if default is not None:
            index = combo_box.findText(default, QtCore.Qt.MatchFixedString)
            if index >= 0:
                combo_box.setCurrentIndex(index)

    def set_sub_filters(self, name, combo_box, sub_combo_box):
        name = name.lower()
        main = combo_box.currentText().lower()
        sub = sub_combo_box.currentText().lower()
        if sub == "any":
            self.filter[name] = main + ".*"
        else:
            self.filter[name] = main + ".*(\ \(|\,\ )(" + sub + ").*"
        self.filter_content()

    def set_filters(self,
                    name,
                    combo_box,
                    sub_combo_box=None,
                    suboptions=None):
        main = combo_box.currentText()
        sub_cond = sub_combo_box is not None
        if sub_cond:
            sub = sub_combo_box.currentText()

        name = name.lower()
        if main == "Any" and name in self.filter.keys():
            del self.filter[name]
            if sub_cond:
                sub_combo_box.setHidden(True)
        else:
            if sub_cond:
                if main in suboptions.keys():
                    _suboptions = [
                        subopt for subopt in suboptions[main]
                        if subopt != "Any"
                    ]  # remove Any as suboption
                    sub_combo_box.setHidden(False)
                    sub_combo_box.clear()
                    sub_combo_box.addItem("Any")
                    sub_combo_box.addItems(_suboptions)
                else:
                    sub_combo_box.clear()
                    sub_combo_box.setHidden(True)
            self.filter[name] = main + ".*"
        # print(self.filter[name])
        self.filter_content()

    def lock(self, attr, value):
        self.locks[attr] = value

    def get_frame(self):
        return self.frame

    def toggle_hidden(self):
        if self.frame.isHidden():
            self.frame.setHidden(False)
        else:
            self.frame.setHidden(True)

    def evaluate_filter(self, entry):
        cond = True
        for key, arg in self.locks.items():
            if not hasattr(entry, key) or getattr(entry, key) != arg:
                return False
        for key, arg in self.filter.items():
            if not hasattr(entry, key):
                # print("Wrong filter key passed to entry in SearchableTable")
                return False
            attr = getattr(entry, key)
            if type(arg) is str and type(
                    attr
            ) is str:  # single attribute, single argument. Easy as pie
                p = re.compile('{}'.format(arg), re.IGNORECASE)
                cond = cond and (p.match(attr))
            elif type(
                    attr
            ) is list:  # single argument, multiple attributes, eval individually for each element
                p = re.compile('{}'.format(arg), re.IGNORECASE)
                cond = cond and any([p.match(_attr) for _attr in attr])
            elif type(
                    arg
            ) is list:  # numerical range, must be inbetween two values
                if attr is None or None in arg:
                    continue
                attr = eval("float({})".format(attr))
                cond = cond and (arg[0] <= attr <= arg[1])

        return cond

    def clear_filters(self):
        for i in reversed(range(self.layout.count())):
            self.layout.removeItem(self.layout.itemAt(i))
        self.filter = dict()
Ejemplo n.º 7
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.smal_params = {
            'betas' : torch.zeros(1, NUM_SHAPE_PARAMS),
            'joint_rotations' : torch.zeros(1, NUM_POSE_PARAMS, 3),
            'global_rotation' :  torch.zeros(1, 1, 3),
            'trans' : torch.zeros(1, 1, 3),
        }

        self.model_renderer = Renderer(RENDER_SIZE)
        self.smal_model = SMAL('data/my_smpl_00781_4_all.pkl')

        with open('data/my_smpl_data_00781_4_all.pkl', 'rb') as f:
            u = pkl._Unpickler(f)
            u.encoding = 'latin1'
            smal_data = u.load()

        self.toy_betas = smal_data['toys_betas']
        self.setup_ui()

    def get_layout_region(self, control_set):
        layout_region = QVBoxLayout()

        scrollArea = QScrollArea()
        scrollArea.setWidgetResizable(True)
        scrollAreaWidgetContents = QWidget(scrollArea)
        scrollArea.setWidget(scrollAreaWidgetContents)
        scrollArea.setMinimumWidth(750)

        grid_layout = QGridLayout()

        for idx, (label, com_slider) in enumerate(control_set):
            grid_layout.addWidget(label, idx, 0)
            grid_layout.addWidget(com_slider, idx, 1)
        
        scrollAreaWidgetContents.setLayout(grid_layout)

        layout_region.addWidget(scrollArea)
        return layout_region

    def setup_ui(self):
        self.shape_controls = []
        self.pose_controls = []
        self.update_poly = True
        self.toy_pbs = []

        def ctrl_layout_add_separator():
            line = QFrame()
            line.setFrameShape(QFrame.HLine)
            line.setFrameShadow(QFrame.Sunken)
            ctrl_layout.addWidget(line)

        # SHAPE REGION
        std_devs = np.std(self.toy_betas, axis=1)
        for idx, toy_std in enumerate(std_devs):
            label = QLabel("S{0}".format(idx))
            sliders = ShapeSlider(idx, toy_std)
            sliders.value_changed.connect(self.update_model)
            self.shape_controls.append((label, sliders))
            self.toy_pbs.append(QPushButton("T{0}".format(idx)))

        reset_shape_pb = QPushButton('Reset Shape')
        reset_shape_pb.clicked.connect(self.reset_shape)

        self.toy_frame = QFrame()
        self.toy_layout = QGridLayout()
        for idx, pb in enumerate(self.toy_pbs):
            row = idx // 5
            col = idx - row * 5
            pb.clicked.connect(partial(self.make_toy_shape, idx))
            self.toy_layout.addWidget(pb, row, col)

        self.toy_frame.setLayout(self.toy_layout)
        self.toy_frame.setHidden(True)

        show_toys_cb = QCheckBox('Show Toys', self)
        show_toys_cb.stateChanged.connect(partial(self.toggle_control, self.toy_frame))
        
        shape_layout = self.get_layout_region(self.shape_controls)
        shape_layout.addWidget(reset_shape_pb)
        shape_layout.addWidget(show_toys_cb)

        ctrl_layout = QVBoxLayout()
        ctrl_layout.addLayout(shape_layout)
        ctrl_layout.addWidget(self.toy_frame)
        ctrl_layout_add_separator()

        # POSE REGION
        model_joints = NUM_POSE_PARAMS
        for idx in range(model_joints):
            if idx == 0:
                label = QLabel("Root Pose (P{0})".format(idx))
                slider = PoseSlider(idx, 2 * np.pi, vert_stack = True)
            else:
                label = QLabel("P{0}".format(idx))
                slider = PoseSlider(idx, np.pi)

            slider.value_changed.connect(self.update_model)
            self.pose_controls.append((label, slider))

        reset_pose_pb = QPushButton('Reset Pose')
        reset_pose_pb.clicked.connect(self.reset_pose)

        root_pose_dict = collections.OrderedDict()
        # root_pose_dict[ "Face Left" ] = np.array([0, 0, np.pi])
        # root_pose_dict[ "Diag Left" ] = np.array([0, 0, 3 * np.pi / 2])
        # root_pose_dict[ "Head On" ] = np.array([0, 0, np.pi / 2])
        # root_pose_dict[ "Diag Right" ] = np.array([0, 0, np.pi / 4])
        # root_pose_dict[ "Face Right" ] = np.array([0, 0, 0])
        # root_pose_dict[ "Straight Up" ] = np.array([np.pi / 2, 0, np.pi / 2])
        # root_pose_dict[ "Straight Down" ] = np.array([-np.pi / 2, 0, np.pi / 2])

        root_pose_dict[ "Face Left" ] = np.array([-np.pi / 2, 0, -np.pi])
        root_pose_dict[ "Diag Left" ] = np.array([-np.pi / 2, 0, -3 * np.pi / 4])
        root_pose_dict[ "Head On" ] = np.array([-np.pi / 2, 0, -np.pi / 2])
        root_pose_dict[ "Diag Right" ] = np.array([-np.pi / 2, 0, -np.pi / 4])
        root_pose_dict[ "Face Right" ] = np.array([-np.pi / 2, 0, 0])

        root_pose_dict[ "Straight Up" ] = np.array([np.pi, np.pi, -np.pi / 2])
        root_pose_dict[ "Straight Down" ] = np.array([np.pi, np.pi, np.pi / 2])

        root_pose_layout = QGridLayout()
        idx = 0
        for key, value in root_pose_dict.items():
            head_on_pb = QPushButton(key)
            head_on_pb.clicked.connect(partial(self.set_known_pose, value))
            root_pose_layout.addWidget(head_on_pb, 0, idx)
            idx = idx + 1
   
        pose_layout = QGridLayout()
        root_label, root_pose_sliders = self.pose_controls[0]

        pose_layout.addWidget(root_label, 0, 0)
        pose_layout.addWidget(root_pose_sliders, 1, 0)
        pose_layout.addLayout(self.get_layout_region(self.pose_controls[1:]), 2, 0)
        pose_layout.addWidget(reset_pose_pb)

        ctrl_layout.addLayout(pose_layout)
        ctrl_layout.addLayout(root_pose_layout)
        ctrl_layout_add_separator()

        # TRANSLATION REGION
        trans_label = QLabel("Root Translation".format(idx))
        self.trans_sliders = TransSlider(idx, -5.0, 5.0, np.array([0.0, 0.0, 0.0]), vert_stack = True)
        self.trans_sliders.value_changed.connect(self.update_model)

        reset_trans_pb = QPushButton('Reset Translation')
        reset_trans_pb.clicked.connect(self.reset_trans)
          
        # Add the translation slider
        trans_layout = QGridLayout()
        trans_layout.addWidget(trans_label, 0, 0)
        trans_layout.addWidget(self.trans_sliders, 1, 0)
        trans_layout.addWidget(reset_trans_pb, 2, 0)

        self.trans_frame = QFrame()
        self.trans_frame.setLayout(trans_layout)
        self.trans_frame.setHidden(True)

        show_trans_cb = QCheckBox('Show Translation Parameters', self)
        show_trans_cb.stateChanged.connect(partial(self.toggle_control, self.trans_frame))

        ctrl_layout.addWidget(show_trans_cb)
        ctrl_layout.addWidget(self.trans_frame)
        ctrl_layout_add_separator()

        # ACTION BUTTONS
        reset_pb = QPushButton('&Reset')
        reset_pb.clicked.connect(self.reset_model)

        export_image_pb = QPushButton('&Export Image')
        export_image_pb.clicked.connect(self.export_image)

        misc_pbs_layout = QGridLayout() 
        misc_pbs_layout.addWidget(reset_pb, 0, 0)
        misc_pbs_layout.addWidget(export_image_pb, 0, 1)
        ctrl_layout.addLayout(misc_pbs_layout)
        ctrl_layout_add_separator()

        view_layout = QVBoxLayout()
        self.render_img_label = QLabel()
        view_layout.addWidget(self.render_img_label)

        main_layout = QHBoxLayout()
        main_layout.addLayout(ctrl_layout)
        main_layout.addLayout(view_layout)

        main_widget = QWidget()
        main_widget.setLayout(main_layout)
        self.setCentralWidget(main_widget)
        
        # WINDOW
        self.window_title_stem = 'SMAL Model Viewer'
        self.setWindowTitle(self.window_title_stem)
        
        self.statusBar().showMessage('Ready...')
        self.update_render()
        
        self.showMaximized()

    def update_model(self, value):
        sender = self.sender()

        if type(sender) is ShapeSlider:
            self.smal_params['betas'][0, sender.idx] = value
        elif type(sender) is PoseSlider:
            if sender.idx == 0:
                self.smal_params['global_rotation'][0, sender.idx] = torch.FloatTensor(value)
            else:
                self.smal_params['joint_rotations'][0, sender.idx - 1] = torch.FloatTensor(value)
        elif type(sender) is TransSlider:
            self.smal_params['trans'][0] = torch.FloatTensor(value)

        if self.update_poly:
            self.update_render()

    def update_render(self):
        with torch.no_grad():
            start = time.time()
            verts, joints, Rs, v_shaped = self.smal_model(
                self.smal_params['betas'], 
                torch.cat([self.smal_params['global_rotation'], self.smal_params['joint_rotations']], dim = 1))

            # normalize by center of mass
            verts = verts - torch.mean(verts, dim = 1, keepdim=True)

            # add on the translation
            verts = verts + self.smal_params['trans']

            end = time.time()
            ellapsed  = end - start
            print (f"SMAL Time: {ellapsed }")

            start = time.time()
            rendered_images = self.model_renderer(verts, self.smal_model.faces.unsqueeze(0))
            end = time.time()
            ellapsed = end - start
            print (f"Renderer Time: {ellapsed }")
        
        self.image_np = rendered_images[0, :, :, :3]
        self.render_img_label.setPixmap(self.image_to_pixmap(self.image_np, DISPLAY_SIZE))
        self.render_img_label.update()

    def reset_shape(self):
        # Reset sliders to zero
        self.update_poly = False
        for label, com_slider in self.shape_controls:
            com_slider.reset()
        self.update_poly = True
        self.update_render()

    def reset_pose(self):
        self.update_poly = False
        for label, com_slider in self.pose_controls:
            com_slider.reset()
        self.update_poly = True
        self.update_render()

    def make_toy_shape(self, toy_id):
        self.update_poly = False
        toy_betas = self.toy_betas[toy_id]
        for idx, val in enumerate(toy_betas):
            label, shape_slider = self.shape_controls[idx]
            shape_slider.setValue(val)

        self.update_poly = True
        self.statusBar().showMessage(str(toy_betas))
        self.smal_params['betas'][0] = torch.from_numpy(toy_betas)
        self.update_render()

    def toggle_control(self, layout):
        sender = self.sender()
        layout.setHidden(not sender.isChecked())
            
    def set_known_pose(self, pose):
        label, root_pose_slider = self.pose_controls[0]
        root_pose_slider.setValue(pose)
        root_pose_slider.force_emit()

    def reset_trans(self):
        self.trans_sliders.reset()

    def reset_model(self):
        self.reset_shape()
        self.reset_pose()
        self.reset_trans()

    def image_to_pixmap(self, img, img_size):
        im = np.require(img * 255.0, dtype='uint8')
        qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888).copy()
        pixmap = QPixmap(qim)
        return pixmap.scaled(img_size, img_size, QtCore.Qt.KeepAspectRatio)

    def export_image(self):
        out_dir = "output"
        if not os.path.exists(out_dir):
            os.mkdir(out_dir)

        time_str = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
        scipy.misc.imsave(os.path.join(out_dir, "{0}.png".format(time_str)), self.image_np)
class PluginConfigDialog(QDialog):
    class WidgetWrapper:
        """ Wraps a widget (e.g. QLineEdit, QCheckbox, etc.) and enhances it with a validate and onChange method. """
        def __init__(self, option: PluginConfig.Option.Base, widget,
                     get_value_callback, config, on_change_signal):
            self.name = option.name
            self.widget = widget
            self.config = config
            self._get_value_callback = get_value_callback
            self.validate = lambda codec, input: self.config.validate(
                option, codec, input)
            self.onChange = on_change_signal

        def _get_value(self):
            return self._get_value_callback()

        value = property(_get_value)

    def __init__(self, context, config, title, codec, icon=None):
        super(PluginConfigDialog, self).__init__()
        self._context = context
        self.config = config
        self._codec = codec
        self._input = None
        self._widgets = {}
        self.setLayout(self._init_main_layout())
        self._build()
        self._init_shortcuts()
        self._validate()
        self.setWindowTitle(title)
        if icon:
            self.setWindowIcon(icon)

    def _init_main_layout(self):
        main_layout = QVBoxLayout()
        main_layout.addWidget(self._init_input_frame())
        main_layout.addWidget(self._init_error_frame())
        self._btn_box = self._init_button_box()
        main_layout.addWidget(self._btn_box)
        return main_layout

    def _init_error_frame(self):
        self._error_frame = QFrame()
        layout = QVBoxLayout()
        self._error_text = QLabel("")
        self._error_text.setStyleSheet('QLabel { color: red }')
        layout.addWidget(self._error_text)
        self._error_frame.setLayout(layout)
        self._error_frame.setHidden(True)
        return self._error_frame

    def _init_button_box(self):
        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        return button_box

    def _init_shortcuts(self):
        def _accept(self):
            if self._btn_box(QDialogButtonBox.Ok).isEnabled():
                self.accept()

        ctrl_return_shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Return),
                                         self)
        ctrl_return_shortcut.activated.connect(_accept)
        alt_return_shortcut = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Return),
                                        self)
        alt_return_shortcut.activated.connect(_accept)
        alt_o_shortcut = QShortcut(QKeySequence(Qt.ALT + Qt.Key_O), self)
        alt_o_shortcut.activated.connect(_accept)

    def _init_input_frame(self):
        input_frame = QGroupBox()
        self._input_frame_layout = QFormLayout()
        input_frame.setLayout(self._input_frame_layout)
        return input_frame

    def _on_change(self):
        """ Update and validate options. """
        self.config.update(
            {key: self._widgets[key].value
             for key in self.config.keys()})
        self._btn_box.button(QDialogButtonBox.Ok).setEnabled(self._validate())

    def _validate(self):
        """ Validate the current settings. """
        self._reset_errors()
        for key, widget_wrapper in self._widgets.items():
            message = widget_wrapper.validate(self._codec, self._input)
            if message is not True:
                self._show_error_indicator(widget_wrapper)
                self._show_error_message(message)
                return False

        message = self._try_codec()
        if message:
            self._show_error_message(message)
            return False

        return True

    def _try_codec(self):
        """ Tries to run the codec with the specified input. Either returns None or an error message."""
        try:
            self._codec(self.config, self._input)
        except BaseException as e:
            return str(e)

    def _reset_errors(self):
        """ Hides error message box and resets any error indicators. """
        self._error_frame.setHidden(True)
        self._error_text.setText("")
        for name in self.config.keys():
            self._reset_error(self._widgets[name])

    def _reset_error(self, widget_wrapper):
        """
        Resets any error indication on a specific widget.
        This method can be overwritten to allow customizing visualization of errors for specific widgets.
        """
        widget = widget_wrapper.widget
        if isinstance(widget, QLineEdit):
            widget.setStyleSheet('QLineEdit { }')

    def _show_error_indicator(self, widget_wrapper):
        """
        Indicates an error on a specific widget.
        This method can be overwritten to allow customizing visualization of errors for specific widgets.
        """
        widget = widget_wrapper.widget
        if isinstance(widget, QLineEdit):
            widget.setStyleSheet('QLineEdit { color: red }')

    def _show_error_message(self, message):
        """ Shows an error message within a error-box. """
        self._error_frame.setHidden(False)
        self._error_text.setText(message)

    def _build_option(self, option: PluginConfig.Option.Base) -> WidgetWrapper:
        """
        Automatically build the widget for this option.
        This method can be overwritten to allow building custom widgets.
        :return the widget for this option.
        """
        if isinstance(option, PluginConfig.Option.String):
            x = QLineEdit(option.value)
            w = PluginConfigDialog.WidgetWrapper(option, x, x.text,
                                                 self.config, x.textChanged)
            w.onChange.connect(lambda evt: self._on_change())
        elif isinstance(option, PluginConfig.Option.Integer):
            x = QLineEdit(option.value)
            w = PluginConfigDialog.WidgetWrapper(option, x, x.text,
                                                 self.config, x.textChanged)
            w.onChange.connect(lambda evt: self._on_change())
        elif isinstance(option, PluginConfig.Option.Group):
            x = QRadioButton(option.name)
            x.setChecked(option.value)
            w = PluginConfigDialog.WidgetWrapper(option, x, x.isChecked,
                                                 self.config, x.clicked)
            w.onChange.connect(lambda evt: self._on_change())
        elif isinstance(option, PluginConfig.Option.Boolean):
            x = QCheckBox(option.name)
            x.setChecked(option.value)
            w = PluginConfigDialog.WidgetWrapper(option, x, x.isChecked,
                                                 self.config, x.clicked)
            w.onChange.connect(lambda evt: self._on_change())
        else:
            raise Exception("Invalid option of type {} detected!".format(
                type(option)))
        return w

    def _add_option_widget(self, label: QLabel, widget):
        self._input_frame_layout.addRow(label, widget)

    def _build(self):
        """
        Automatically build the widgets for all options.
        This method can be overwritten to allow building custom widgets.
        """
        for key, option in self.config.items():
            label = QLabel()
            if not isinstance(option, PluginConfig.Option.Boolean):
                label.setText(option.name)
            self._widgets[key] = self._build_option(option)
            self._add_option_widget(label, self._widgets[key].widget)

    def setInput(self, text):
        self._input = text
        self._on_change()
class ReformatDialog(QDialog):

    def __init__(self, context, input, config, codec):
        super(ReformatDialog, self).__init__()
        self._context = context
        self._input = input
        self.config = config
        self._codec = codec
        self.setLayout(self._init_main_layout())
        self._update_view()
        self.setWindowIcon(qtawesome.icon("fa.edit"))
        self.setWindowTitle("Reformat Text")

    def _init_main_layout(self):
        frm_main_layout = QVBoxLayout()
        frm_main_layout.addWidget(self._init_form_frame())
        self._txt_preview = QPlainTextEdit(self)
        self._txt_preview.setReadOnly(True)
        self._txt_preview.setFixedHeight(126)
        frm_main_layout.addWidget(self._txt_preview)
        frm_main_layout.addWidget(self._init_error_frame())
        self._btn_box = self._init_button_box()
        frm_main_layout.addWidget(self._btn_box)
        return frm_main_layout

    def _init_error_frame(self):
        self._error_frame = QFrame()
        layout = QVBoxLayout()
        self._error_text = QLabel("")
        self._error_text.setStyleSheet('QLabel { color: red }')
        layout.addWidget(self._error_text)
        self._error_frame.setLayout(layout)
        self._error_frame.setHidden(True)
        return self._error_frame

    def _init_form_frame(self):
        # Define input fields and register change events
        self._txt_format = QLineEdit()
        self._txt_format.setText(self.config.get(Plugin.Option.Format).value)
        self._txt_format.textChanged.connect(self._on_change_event)

        self._btn_format_help = QToolButton()
        self._btn_format_help.setText("?")
        self._btn_format_help.clicked.connect(lambda evt: QDesktopServices.openUrl(QUrl("https://pyformat.info/")))

        self._txt_split_char = QLineEdit()
        self._txt_split_char.setText(self.config.get(Plugin.Option.SplitChars).value)
        self._txt_split_char.textChanged.connect(self._on_change_event)

        self._chk_regex = QCheckBox("Regex")
        self._chk_regex.setChecked(self.config.get(Plugin.Option.IsRegex).value)
        self._chk_regex.clicked.connect(self._on_change_event)

        self._chk_new_lines = QCheckBox("Handle Newline")
        self._chk_new_lines.setChecked(self.config.get(Plugin.Option.HandleNewlines).value)
        self._chk_new_lines.clicked.connect(self._on_change_event)

        # Build layout
        frm_frame = QFrame()
        frm_layout = QHBoxLayout()
        frm_layout.addWidget(QLabel("Format: "))
        frm_layout.addWidget(self._txt_format)
        frm_layout.addWidget(self._btn_format_help)
        frm_layout.addWidget(QLabel("Split by: "))
        frm_layout.addWidget(self._txt_split_char)
        frm_layout.addWidget(self._chk_regex)
        frm_layout.addWidget(self._chk_new_lines)
        frm_frame.setLayout(frm_layout)
        return frm_frame

    def _init_button_box(self):
        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(self.accept)
        btn_box.rejected.connect(self.reject)
        return btn_box

    def _validate_regex(self):
        try:
            if self._is_regex():
                re.compile(self._get_format_text())
            return True
        except:
            return False

    def _update_view(self):
        self._txt_format.setText(self.config.get(Plugin.Option.Format).value)
        self._txt_split_char.setText(self.config.get(Plugin.Option.SplitChars).value)
        self._chk_regex.setChecked(self.config.get(Plugin.Option.IsRegex).value)
        self._chk_new_lines.setChecked(self.config.get(Plugin.Option.HandleNewlines).value)
        self._on_change_event(None)

    def _on_change_event(self, event):
        if not self._txt_split_char.text():
            self._show_error_message(self._txt_split_char, "Split by text should not be empty!")
            self._btn_box.button(QDialogButtonBox.Ok).setEnabled(False)
            return

        if self._chk_regex.isChecked() and self._validate_regex():
            self._show_error_message(self._txt_split_char, "Invalid regular expression!")
            self._btn_box.button(QDialogButtonBox.Ok).setEnabled(False)
            return

        if not self._do_preview():
            self._show_error_message(self._txt_format, "Invalid format string!")
            self._btn_box.button(QDialogButtonBox.Ok).setEnabled(False)
            return

        self._hide_error_message([self._txt_format, self._txt_split_char])
        self._btn_box.button(QDialogButtonBox.Ok).setEnabled(True)

        self.config.get(Plugin.Option.Format).value = self._txt_format.text()
        self.config.get(Plugin.Option.IsRegex).value = self._chk_regex.isChecked()
        self.config.get(Plugin.Option.SplitChars).value = self._txt_split_char.text()

    def _do_preview(self):
        try:
            result = self._codec.reformat(self._input, self._txt_format.text(), self._txt_split_char.text(),
                                          self._chk_regex.isChecked(), self._chk_new_lines.isChecked())
            self._txt_preview.setPlainText(result)
            return True
        except BaseException as e:
            return False

    def _show_error_message(self, widget, text: str):
        widget.setStyleSheet('QLineEdit { background-color: red }')
        self._error_frame.setHidden(False)
        self._error_text.setText(text)

    def _hide_error_message(self, widgets):
        self._error_frame.setHidden(False)
        self._error_text.setText("")
        for widget in widgets:
            widget.setStyleSheet('QLineEdit {  }')

    def setInput(self, input):
        self._input = input
Ejemplo n.º 10
0
class DMTool(QMainWindow):
    SEARCH_BOX_WIDTH = 200

    def __init__(self, db_path, validate_views=False):
        super().__init__()
        self._database_path = db_path
        sys.excepthook = self.excepthook
        self.settings = dict({"query_srd": True})
        self.load_meta()
        self._setup_ui()
        self._setup_menu()
        self.bind_signals()
        self.load_session()
        self._display_ui()
        if validate_views:
            self.validate_views()

    def _setup_ui(self):
        """
        Layout is a windowLayout with a horizontal box on the left and a tab widget on the right
        :return:
        """
        self.setStyleSheet(
            open(os.path.join("assets", "styles", "default.css")).read())
        self.setWindowIcon(QIcon(os.path.join('assets', 'tear.png')))
        self.setWindowTitle("RainyDM")
        self.setGeometry(100, 100, 1280, 720)
        self.window_frame = QFrame()
        self.window_layout = QHBoxLayout()
        # Left side tab
        self.tab_widget = QTabWidget()

        # Viewers
        # - monster viewer
        monster_button_bar = QFrame()
        monster_button_bar_layout = QHBoxLayout()
        monster_button_bar.setLayout(monster_button_bar_layout)
        self.monster_viewer = MonsterViewer(monster_button_bar, self.system)
        monster_viewer_frame_layout = QVBoxLayout()
        self.monster_viewer_frame = QFrame()
        self.monster_viewer_frame.setLayout(monster_viewer_frame_layout)
        self.monster_viewer_frame.layout().setContentsMargins(0, 0, 0, 0)
        self.monster_viewer_frame.setFrameStyle(0)

        # - spell viewer
        self.spell_viewer = SpellViewer(self.system)

        # - item viewer
        self.item_viewer = ItemViewer(self.system)

        # Text box
        self.text_box = QTextEdit()
        self.text_box.setObjectName("OutputField")
        self.text_box.setReadOnly(True)
        self.text_box.setFontPointSize(10)

        ## Tables
        # Spell Table
        self.spell_table_widget = SpellTableWidget(self, self.spell_viewer)

        # Monster table
        self.monster_table_widget = MonsterTableWidget(self,
                                                       self.monster_viewer)

        # Item table
        self.item_table_widget = ItemTableWidget(self, self.item_viewer)
        self.item_table_widget.layout().addWidget(self.item_viewer)

        self.load_resources(self._database_path)

        # Loot Generator Widget
        self.lootViewer = ItemViewer(self.system)
        self.loot_widget = TreasureHoardTab(self, self.item_viewer,
                                            self.item_table_widget)

        # Initiative list
        self.encounterWidget = EncounterWidget(self.monster_viewer)

        # bookmark
        self.bookmark_widget = BookmarkWidget(self.monster_table_widget,
                                              self.monster_viewer,
                                              self.spell_table_widget,
                                              self.spell_viewer)

        encounter_frame = QFrame()
        encounter_layout = QVBoxLayout()
        encounter_layout.addWidget(self.encounterWidget)
        encounter_layout.addWidget(self.bookmark_widget)
        encounter_frame.setLayout(encounter_layout)

        # player tab
        player_table_frame = QFrame()
        player_table_layout = QVBoxLayout()
        encounter_button_layout = QHBoxLayout()
        self.add_player_button = QPushButton("Add Player")
        self.add_player_button.setSizePolicy(QSizePolicy.Minimum,
                                             QSizePolicy.Minimum)
        self.playerWidget = PlayerTable()
        encounter_button_layout.addWidget(self.add_player_button)
        encounter_button_layout.addStretch(0)
        player_table_layout.addWidget(self.playerWidget)
        player_table_layout.addLayout(encounter_button_layout)
        player_table_frame.setLayout(player_table_layout)

        self.monster_viewer_bar = QFrame()
        self.monster_viewer_bar.setContentsMargins(0, 0, 0, 0)

        monster_viewer_frame_layout.addWidget(self.monster_viewer)
        monster_viewer_frame_layout.addWidget(monster_button_bar)
        monster_viewer_frame_layout.addWidget(self.monster_viewer_bar)
        monster_viewer_frame_layout.setStretch(3, 1)
        monster_viewer_frame_layout.setStretch(0, 2)

        middle_frame_layout = QVBoxLayout()
        self.middle_frame = QTabWidget()
        self.middle_frame.setLayout(middle_frame_layout)
        self.middle_frame.setContentsMargins(0, 0, 0, 0)

        layout = QHBoxLayout()
        monster_plaintext_button = QPushButton("Copy plaintext to clipboard")
        monster_plaintext_button.clicked.connect(
            self.copy_plaintext_monster_to_clipboard)
        layout.addWidget(monster_plaintext_button)
        self.monster_viewer_bar.setLayout(layout)

        # middle_frame_layout.addWidget(self.spell_viewer)
        middle_frame_layout.setStretch(0, 2)
        middle_frame_layout.setContentsMargins(0, 0, 0, 0)

        # Leftmost tab
        self.tab_widget.addTab(encounter_frame, "Encounter")
        self.tab_widget.addTab(player_table_frame, "Players")
        self.tab_widget.addTab(self.loot_widget, "Loot")

        # Center tab
        self.middle_frame.addTab(self.monster_table_widget, "Monster")
        self.middle_frame.addTab(self.spell_table_widget, "Spell")
        self.middle_frame.addTab(self.item_table_widget, "Item")
        self.middle_frame.addTab(self.text_box, "Text Box")

        # Right frame
        self.right_tab = QTabWidget()
        self.right_tab.addTab(self.monster_viewer_frame, "Monster")
        self.right_tab.addTab(self.spell_viewer, "Spell")
        self.right_tab.addTab(self.item_viewer, "Item")

        self.window_layout.addWidget(self.tab_widget)
        self.window_layout.addWidget(self.middle_frame)
        self.window_layout.addWidget(self.right_tab)
        self._set_widget_stretch(GlobalParameters.MAIN_TOOL_POSITION,
                                 GlobalParameters.MAIN_TOOL_STRETCH)
        self._set_widget_stretch(GlobalParameters.MIDDLE_FRAME_POSITION, 0)
        self._set_widget_stretch(GlobalParameters.RIGHT_FRAME_POSITION,
                                 GlobalParameters.RIGHT_FRAME_STRETCH)

        self.monster_viewer_bar.setHidden(True)

        self.window_frame.setLayout(self.window_layout)

    def _setup_menu(self):
        ### Menubar
        menu = self.menuBar()
        version = menu.addMenu("Version")
        # button_3_5 = QAction("3.5 Edition", self)
        # button_3_5.setStatusTip("3.5 Edition")
        # version.addAction(button_3_5)
        button_5 = QAction("5th Edition", self)
        button_5.setStatusTip("5th Edition")
        version.addAction(button_5)
        button_5.triggered.connect(lambda: self.change_version(System.DnD5e))
        button_sw5e = QAction("SW 5th Edition", self)
        button_sw5e.setStatusTip("SW 5th Edition")
        version.addAction(button_sw5e)
        button_sw5e.triggered.connect(lambda: self.change_version(System.SW5e))
        # button_3_5.triggered.connect(lambda: self.change_version("3.5"))

        experimental = menu.addMenu("Experimental")
        button_plain_text = QAction("Plain text monsters",
                                    self,
                                    checkable=True)
        button_plain_text.setStatusTip("Plain text monsters")
        button_plain_text.triggered.connect(self.toggle_monster_bar)
        # raise_exception = QAction("Raise Exception", self)
        # raise_exception.setStatusTip("Raise an Exception")
        # raise_exception.triggered.connect(self.raise_exception)
        self.edit_entries_action = QAction("Edit Entries",
                                           self,
                                           checkable=True)
        self.edit_entries_action.setStatusTip("Enable edit data entries")
        # development
        self.edit_entries_action.setChecked(True)  # default ON
        self.enable_edit_data_entries()
        ##
        self.edit_entries_action.triggered.connect(
            self.enable_edit_data_entries)

        experimental.addAction(button_plain_text)
        experimental.addAction(self.edit_entries_action)
        # experimental.addAction(raise_exception)

        self.window_frame.setLayout(self.window_layout)

    # def raise_exception(self):
    #     raise EnvironmentError("Forced an exception")

    def enable_edit_data_entries(self):
        cond = self.edit_entries_action.isChecked()
        self.monster_table_widget.EDITABLE = False  # not for monsters
        self.spell_table_widget.EDITABLE = cond
        self.item_table_widget.EDITABLE = cond

    def bind_signals(self):
        self.encounterWidget.add_players_button.clicked.connect(
            self.addPlayersToCombat)
        self.encounterWidget.sort_init_button.clicked.connect(
            self.sort_init_handle)
        self.encounterWidget.roll_init_button.clicked.connect(
            self.roll_init_handle)
        self.encounterWidget.save_encounter_button.clicked.connect(
            self.encounterWidget.save)
        self.encounterWidget.load_encounter_button.clicked.connect(
            lambda: self.encounterWidget.load(self.monster_table_widget))
        self.encounterWidget.clear_encounter_button.clicked.connect(
            self.clear_encounter_handle)
        self.bookmark_widget.clear_bookmark_button.clicked.connect(
            self.clear_bookmark_handle)
        self.bookmark_widget.toggle_bookmark_button.clicked.connect(
            self.toggle_bookmark_handle)

        self.add_player_button.clicked.connect(self.add_player)
        sNexus.attackSignal.connect(self.attackSlot)
        sNexus.addSpellsSignal.connect(self.addSpellsToBookmark)
        sNexus.printSignal.connect(self.print)
        sNexus.addMonstersToEncounter.connect(
            self.encounterWidget.addMonsterToEncounter)
        sNexus.setWidgetStretch.connect(self._set_widget_stretch)
        sNexus.viewerSelectChanged.connect(self.viewer_select_changed)

    def _display_ui(self):
        self.setCentralWidget(self.window_frame)

    def _set_widget_stretch(self, widget, stretch):
        self.window_layout.setStretch(widget, stretch)

    def toggle_monster_bar(self):
        if self.monster_viewer_bar.isHidden():
            self.monster_viewer_bar.setHidden(False)
        else:
            self.monster_viewer_bar.setHidden(True)

    def copy_plaintext_monster_to_clipboard(self):
        pyperclip.copy(html2text.html2text(self.monster_viewer.html))

    def viewer_select_changed(self, idx):
        self.right_tab.setCurrentIndex(idx)

    def change_version(self, version):
        if self.system == version:
            return
        self.system = version
        self.clear_bookmark_handle()
        self.clear_encounter_handle()

        self.monster_table_widget.table.clear()
        self.spell_table_widget.table.clear()
        self.item_table_widget.table.clear()

        self.monster_table_widget.filter.clear_filters()

        self.load_resources(self._database_path)

    def addMonsterToBookmark(self, monster):
        row_position = self.bookmark_widget.monster_bookmark.rowCount()
        self.bookmark_widget.monster_bookmark.insertRow(row_position)
        if type(monster) == list:
            for itt, value in enumerate(monster):
                self.bookmark_widget.monster_bookmark.setItem(
                    row_position, itt, QTableWidgetItem(str(value)))
        else:
            self.bookmark_widget.monster_bookmark.setItem(
                row_position, 0, QTableWidgetItem(str(monster.name)))
            self.bookmark_widget.monster_bookmark.setItem(
                row_position, 1, QTableWidgetItem(str(monster.index)))

    def addSpellsToBookmark(self, spells):
        for spell in spells:
            _spell = self.spell_table_widget.find_entry('name', spell)
            self.add_to_bookmark_spell(_spell)

    def add_to_bookmark_spell(self, spell):
        row_position = self.bookmark_widget.spell_bookmark.rowCount()
        self.bookmark_widget.spell_bookmark.insertRow(row_position)
        if type(spell) == list:
            for itt, value in enumerate(spell):
                self.bookmark_widget.spell_bookmark.setItem(
                    row_position, itt, QTableWidgetItem(str(value)))
        elif spell is not None:
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 0, QTableWidgetItem(str(spell.name)))
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 1, QTableWidgetItem(str(spell.index)))
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 2, QTableWidgetItem(str(spell.level)))

    def load_resources(self, database_path):
        self.db = RainyDatabase(database_path, system=self.system)
        self.item_table_widget.set_entries(self.db.get_items())
        self.item_table_widget.fill_table()
        self.item_table_widget.define_filters(self.system)
        self.monster_table_widget.set_entries(self.db.get_monsters())
        self.monster_table_widget.fill_table()
        self.monster_table_widget.define_filters(self.system)
        # self.spell_table_widget.load_all("./spell", "{}/{}/Spells/".format(resource_path, self.version), spell_cls)
        self.spell_table_widget.set_entries(self.db.get_spells())
        self.spell_table_widget.fill_table()
        self.spell_table_widget.define_filters(self.system)

    def add_player(self, player=None):
        self.playerWidget.add(PlayerFrame(self.playerWidget))

    def addPlayersToCombat(self):
        encounterWidget = self.encounterWidget
        characterNames = encounterWidget.getCharacterNames()
        # Get active players

        for entry in self.playerWidget.m_widgetList:
            # character in encounter, and should be
            if entry.getCharacter().getCharName(
            ) in characterNames and entry.isEnabled():
                # print("Character in encounter, and should be")
                encounterWidget.update_character(entry.getCharacter())

            # character in encounter, but shouldn't be
            elif entry.getCharacter().getCharName(
            ) in characterNames and not entry.isEnabled():
                # print("Character in enocunter, shouldn't be")
                # print(entry.getCharacter().getCharName(), entry.isEnabled())
                encounterWidget.remove_character(entry.getCharacter())

            # character not in encounter, but should be
            elif entry.getCharacter().getCharName(
            ) not in characterNames and entry.isEnabled():
                # print("Character not in encounter, should be")
                encounterWidget.addPlayerToEncounter(entry.getCharacter())

            # character not in encounter, and shouldn't be
            else:
                pass

    def sort_init_handle(self):
        self.encounterWidget.sortInitiative()

    def roll_init_handle(self):
        self.encounterWidget.rollInitiative()

    def clear_encounter_handle(self):
        self.encounterWidget.clear()

    def clear_bookmark_handle(self):
        self.bookmark_widget.monster_bookmark.clear()
        self.bookmark_widget.monster_bookmark.setRowCount(0)
        self.bookmark_widget.spell_bookmark.clear()
        self.bookmark_widget.spell_bookmark.setRowCount(0)

    def toggle_bookmark_handle(self):
        self.bookmark_widget.toggle_hide()

    def print(self, s):
        self.middle_frame.setCurrentIndex(GlobalParameters.TEXT_BOX_INDEX)
        self.text_box.append(s)

    def print_attack(self, monster_name, attack):
        attack = attack.strip(" ")
        comp = attack.split("|")
        if attack == "":
            s = "{} used an action".format(monster_name)
        else:
            s = "{} uses {} -- ".format(monster_name, comp[0])

            if comp[1] not in [
                    "", " "
            ]:  # this means there's an attack roll and a damage roll
                attack_roll = roll_function("1d20+" + comp[1])
                s = s + "{}({}) to hit".format(attack_roll,
                                               attack_roll - int(comp[1]))
            damage_roll = roll_function(comp[2])
            if damage_roll is not None:
                if type(damage_roll) is list:
                    halved = [max(1, int(dr / 2)) for dr in damage_roll]
                else:
                    # print("\trainydm - print_attack: \"{}\"".format(damage_roll))
                    halved = max(1, int(damage_roll / 2))
                s = s + " -- for {} ({} halved)".format(
                    str(damage_roll), str(halved))
        self.print(s)

    def extract_and_add_spellbook(self, monster):
        spells = monster.extract_spellbook()
        if spells is not None:
            for spell in spells:
                spell_entry = self.spell_table_widget.find_entry("name", spell)
                if spell_entry is not None:
                    self.add_to_bookmark_spell(spell_entry)
                else:
                    print("Failed to locate spell for", monster.name,
                          "with spellname {}".format(spell))

    def load_meta(self):
        if not os.path.exists("metadata/"):
            os.mkdir("metadata")

        meta_path = os.path.join("metadata", "meta.txt")
        if os.path.exists(meta_path):
            with open(meta_path, "r") as f:
                meta_dict = json.load(f)
                self.system = System.from_plaintext(meta_dict['system'])
                self.settings = meta_dict['settings']
        else:
            self.system = System.DnD5e

    def load_session(self):
        if not os.path.exists("metadata/"):
            os.mkdir("metadata")
        if os.path.exists("metadata/session.txt"):
            with open("metadata/session.txt", "r") as f:
                meta_dict = eval(f.read())
                for monster_tuple in meta_dict['bookmark_meta']:
                    self.addMonsterToBookmark(monster_tuple)

                for player in meta_dict['player_meta']:
                    player_dict = json.loads(player)
                    self.playerWidget.add(
                        PlayerFrame(self.playerWidget,
                                    charName=player_dict["characterName"],
                                    playerName=player_dict["playerName"],
                                    init=player_dict["initiative"],
                                    perception=player_dict["perception"],
                                    insight=player_dict["insight"],
                                    isEnabled=player_dict["isEnabled"]))

                for entry in meta_dict['initiative_meta']:
                    entry_dict = json.loads(entry)
                    if entry_dict["type"] == "Monster":
                        self.encounterWidget.add(
                            MonsterWidget(self.monster_table_widget.find_entry(
                                "name", entry_dict["monster"]),
                                          self.encounterWidget,
                                          viewer=self.monster_viewer,
                                          init=entry_dict["init"],
                                          hp=entry_dict["hp"]))
                    elif entry_dict["type"] == "Player":
                        self.encounterWidget.add(
                            PlayerWidget(
                                self.encounterWidget,
                                self.playerWidget.findCharacterByName(
                                    entry_dict["name"])))

    def closeEvent(self, event):
        bookmark_meta = self.bookmark_widget.monster_bookmark.jsonlify()
        initiative_meta = self.encounterWidget.jsonlify()
        player_meta = self.playerWidget.jsonlify()

        with open("metadata/session.txt", "w") as f:
            json.dump(
                dict(bookmark_meta=bookmark_meta,
                     initiative_meta=initiative_meta,
                     player_meta=player_meta), f)

        with open("metadata/meta.txt", "w") as f:
            json.dump(
                dict(system=System.to_plaintext(self.system),
                     settings=self.settings), f)

    # SLOTS
    @pyqtSlot(str, str)
    def attackSlot(self, name, attack):
        self.print_attack(name, attack)
        self.middle_frame.setCurrentIndex(GlobalParameters.TEXT_BOX_INDEX)

    def excepthook(self, type, value, tb):
        box = QMessageBox()
        box.setWindowTitle("Oof!")
        box.setText("RainyDM has crashed!")
        box.setIcon(QMessageBox.Critical)
        details = "".join(traceback.format_exception(type, value, tb))
        box.setDetailedText(details)

        spacer = QSpacerItem(500, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
        box.layout().addItem(spacer,
                             box.layout().rowCount(), 0, 1,
                             box.layout().columnCount())

        box.exec_()
        old_excepthook(type, value, tb)
        self.close()

    def validate_views(self):
        for spell in self.db.get_spells().values():
            self.spell_viewer.draw_view(spell)
        for monster in self.db.get_monsters().values():
            self.monster_viewer.draw_view(monster)
        for item in self.db.get_items().values():
            self.item_viewer.draw_view(item)
Ejemplo n.º 11
0
class LootWidget(EntryWidget):
    def __init__(self, item, item_list, viewer):
        super().__init__(item, viewer)
        self.setObjectName("LootWidget")
        self.item = item
        self.item_list = item_list
        self.viewer = viewer

        name_frame = QFrame()
        name_frame.setContentsMargins(0, 0, 0, 0)
        name_frame.setLayout(QHBoxLayout())
        self.name_label = NameLabel(item.name)
        self.name_label.setObjectName("LootWidget_name")
        name_frame.layout().addWidget(self.name_label)
        name_frame.layout().addStretch(1)

        self.reroll_button = RerollButton()
        self.reroll_button.clicked.connect(self.reroll_item)

        self.button_bar = QFrame()
        self.button_bar.setContentsMargins(0, 0, 0, 0)
        self.button_bar.setLayout(QHBoxLayout())

        self.button_bar.setHidden(True)
        self.type_dropdown = QComboBox()
        self.type_dropdown.addItem("Any")
        self.type_dropdown.addItem("Weapon")
        self.type_dropdown.addItem("Armor")
        self.type_dropdown.addItems(self.item_list.unique_attr("type"))
        if self.item.type in ["Staff", "Melee", "Ranged", "Rod"]:
            self.type_dropdown.setCurrentText("Weapon")
        elif self.item.type in ["Light Armor, Medium Armor, Heavy Armor"]:
            self.type_dropdown.setCurrentText("Armor")
        else:
            self.type_dropdown.setCurrentText(self.item.type)

        self.rarity_dropdown = QComboBox()
        self.rarity_dropdown.addItems(self.item_list.unique_attr("rarity"))
        self.rarity_dropdown.setCurrentText(self.item.rarity)

        self.button_bar.layout().addWidget(self.type_dropdown)
        self.button_bar.layout().addWidget(self.rarity_dropdown)
        self.button_bar.layout().addStretch(1)
        self.button_bar.layout().addWidget(self.reroll_button)

        self.setLayout(QVBoxLayout())
        QSpacerItem(50, 10)
        self.layout().setContentsMargins(20, 5, 10, 10)
        self.layout().addWidget(name_frame)
        self.layout().addWidget(self.button_bar)
        self.setFrameShape(QFrame.Box)

    def reroll_item(self):
        item_dict = dict({
            "type": self.type_dropdown.currentText(),
            "rarity": self.rarity_dropdown.currentText()
        })
        subset = self.item_list.subset(item_dict)
        if len(subset) is 0:
            sNexus.printSignal.emit(
                "There is no {} {} in the database.".format(
                    item_dict["rarity"], item_dict["type"]))
            return
        self.item = random.choice(subset)
        self.name_label.setText(self.item.name)
        self.viewer.draw_view(self.item)

    def mousePressEvent(self, a0: QMouseEvent):
        if self.property('clicked'):  # already clicked
            self.deselect()
        else:
            sNexus.treasureHoardDeselectSignal.emit()
            self.select()
            self.viewer.draw_view(self.item)
        self.redraw()
Ejemplo n.º 12
0
class UpdaterDialog(JDialog):
    def __init__(self):
        super().__init__()

        self.setInitialSize(800, 800)
        self.initUi()
        self.setActions()

    def initUi(self):
        self.setWindowTitle("Update Jinn")

        self.windowLayout = QVBoxLayout(self)
        self.topBar = QHBoxLayout()
        self.middleLayout = QHBoxLayout()
        self.advancedOptionsLayout = QVBoxLayout()
        self.advancedButtonLayout = QHBoxLayout()
        self.buttonBtm = QHBoxLayout()

        self.advancedOptionsFrame = QFrame()
        self.advancedOptionsFrame.setHidden(True)

        self.updateLog = JTextEdit(
            "Use this on your work PC. Press 'Update' to copy the Jinn code on this USB stick to "
            "this PC. The old code will be saved incase it is needed.")
        self.updateLog.setReadOnly(True)

        self.btnAdvancedOptions = JPushButton("Show advanced options")
        self.btnLocateJinn = JPushButton("Locate Jinn installation")
        self.btnUpdate = JPushButton("Update")
        self.btnCreateShortcut = JPushButton("Create desktop shortcut")
        self.btnCancel = JCancelButton("Cancel")

        self.codeDir = DirectorySelector(caption="Select Code directory")
        self.codeDir.leDirname.setText("C:/Jinn/Code")

        self.advancedOptionsLayout.addWidget(self.codeDir)
        self.advancedButtonLayout.addWidget(self.btnCreateShortcut)
        self.advancedButtonLayout.addWidget(self.btnLocateJinn)
        self.advancedOptionsLayout.addLayout(self.advancedButtonLayout)
        self.advancedOptionsFrame.setLayout(self.advancedOptionsLayout)

        self.buttonBtm.addWidget(self.btnUpdate)
        self.buttonBtm.addWidget(self.btnCancel)

        self.topBar.addWidget(self.btnAdvancedOptions)
        self.middleLayout.addWidget(self.advancedOptionsFrame)

        self.windowLayout.addLayout(self.topBar)

        self.windowLayout.addLayout(self.middleLayout)
        self.windowLayout.addStretch()
        self.windowLayout.addWidget(self.updateLog)
        self.windowLayout.addLayout(self.buttonBtm)

    def setActions(self):
        self.btnLocateJinn.clicked.connect(self.locateCodeFolder)
        self.btnUpdate.clicked.connect(self.updateCode)
        self.btnCreateShortcut.clicked.connect(self.createShortcut)
        self.btnCancel.clicked.connect(self.reject)
        self.btnAdvancedOptions.clicked.connect(self.showAdvancedOptions)

    def showAdvancedOptions(self):
        if self.advancedOptionsFrame.isHidden():
            self.advancedOptionsFrame.show()
            self.btnAdvancedOptions.setText("Hide advanced options")
        else:
            self.advancedOptionsFrame.hide()
            self.btnAdvancedOptions.setText("Show advanced options")

    def createShortcut(self):
        path = self.codeDir.leDirname.text()
        try:
            print("Attempting shortcut to path variable 'python3'")
            createShortcut(path, 'python3')
        except:
            print("'python3' failed using 'python'")
            createShortcut(path, 'python')

    def locateCodeFolder(self):
        root = "C:\\"
        pattern = '..\Jinn\Code\home.py'
        # Want to find all Jinn\Code paths
        # Performs a walk through operating system paths and looks for the match "Jinn\Code"
        # Potential for failure if user has multiple Jinns for some reason
        try:
            possibleDirs = []
            for path, dirs, files in os.walk(os.path.abspath(root)):
                if pathlib.PurePath(path).match('*/Jinn/Code'):
                    possibleDirs.append(path)

            print(possibleDirs)
        except Exception as ex:
            raise ex

        if len(possibleDirs) > 1:
            multipleJinnDialog = MultipleJinnDialog(possibleDirs)
            with multipleJinnDialog.delayedDeleteOnClose():
                multipleJinnDialog.exec()
                path = multipleJinnDialog.getPath()
        else:
            path = possibleDirs[0]

        self.codeDir.leDirname.setText(str(path))

    def updateCode(self):
        updateVariables = UpdateVariables()
        # Rename old code directory and then move new code and rename it
        codeDirPath = self.codeDir.leDirname.text()
        codeDirPath = os.path.abspath(codeDirPath)
        oldCodeFolder = updateVariables.getOldCodeDirWithDateTime()

        jinnDirPath = os.path.join(codeDirPath, "..")

        codeDirAlreadyExists = os.path.exists(codeDirPath)
        if codeDirAlreadyExists:
            updateJTextEdit(
                self.updateLog,
                "Rename existing \"{}\" directory to \"{}\", and ".format(
                    codeDirPath, oldCodeFolder))
        updateJTextEdit(
            self.updateLog,
            "Rename \"{}\" to \"{}\"\n".format(codeDirPath,
                                               updateVariables.codeDir))
        # rename existing `Code` directory to `OldCode`
        if codeDirAlreadyExists:
            oldCodeDirPath = os.path.join(jinnDirPath, oldCodeFolder)
            updateJTextEdit(
                self.updateLog,
                "Renaming \"{}\" to \"{}\"\n".format(codeDirPath,
                                                     oldCodeDirPath))
            os.rename(codeDirPath, oldCodeDirPath)
            # rename directory from extracted zip file to `Code`
            updateJTextEdit(
                self.updateLog,
                "Renaming \"{}\" to \"{}\"\n".format(codeDirPath, codeDirPath))
        # Old code folder is renamed. Now we need to move the newCode and rename it
        # New code is in UpdateVariables.getPath(newCode), unfortunately there is an unknown folder name here from Git
        # First work out the Git hub zip extracted name
        gitFolder = getImmediateSubdirectories(
            updateVariables.getPath(updateVariables.codeDir))[0]
        print(gitFolder)
        newCode = os.path.join(
            updateVariables.getPath(updateVariables.codeDir), gitFolder)
        try:
            os.chdir(newCode)
            shutil.copytree(newCode, codeDirPath)
            dialog = InfoMsgBox(
                "Update Finished",
                "Update finished with no faults. Code has been updated to the USB "
                "copy", "Finished")
            dialog.exec()
        except Exception as e:
            raise e
Ejemplo n.º 13
0
class Tablewidget(QTableWidget):
    def __init__(self,parent):
        super().__init__()
        self.setParent(parent)
        self.frontandnextFlag = []
        self.pat = re.compile(r"<font style='background-color:red;'>(.*?)</font>")
        self.searchbox = QFrame(self)
        self.searchbox.setGeometry(10,50,330,30)
        # self.searchbox.setFrameRect(QRect(10,10,10,10))
        self.searchbox.setStyleSheet("border-radius:2px;background-color:rgb(200,200,200)")
        self.searchbox.setHidden(True)

        self.searchtextbox = QLineEdit(self.searchbox)
        self.searchtextbox.setGeometry(0,0,210,30)
        self.searchtextbox.setStyleSheet("border:none")

        #文本显示框
        self.textwindow = QTextEdit(self)
        self.textwindow.setGeometry(0,0, self.width() - 100, self.height() - 100)
        self.textwindow.setVisible(False)
        self.textwindow_text = None
        #搜索窗口
        self.search = QPushButton("", self.searchbox)
        self.search.setIcon(QIcon("./pic/search.ico"))
        self.search.setGeometry(210, 0, 30, 30)
        self.search.setStyleSheet("border:none")
        self.search.clicked.connect(self.searchdata)

        self.front  =   QPushButton("",self.searchbox)
        self.front.setIcon(QIcon("./pic/front.ico"))
        self.front.setGeometry(240,0,30,30)
        self.front.setStyleSheet("border:none")
        self.front.clicked.connect(lambda: self.frontandnextpress(-1))

        self.next   =   QPushButton("", self.searchbox)
        self.next.setIcon(QIcon("./pic/next.ico"))
        self.next.setGeometry(270,0,30,30)
        self.next.setStyleSheet("border:none")
        self.next.clicked.connect(lambda: self.frontandnextpress(1))

        self.clo = QPushButton("", self.searchbox)
        self.clo.setIcon(QIcon("./pic/close.ico"))
        self.clo.setGeometry(300, 0, 30, 30)
        self.clo.setStyleSheet("border:none")
        self.clo.clicked.connect(self.searchboxclo)

        self.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        # 设置垂直方向滑块像素移动
        self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        # 设置水平方向滑块像素移动
        self.setEditTriggers(QAbstractItemView.NoEditTriggers | QAbstractItemView.DoubleClicked)
        # 设置表格不可编辑
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        # 设置启用右键策略

    def showdata(self, data):
        self.setRowCount(len(data[0]) - 1)
        self.setColumnCount(len(data))
        for i in range(0, len(data)):  # 总列数,显示所有数据
            self.setHorizontalHeaderItem(i, QTableWidgetItem(data[i][0]))
            for j in range(1, len(data[0])):  # 总数据行数
                ss = QTableWidgetItem(data[i][j])
                self.setItem(j - 1, i, ss)
                ss.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)  # 设置所有单元格对齐方式

    def keyPressEvent(self, QkeyEvent):
        if QkeyEvent.key() == Qt.Key_F:
            if QApplication.keyboardModifiers() == Qt.ControlModifier:
                self.searchbox.show()
                self.searchbox.setHidden(False)
                self.searchtextbox.setFocus()
        elif QkeyEvent.key() == Qt.Key_Escape:
            if self.searchbox.isHidden():
                self.textwindow.setHidden(True)
            else:
                self.searchbox.setHidden(True)
                self.textwindow.setHidden(True)
        elif QkeyEvent.key() == Qt.Key_F2:
            self.textwindow.setGeometry(0,0, self.width() - 100, self.height() - 100)
            detail = JSONEncoder().encode(self.textwindow_text)
            detail = json.loads(detail)
            self.textwindow.setText(json.dumps(detail, indent=5, ensure_ascii=False))
            self.textwindow.setHidden(False)


    def searchdata(self):
        self.frontandnextFlag = []
        global  pressFlag
        pressFlag = -1
        findtext = ""
        # if self.searchtextbox.text() == "":
        #     return
        # else:
        try:
            findtext = self.searchtextbox.text().split()[0]
        except IndexError:
            findtext = "$@##$$@!!"  #如果为空,标记特殊寻找字符,找不到将Qlabel替换为字符串
        for a in range(self.rowCount()):
            for b in range(self.columnCount()):
                if isinstance(type(self.item(a,b)),type(None)) and isinstance(type(self.cellWidget(a,b)),type(None)):
                    pass
                else:

                    if isinstance(type(self.cellWidget(a,b)),type(QLabel)):
                        if "<font style" in self.cellWidget(a,b).text():
                            d = self.cancelCssFormat(self.cellWidget(a,b).text())
                            celltext = self.cellWidget(a,b).text().replace(
                                "<font style='background-color:red;'>{}</font>".format(d),
                                d)
                            if findtext in celltext:
                                self.cellWidget(a,b).setText(self.setStrkeyColor(celltext,findtext))
                                self.frontandnextFlag.append([a,b])
                            else:
                                self.removeCellWidget(a,b)
                                celltext = celltext.replace("<br>", "\n")
                                self.setItem(a,b,QTableWidgetItem(celltext))
                        else:
                            celltext = self.cellWidget(a,b).text()
                            celltext = celltext.replace("<br>", "\n")
                            self.removeCellWidget(a,b)
                            self.setItem(a,b,QTableWidgetItem(celltext))
                    elif isinstance(type(self.item(a, b)), type(QTableWidgetItem)):
                        if findtext in self.item(a,b).text():
                            celltext = self.item(a,b).text().replace("\n","<br>")
                            celltext = self.setStrkeyColor(celltext,findtext)
                            lab = QLabel(celltext,self)
                            self.setCellWidget(a,b,lab)
                            self.setItem(a,b,QTableWidgetItem(""))
                            self.frontandnextFlag.append([a, b])
                            # print(a,b,type(self.cellWidget(a,b)),type(self.item(a,b)),"\n",lab.text())
                        else:
                            pass
                    else:
                        pass

    def setStrkeyColor(self,strdata,key):
        needstr = strdata.replace(key,"<font style='background-color:red;'>{}</font>".format(key))
        return needstr

    def cancelCssFormat(self,strdata):
        return self.pat.search(strdata).group(1)

    def stecellbackcolor(self,a,b,color=QColor(200,200,200)):
        self.item(a,b).setBackground(QColor(color))

    def searchboxclo(self):
        self.searchtextbox.clear()
        self.searchbox.close()

    def frontandnextpress(self,k):
        global pressFlag
        pressFlag += k
        if pressFlag >= 0 and pressFlag < len(self.frontandnextFlag):
            self.setCurrentCell(self.frontandnextFlag[pressFlag][0],self.frontandnextFlag[pressFlag][1])
        else:
            pressFlag = -1
Ejemplo n.º 14
0
    def initUI(self):
        
        browseButton = QPushButton("Browse")
        browseButton.setAutoFillBackground(True)
        browseButton.setMaximumHeight(43)
        saveButton = QPushButton("Browse")
        sortButton = QPushButton("Sort")
        cancelButton = QPushButton("Cancel")
        prefButton = QPushButton("Advanced Options")
        textbox_in = QLineEdit()
        textbox_in.setTextMargins(5, 5, 6, 6)
        textbox_out = QLineEdit()
        textbox_out.setTextMargins(5, 5, 6, 6)
        cat1_num = QLineEdit()
        cat2_num = QLineEdit()
        cat3_num = QLineEdit()
        
        popSlider= QSlider(orientation = Qt.Horizontal)
        popSlider.setTickInterval(20)
        popSlider.setTickPosition(QSlider.TicksBelow)
        popReadout = QLabel('100')
        def updatePopulationSize(n): 
            popReadout.setText(str(n))
        popSlider.valueChanged[int].connect(updatePopulationSize)
        popSlider.setMaximum(500)
        popSlider.setMinimum(50)
        popSlider.setValue(100)
        
        rptSlider= QSlider(orientation = Qt.Horizontal)
        rptSlider.setTickInterval(10)
        rptSlider.setTickPosition(QSlider.TicksBelow)
        rptReadout = QLabel('50')
        def updateRpts(n): 
            rptReadout.setText(str(n))
        rptSlider.valueChanged[int].connect(updateRpts)
        rptSlider.setMaximum(200)
        rptSlider.setMinimum(1)
        rptSlider.setValue(50)
        
        iterSlider= QSlider(orientation = Qt.Horizontal)
        iterSlider.setTickInterval(30)
        iterSlider.setTickPosition(QSlider.TicksBelow)
        iterReadout = QLabel('50')
        def updateIterations(n): 
            iterReadout.setText(str(n))
        iterSlider.valueChanged[int].connect(updateIterations)
        iterSlider.setMaximum(500)
        iterSlider.setMinimum(10)
        iterSlider.setValue(50)
        
        # Set window background color
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), QColor(50, 40, 60))
                
        brush = QBrush(QColor(200, 200, 200))
        p.setBrush(QPalette.Active, QPalette.WindowText, brush)
        
        brush = QBrush(QColor(0, 100, 0))
        brush.setStyle(Qt.SolidPattern)
        p.setBrush(QPalette.Inactive, QPalette.Button, brush)
        self.setPalette(p)
        
        def selectFile():     
            textbox_in.setText(QFileDialog.getOpenFileName()[0])
            
        def saveFile():     
            textbox_out.setText(QFileDialog.getSaveFileName()[0])        
            
        def runSort():
            input_file = textbox_in.text()
            output_file = textbox_out.text()
            n1 = int(cat1_num.text())
            n2 = int(cat2_num.text())
            n3 = int(cat3_num.text())
            section_counts = [n1,n2,n3]
            
            f = open(input_file, "r")
            lines = f.readlines()
            if sum(section_counts) != len(lines[0].split(',')[5:]):
                print('category counts do not sum up to total options from input file')
                return
            paper_assign(str(input_file), str(output_file), section_counts,
                         population_size=int(popReadout.text()), 
                         num_iterations=int(iterReadout.text()),
                         repeat_all=int(rptReadout.text()))
                
        def showPrefs():
            prefFrame.setHidden(not prefFrame.isHidden())
            self.setFixedSize(self.sizeHint())

        browseButton.clicked.connect(selectFile)
        saveButton.clicked.connect(saveFile)
        sortButton.clicked.connect(runSort)
        prefButton.clicked.connect(showPrefs)
        hboxinst = QHBoxLayout()
        hboxinst.addStretch(2)
        hboxinst.addWidget(QLabel('Number of papers in each category (in order):'))
        hboxinst.addStretch(8)       

        hcatbox1 = QHBoxLayout()
        hcatbox1.addStretch(2)       
        hcatbox1.addWidget(QLabel('1st: '))
        hcatbox1.addWidget(cat1_num,2)
        hcatbox1.addStretch(8)       
        
        hcatbox2 = QHBoxLayout()
        hcatbox2.addStretch(2)       
        hcatbox2.addWidget(QLabel('2nd:'))
        hcatbox2.addWidget(cat2_num,2)
        hcatbox2.addStretch(8)       
        
        hcatbox3 = QHBoxLayout()
        hcatbox3.addStretch(2)       
        hcatbox3.addWidget(QLabel('3rd: '))
        hcatbox3.addWidget(cat3_num,2)
        hcatbox3.addStretch(8)       

        hbox = QHBoxLayout()
        hbox.addWidget(QLabel('Input file:'))
        hbox.addWidget(browseButton,1)
        hbox.addWidget(textbox_in, 10)
        
        hbox1 = QHBoxLayout()
        hbox1.addWidget(QLabel('Output file:'))
        hbox1.addWidget(saveButton,1)
        hbox1.addWidget(textbox_out, 10)
        hbox1.addWidget(sortButton, 2)
   
        hbox2 = QHBoxLayout()
        hbox2.addWidget(QLabel('Population size:'))
        hbox2.addWidget(popSlider)
        hbox2.addWidget(popReadout)
        
        hbox3 = QHBoxLayout()
        hbox3.addWidget(QLabel('Number of iterations:'))
        hbox3.addWidget(iterSlider)
        hbox3.addWidget(iterReadout)
        
        hbox4 = QHBoxLayout()
        hbox4.addWidget(QLabel('Number of repeats:'))
        hbox4.addWidget(rptSlider)
        hbox4.addWidget(rptReadout)
        
      
        vbox1 = QVBoxLayout()
        vbox1.addLayout(hboxinst)
        vbox1.addLayout(hcatbox1)
        vbox1.addLayout(hcatbox2)    
        vbox1.addLayout(hcatbox3)    
        vbox1.addLayout(hbox)    
        vbox1.addLayout(hbox1)   
        vbox1.addWidget(prefButton)
        
        vbox2 = QVBoxLayout()
        vbox2.addLayout(hbox2)  
        vbox2.addLayout(hbox3)  
        vbox2.addLayout(hbox4)  
        prefFrame = QFrame()
        prefFrame.setLayout(vbox2)
        
        vbox = QVBoxLayout()
        vbox.addLayout(vbox1)
        vbox.addWidget(prefFrame)

        prefFrame.setHidden(1)
        self.setLayout(vbox)
        self.setGeometry(300, 300, 300, 220)
        self.setWindowTitle('HKT Paper Sorting')
        self.setWindowIcon(QIcon('sort-hat.ico'))        
        self.show()