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)
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())
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()
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)
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
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()
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
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)
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()
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
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
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()