class ByteBufferWidget(QWidget): on_data_selected = pyqtSignal(QObject) def __init__(self): super().__init__() self.initUI() def initUI(self): #toolbar = QToolBar() #self.splitIntoPacketsAction = toolbar.addAction("Split into packets") #self.splitIntoPacketsAction.triggered.connect(self.splitIntoPackets) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setLayout(layout) self.tabWidget = QTabWidget() self.tabWidget.setContentsMargins(0, 0, 0, 0) self.tabWidget.setDocumentMode(True) layout.addWidget(self.tabWidget) self.textbox = HexView2() self.textbox.on_data_selected.connect(self.on_data_selected.emit) self.textbox.onNewSubflowCategory.connect(self.newSubflowCategory) self.textbox.formatInfoUpdated.connect(self.onFormatInfoUpdated) self.tabWidget.addTab(self.textbox, "Raw buffer") #layout.addWidget(toolbar) def setContents(self, bufObj): self.bufferObject = bufObj self.setWindowTitle(str(bufObj)) self.textbox.setBuffer(bufObj) self.bufferObject.on_new_data.connect(self.onNewData) def onFormatInfoUpdated(self): self.tabWidget.clear() self.tabWidget.addTab(self.textbox, "Raw buffer") def newSubflowCategory(self, category, parse_context): for i in range(self.tabWidget.count()): if self.tabWidget.tabText(i) == category: break widget = PacketListWidget() widget.setContents(parse_context.subflow_categories[category]) self.tabWidget.addTab(widget, category) widget.on_data_selected.connect(self.on_data_selected.emit) def onNewData(self): #self.textbox.showHex(bufObj.buffer) self.textbox.redraw() def splitIntoPackets(self): pass def run_ndis(self): pass
def _add_widgets(self): layout = QVBoxLayout() tabs = QTabWidget() tabs.setContentsMargins(0, 0, 0, 0) tabs.addTab(TabAbout(), "&About") tabs.addTab(TabSystem(), "&System") tabs.addTab(TabFiles(), "&Files") tabs.addTab(TabMeetings(), "&Meetings") tabs.addTab(TabLog(), "&Log") layout.addWidget(tabs) self.setLayout(layout)
class SchoolManagement(QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # create widgets self.tabs = QTabWidget(self) self.students_tab = StudentsTab() self.classes_tab = ClassesTab() self.jobs_tab = JobsTab() self.assign_tab = AssignmentsTab() self.policy_tab = PolicyTab() self.expansions_tab = ExpansionsTab() self.clubs_tab = ClubsTab() self.accounting_tab = AccountingTab() self.stats_tab = StatsTab() self.exit_btn = QPushButton() # create layouts layout = QVBoxLayout(self) self.tabs.setContentsMargins(0, 0, 0, 0) # TODO: translate self.tabs.addTab(self.classes_tab, "Classes") self.tabs.addTab(self.students_tab, "Students") self.tabs.addTab(self.jobs_tab, "Jobs") self.tabs.addTab(self.assign_tab, "Teacher Assignments") self.tabs.addTab(self.policy_tab, "School Policy") self.tabs.addTab(self.expansions_tab, "Expansions") self.tabs.addTab(self.clubs_tab, "Clubs") self.tabs.addTab(self.accounting_tab, "Accounting") self.tabs.addTab(self.stats_tab, "Stats") layout.addWidget(self.tabs) layout.addWidget(self.exit_btn) fixedsize = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.exit_btn.setSizePolicy(fixedsize) # configure widgets self.tabs.setStyleSheet( "QTabWidget { background-color: rgb(25, 45, 52);}") # connect signals self.exit_btn.clicked.connect(self.parent().toggle_school_management) # TODO: check if top part of tab handle reacts to interaction self.retranslateUi() def retranslateUi(self): tra = QApplication.translate ctxt = "SchoolManagement" self.exit_btn.setText(tra(ctxt, "Exit")) for idx, name in enumerate( ("Classes", "Students", "Jobs", "Teacher Assignments", "School Policy", "Expansions", "Clubs", "Accounting", "Stats")): self.tabs.setTabText(idx, tra(ctxt, name))
class MainWindows(QWidget): ## Main class 3 tabs : 12 cameras def __init__(self): super().__init__() self.left = 100 self.top = 30 self.width = 1200 self.height = 300 self.setGeometry(self.left, self.top, self.width, self.height) self.setWindowTitle('Lolita Alignment') self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) p = pathlib.Path(__file__) sepa = os.sep self.icon = str(p.parent) + sepa + 'icons' + sepa self.setWindowIcon(QIcon(self.icon + 'LOA.png')) self.setup() self.actionButton() def setup(self): self.layout = QVBoxLayout(self) self.layout.setContentsMargins(1, 1, 1, 1) self.setContentsMargins(1, 1, 1, 1) self.tabs = QTabWidget() self.tabs.setContentsMargins(1, 1, 1, 1) self.tab0 = MULTICAM(names=['cam0', 'cam1', 'cam2', 'cam3']) self.tab1 = MULTICAM(names=['cam6', 'cam7', 'cam4', 'cam5']) # self.tab2=App4Cam() self.tabs.addTab(self.tab0, ' Lolita centers ') self.tabs.addTab(self.tab1, ' P3 & misc. ') #self.tabs.addTab(self.tab2,' P3 ') self.layout.addWidget(self.tabs) self.setLayout(self.layout) def changeTab(self): # print('tab change', 'tab is',self.tabs.currentIndex()) self.tab = [self.tab0, self.tab1] self.tab0.stopRun() self.tab1.stopRun() #self.tab2.stopRun() def actionButton(self): self.tabs.currentChanged.connect(self.changeTab) def closeEvent(self, event): event.accept()
class TabWindow(QMainWindow): def __init__(self, app, **kwargs): super().__init__(None, **kwargs) self.app = app self.pages = {} self.menubar = None self.menuList = set() self.last_index = -1 self.previous_widget_actions = set() self._setupUi() self.app.willSavePrefs.connect(self.appWillSavePrefs) def _setupActions(self): # (name, shortcut, icon, desc, func) ACTIONS = [ ( "actionToggleTabs", "", "", tr("Show tab bar"), self.toggleTabBar, ), ] createActions(ACTIONS, self) self.actionToggleTabs.setCheckable(True) self.actionToggleTabs.setChecked(True) def _setupUi(self): self.setWindowTitle(self.app.NAME) self.resize(640, 480) self.tabWidget = QTabWidget() # self.tabWidget.setTabPosition(QTabWidget.South) self.tabWidget.setContentsMargins(0, 0, 0, 0) # self.tabWidget.setTabBarAutoHide(True) # This gets rid of the annoying margin around the TabWidget: self.tabWidget.setDocumentMode(True) self._setupActions() self._setupMenu() # This should be the same as self.centralWidget.setLayout(self.verticalLayout) self.verticalLayout = QVBoxLayout(self.tabWidget) # self.verticalLayout.addWidget(self.tabWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.tabWidget.setTabsClosable(True) self.setCentralWidget(self.tabWidget) # only for QMainWindow self.tabWidget.currentChanged.connect(self.updateMenuBar) self.tabWidget.tabCloseRequested.connect(self.onTabCloseRequested) self.updateMenuBar(self.tabWidget.currentIndex()) self.restoreGeometry() def restoreGeometry(self): if self.app.prefs.mainWindowRect is not None: self.setGeometry(self.app.prefs.mainWindowRect) else: moveToScreenCenter(self) def _setupMenu(self): """Setup the menubar boiler plates which will be filled by the underlying tab's widgets whenever they are instantiated.""" self.menubar = self.menuBar( ) # QMainWindow, similar to just QMenuBar() here # self.setMenuBar(self.menubar) # already set if QMainWindow class self.menubar.setGeometry(QRect(0, 0, 100, 22)) self.menuFile = QMenu(self.menubar) self.menuFile.setTitle(tr("File")) self.menuMark = QMenu(self.menubar) self.menuMark.setTitle(tr("Mark")) self.menuActions = QMenu(self.menubar) self.menuActions.setTitle(tr("Actions")) self.menuColumns = QMenu(self.menubar) self.menuColumns.setTitle(tr("Columns")) self.menuView = QMenu(self.menubar) self.menuView.setTitle(tr("View")) self.menuHelp = QMenu(self.menubar) self.menuHelp.setTitle(tr("Help")) self.menuView.addAction(self.actionToggleTabs) self.menuView.addSeparator() self.menuList.add(self.menuFile) self.menuList.add(self.menuMark) self.menuList.add(self.menuActions) self.menuList.add(self.menuColumns) self.menuList.add(self.menuView) self.menuList.add(self.menuHelp) @pyqtSlot(int) def updateMenuBar(self, page_index=None): if page_index < 0: return current_index = self.getCurrentIndex() active_widget = self.getWidgetAtIndex(current_index) if self.last_index < 0: self.last_index = current_index self.previous_widget_actions = active_widget.specific_actions return page_type = type(active_widget).__name__ for menu in self.menuList: if menu is self.menuColumns or menu is self.menuActions or menu is self.menuMark: if not isinstance(active_widget, ResultWindow): menu.setEnabled(False) continue else: menu.setEnabled(True) for action in menu.actions(): if action not in active_widget.specific_actions: if action in self.previous_widget_actions: action.setEnabled(False) continue action.setEnabled(True) self.app.directories_dialog.actionShowResultsWindow.setEnabled( False if page_type == "ResultWindow" else self.app.resultWindow is not None) self.app.actionIgnoreList.setEnabled( True if self.app.ignoreListDialog is not None and not page_type == "IgnoreListDialog" else False) self.app.actionDirectoriesWindow.setEnabled( False if page_type == "DirectoriesDialog" else True) self.previous_widget_actions = active_widget.specific_actions self.last_index = current_index def createPage(self, cls, **kwargs): app = kwargs.get("app", self.app) page = None if cls == "DirectoriesDialog": page = DirectoriesDialog(app) elif cls == "ResultWindow": parent = kwargs.get("parent", self) page = ResultWindow(parent, app) elif cls == "IgnoreListDialog": parent = kwargs.get("parent", self) model = kwargs.get("model") page = IgnoreListDialog(parent, model) self.pages[cls] = page return page def addTab(self, page, title, switch=False): # Warning: this supposedly takes ownership of the page index = self.tabWidget.addTab(page, title) # index = self.tabWidget.insertTab(-1, page, title) if isinstance(page, DirectoriesDialog): self.tabWidget.tabBar().setTabButton(index, QTabBar.RightSide, None) if switch: self.setCurrentIndex(index) return index def showTab(self, page): index = self.indexOfWidget(page) self.setTabVisible(index, True) self.setCurrentIndex(index) def indexOfWidget(self, widget): return self.tabWidget.indexOf(widget) def setCurrentIndex(self, index): return self.tabWidget.setCurrentIndex(index) def setTabVisible(self, index, value): return self.tabWidget.setTabVisible(index, value) def removeTab(self, index): return self.tabWidget.removeTab(index) def isTabVisible(self, index): return self.tabWidget.isTabVisible(index) def getCurrentIndex(self): return self.tabWidget.currentIndex() def getWidgetAtIndex(self, index): return self.tabWidget.widget(index) def getCount(self): return self.tabWidget.count() # --- Events def appWillSavePrefs(self): # Right now this is useless since the first spawn dialog inside the # QTabWidget will assign its geometry after restoring it prefs = self.app.prefs prefs.mainWindowIsMaximized = self.isMaximized() prefs.mainWindowRect = self.geometry() def closeEvent(self, close_event): # Force closing of our tabbed widgets in reverse order so that the # directories dialog (which usually is at index 0) will be called last for index in range(self.getCount() - 1, -1, -1): self.getWidgetAtIndex(index).closeEvent(close_event) self.appWillSavePrefs() @pyqtSlot(int) def onTabCloseRequested(self, index): current_widget = self.getWidgetAtIndex(index) if isinstance(current_widget, DirectoriesDialog): # if we close this one, the application quits. Force user to use the # menu or shortcut. But this is useless if we don't have a button # set up to make a close request anyway. This check could be removed. return current_widget.close() self.setTabVisible(index, False) # self.tabWidget.widget(index).hide() self.removeTab(index) @pyqtSlot() def onDialogAccepted(self): """Remove tabbed dialog when Accepted/Done.""" widget = self.sender() index = self.indexOfWidget(widget) if index > -1: self.removeTab(index) @pyqtSlot() def toggleTabBar(self): value = self.sender().isChecked() self.actionToggleTabs.setChecked(value) self.tabWidget.tabBar().setVisible(value)
class MainWindows(QWidget): ## Main class 4 tabs : cameras def __init__(self): super().__init__() self.left = 100 self.top = 30 self.width = 1400 self.height = 1700 self.setGeometry(self.left, self.top, self.width, self.height) self.setWindowTitle('Lolita Cameras') self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) p = pathlib.Path(__file__) sepa = os.sep self.icon = str(p.parent) + sepa + 'icons' + sepa self.setWindowIcon(QIcon(self.icon + 'LOA.png')) self.setup() self.actionButton() def setup(self): self.layout = QVBoxLayout(self) self.layout.setContentsMargins(1, 1, 1, 1) self.setContentsMargins(1, 1, 1, 1) self.tabs = QTabWidget() self.tabs.setContentsMargins(1, 1, 1, 1) pathVisu = 'C:/Users/loa/Desktop/Python/camera/confCamera.ini' self.tab0 = CameraMotorLoop.CAMERAMOTOR(cam="cam2", fft='off', meas='on', affLight=False, aff='left', separate=False, multi=False, confpath=pathVisu, loop=True) self.tab1 = camera2.CAMERA(cam="cam3", fft='off', meas='on', affLight=False, aff='left', separate=False, multi=False, confpath=pathVisu) self.tab2 = camera2.CAMERA(cam="cam1", fft='off', meas='on', affLight=False, aff='left', separate=False, multi=False, confpath=pathVisu) self.tab3 = camera2.CAMERA(cam='cam4', fft='off', meas='on', affLight=False, aff='left', separate=False, multi=False, confpath=pathVisu) self.tab4 = CameraMotorLoop.CAMERAMOTOR(cam='cam5', fft='off', meas='on', affLight=False, aff='left', separate=False, multi=False, confpath=pathVisu, loop=True) # self.tab2=App4Cam() self.tabs.addTab(self.tab0, self.tab0.ccdName) self.tabs.addTab(self.tab1, self.tab1.ccdName) self.tabs.addTab(self.tab2, self.tab2.ccdName) self.tabs.addTab(self.tab3, self.tab3.ccdName) self.tabs.addTab(self.tab4, self.tab4.ccdName) #self.tabs.addTab(self.tab2,' P3 ') self.layout.addWidget(self.tabs) self.setLayout(self.layout) def changeTab(self): print('tab change', 'tab is', self.tabs.currentIndex()) # self.tab=[self.tab0,self.tab1] # self.tab0.stopRun() # self.tab1.stopRun() #self.tab2.stopRun() def actionButton(self): self.tabs.currentChanged.connect(self.changeTab) def closeEvent(self, event): # exit event.accept()
class Main(QFrame): def __init__(self, parent=None): """""" super().__init__() self.setObjectName('Main') self.parent = parent def initUI(self): self.setWindowFlags(Qt.FramelessWindowHint) # 隐藏边框 self.mainLayout = QVBoxLayout(self) # self.mainLayout.setSpacing(0) self.header = Header(self) self.mainLayout.addWidget(self.header, 20) self.contentLayout = QHBoxLayout() self.contentLayout.setContentsMargins(0, 0, 0, 0) self.contentLayout.setSpacing(0) self.navigation = Navigation(self) self.contentLayout.addWidget(self.navigation) self.contents = QTabWidget() self.contents.setContentsMargins(0, 0, 0, 0) self.contents.tabBar().hide() self.recommendMusic = RecommendMusic(self) self.musicDetailNetEase = RecommendMusicDetailNetEase(self) self.musicDetailQQ = RecommendMusicDetailQQ(self) self.searchMusic = SearchMusic(self) self.contents.addTab(self.recommendMusic, "") self.contents.addTab(self.musicDetailNetEase, "") self.contents.addTab(self.musicDetailQQ, "") self.contents.addTab(self.searchMusic, "") self.content = self.recommendMusic self.contents.setCurrentWidget(self.content) self.contentLayout.addWidget(self.contents) self.mainLayout.addLayout(self.contentLayout, 400) self.player = Player(self) self.mainLayout.addWidget(self.player, 20) self.registerSignalConnect() def registerSignalConnect(self): # 注册最小化事件 self.header.minButton.clicked.connect(self.showMinimized) # 注册最大化事件 self.header.maxButton.clicked.connect(self.showMaxiOrRevert) #注册关闭事件 self.header.closeButton.clicked.connect(self.close) # 注册导航栏事件 self.navigation.recommendList.currentRowChanged.connect( self.navigationRecommendChanged) self.navigation.recommendList.itemPressed.connect( self.navigationRecommendItemClick) self.navigation.myMusicList.currentRowChanged.connect( self.navigationmyMusicChanged) self.header.searchLineEdit.searchSignal.connect(self.showSearchMusic) def showMaxiOrRevert(self): if self.isMaximized(): self.showNormal() else: self.showMaximized() def navigationRecommendChanged(self, index): #print(index) self.navigation.myMusicList.setCurrentRow(-1) self.changeContentWidget(self.recommendMusic) def navigationRecommendItemClick(self, widgetItem): pass print(self.navigation.recommendList.currentRow()) #print(widgetItem) def navigationmyMusicChanged(self, index): self.navigation.recommendList.setCurrentRow(-1) def changeContentWidget(self, content): #self.contentLayout.replaceWidget(self.content, content) #sip.delete(self.content) #del self.content self.content = content self.contents.setCurrentWidget(self.content) def showSearchMusic(self, text): text = text.strip() if text: self.changeContentWidget(self.searchMusic) self.searchMusic.search(text)
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.create_flags() self.create_backend() self.create_shortcuts() self.build_ui() self.window_setup() self.build_dialogs() self.load_folder() self.show_window() # main app creators def create_main_components(self): # main window self.window = QFrame() self.layout = QVBoxLayout() # external windows self.folderSwitch = None def create_context(self): self.context = Context() self.context.load() def create_shortcuts(self): self.shortcutSave = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcutInfo = QShortcut(QKeySequence("F1"), self) self.shortcutMain = QShortcut(QKeySequence("F2"), self) self.shortcutSide = QShortcut(QKeySequence("F3"), self) self.shortcutTasks = QShortcut(QKeySequence("F4"), self) self.shortcutSwitch = QShortcut(QKeySequence("F5"), self) self.shortcutTheme = QShortcut(QKeySequence("F7"), self) self.shortcutMode = QShortcut(QKeySequence("F8"), self) self.shortcutSetup = QShortcut(QKeySequence("F9"), self) self.shortcutExit = QShortcut(QKeySequence("F10"), self) self.shortcutFullscreen = QShortcut(QKeySequence("F11"), self) self.shortcutHide = QShortcut(QKeySequence("Esc"), self) self.bind_shortcuts() def create_flags(self): # logic self.wasMaximized = False def create_backend(self): self.notes = Notes() ## do remove self.version = VersionInfo() ## to context self.stylist = Stylist() self.directory = Directory() self.timer = Timer(self) def create_side_components(self): self.sidenote = SideNotes(self) def create_notepad_components(self): self.notepad = Notepad(self) def create_todolist_components(self): self.todolist = ToDoList(self, Component.ToDoList) def create_status_bar(self): self.status_bar = StatusBar(self, Component.StatusBar) def build_ui(self): self.create_context() self.create_main_components() self.create_notepad_components() self.create_side_components() self.create_todolist_components() self.create_status_bar() desktop = QWidget() desktop_container = QHBoxLayout() self.side_tabs = QTabWidget() self.side_tabs.addTab(self.sidenote, "Notes") self.side_tabs.addTab(self.todolist, "Tasks") self.side_tabs.setFixedWidth(300) desktop_container.addWidget(self.notepad) # separate class desktop_container.addWidget(self.side_tabs) desktop.setLayout(desktop_container) desktop.setContentsMargins(0, 0, 0, 0) self.side_tabs.setContentsMargins(0, 0, 0, 0) self.layout.setContentsMargins(0, 0, 0, 0) desktop_container.setContentsMargins(0, 0, 0, 0) desktop_container.setSpacing(0) self.layout.addWidget(desktop) self.layout.addWidget(self.status_bar) self.window.setLayout(self.layout) self.setCentralWidget(self.window) # shortcuts actions def bind_shortcuts(self): self.shortcutSave.activated.connect(self.action_save) self.shortcutFullscreen.activated.connect( self.action_toggle_fullscreen) self.shortcutExit.activated.connect(self.action_terminate) self.shortcutMain.activated.connect(self.action_focus_notepad) self.shortcutSide.activated.connect(self.action_focus_sidenote) self.shortcutTasks.activated.connect(self.action_focus_tasks) self.shortcutSwitch.activated.connect(self.action_toggle_folder_switch) self.shortcutInfo.activated.connect(self.action_toggle_info_window) self.shortcutSetup.activated.connect( self.action_toggle_settings_window) self.shortcutHide.activated.connect(self.action_hide_dialog) self.shortcutTheme.activated.connect(self.action_switch_editor_theme) self.shortcutMode.activated.connect(self.action_switch_editor_mode) def action_save(self): saved = False saved = saved or self.notepad.save(self.context.source_folder) saved = saved or self.sidenote.save(self.context.source_folder) saved = saved or self.todolist.save(self.context.source_folder) if saved: self.status_bar.publish("Saved!") self.timer.setup() def action_toggle_fullscreen(self): if self.isFullScreen(): if self.wasMaximized: self.showNormal() self.showMaximized() else: self.showNormal() else: self.wasMaximized = self.isMaximized() self.showFullScreen() def action_terminate(self): self.save_window_position() self.action_save() self.close() def action_focus_notepad(self): self.notepad.focus() def action_focus_sidenote(self): self.side_tabs.setCurrentIndex(0) self.sidenote.focus() def action_focus_tasks(self): self.side_tabs.setCurrentIndex(1) self.todolist.focus() def action_toggle_folder_switch(self): if self.folderSwitch.isVisible(): self.folderSwitch.hide() else: self.folderSwitch.show() def action_toggle_info_window(self): self.dialog.show_dialog(ActivePanel.Info) def action_toggle_settings_window(self): self.dialog.setup(self.context) self.dialog.show_dialog(ActivePanel.Options) def action_hide_dialog(self): self.dialog.hide_dialog() def action_switch_editor_theme(self): if self.context.color_theme == EditorTheme.Dark: self.context.color_theme = EditorTheme.Light else: self.context.color_theme = EditorTheme.Dark self.set_editor_theme() def action_switch_editor_mode(self): if self.context.editor_mode == EditorMode.Focus: self.context.editor_mode = EditorMode.Normal else: self.context.editor_mode = EditorMode.Focus self.set_editor_mode() # dialogs def build_dialogs(self): self.dialogWidget = QWidget(self) self.dialog = Dialog(self.dialogWidget) self.dialog.hide() self.build_folder_switch_dialog() def build_folder_switch_dialog(self): self.folderSwitch = QWidget(self) switch = FolderSwitch(self.folderSwitch) self.resizeEvent(None) # main window settings def window_setup(self): self.setMinimumSize(800, 600) self.setWindowTitle(self.version.app_name()) self.set_icon() self.set_geometry() self.update_params() def update_params(self): self.set_editor_font() self.set_editor_theme() self.set_editor_mode() def set_editor_font(self): self.notepad.setup(self.context.text_size) self.sidenote.setup(self.context.text_size) def set_editor_theme(self): self.setStyleSheet( self.stylist.get_style_sheet(self.context.color_theme)) def set_editor_mode(self): self.notepad.setup_mode(self.context) def set_icon(self): self.setWindowIcon( QtGui.QIcon(self.directory.get_resource_dir() + 'icon.png')) def set_geometry(self): if self.context.window_left < 0 or self.context.window_top < 0: screen = QDesktopWidget().screenGeometry(-1) self.context.window_width = int(screen.width() / 3) * 2 self.context.window_height = int(screen.height() / 3) * 2 if self.context.window_width < 800: self.context.window_width = 800 if self.context.window_height < 600: self.context.window_height = 600 self.setGeometry(0, 0, self.context.window_width, self.context.window_height) self.center_window() else: if self.context.window_width < 800: self.context.window_width = 800 if self.context.window_height < 600: self.context.window_height = 600 self.setGeometry(self.context.window_left, self.context.window_top, self.context.window_width, self.context.window_height) self.move(self.context.window_left, self.context.window_top) def center_window(self): geometry = self.frameGeometry() screen = QApplication.desktop().screenNumber( QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() geometry.moveCenter(centerPoint) self.move(geometry.topLeft()) def show_window(self): if self.context.window_maximized == 1: self.showMaximized() else: self.showNormal() # def load_folder(self, folder=0): if folder != 0: self.context.source_folder = folder if self.context.is_source_local: self.notepad.load(self.context.source_folder) self.sidenote.load(self.context.source_folder) self.todolist.load(self.context.source_folder) def clear_status(self): self.status_bar.clear() def save_window_params(self): if self.isMaximized(): self.context.window_maximized = True else: self.context.window_maximized = False geometry = self.geometry() pos = self.pos() self.context.window_left = pos.x() self.context.window_top = pos.y() self.context.window_width = geometry.width() self.context.window_height = geometry.height() # events def resizeEvent(self, event): self.notepad.refresh() if not (self.folderSwitch is None): self.resize_folder_switch() self.dialog.resize() def closeEvent(self, event): self.save_window_params() self.context.store() self.action_save() event.accept() ## dragons below # switch folder { def resize_folder_switch(self): maxw = 700 maxh = 500 left_shift = int((self.width() - maxw) / 2) top_shift = int((self.height() - maxh) / 2) self.folderSwitch.setGeometry(left_shift, top_shift, maxw, maxh)
class CentralWidget(QWidget): crawledMovieInfo = None def __init__(self, config): super().__init__() self.globalConfig = config if not 'FolderView' in config.sections(): config.add_section('y') self.scrapperConfig = self.globalConfig['Scrapper'] mainLayout = QHBoxLayout() mainLayout.setContentsMargins(3, 3, 3, 3) self.fileView = FolderView(config) self.fileView.movieFound.connect(self.onFoundMovie) mainLayout.addWidget(self.fileView) self.movieTab = QTabWidget() self.movieTab.setContentsMargins(0, 0, 0, 0) self.listView = MovieListView(config, self.fileView.model, parent=self) self.listView.movieDoubleClicked.connect(self.onMovieClicked) self.movieTab.addTab(self.listView, 'List') self.infoView = MovieInfoView() self.movieTab.addTab(self.infoView, 'Detail') mainLayout.addWidget(self.movieTab) self.setLayout(mainLayout) self.initCrawlRunner() def initCrawlRunner(self): from scrapy.crawler import CrawlerRunner from scrapy.utils.log import configure_logging from scrapy.utils.project import get_project_settings configure_logging() self.runner = CrawlerRunner(get_project_settings()) self.crawler = None self.site = None self.numCids = 0 ''' def onMovieDoubleClicked(self, index): self.movieTab.setCurrentWidget(self.infoView) self.fileView.setCurrentIndex(index) ''' def onMovieClicked(self, index, doubleClicked): if doubleClicked: self.movieTab.setCurrentWidget(self.infoView) self.fileView.setCurrentIndex(index) def updateFromFile(self, files, index = None): self.infoView.clearMovieInfo(True, self.numCids > 1) if not files: return #print(files) nfo = next(filter(lambda x:x.endswith('.nfo'), files), False) if not nfo: return info = utils.nfo2dict(nfo) if index: info['path'] = self.fileView.getPath(index) else: info['path'] = self.fileView.getPath() for file in files: if file.endswith('.nfo'): continue if '-poster' in file: info['poster'] = utils.AvImage(file) elif '-fanart' in file: info['fanart'] = file #print('file set movie info') #print(info) self.infoView.setMovieInfo(info, self.numCids > 1) def checkCrop(self, info): donotcrop = [] if 'VR' in info['id'] : return False if self.scrapperConfig.get('studios_skipping_crop'): donotcrop = self.scrapperConfig['studios_skipping_crop'].split(',') #print(donotcrop) if not info.get('studio'): return False if info['studio'] in donotcrop: return False if self.scrapperConfig.get('labels_skipping_crop'): donotcrop = self.scrapperConfig['labels_skipping_crop'].split(',') if not info.get('label'): return False if info['label'] in donotcrop: return False return True def updateFromScrapy(self, info): #self.infoView.clearMovieInfo(False, True) try : info['fanart'] = info['thumb'] if self.checkCrop(info): info['poster'] = info['thumb'].cropLeft() else: info['poster'] = info['thumb'] #print('scrapy set movie info') self.infoView.setMovieInfo(info, False) except: traceback.print_exc() def onFoundMovie(self, movieinfo): if isinstance(movieinfo, list): self.updateFromFile(movieinfo) elif isinstance(movieinfo, dict): self.updateFromScrapy(movieinfo) ''' def onScrapDone(self, _): self.numCids = 0 # don't do anything related to Qt UI in scrapy signal. it doesn't work. def onSpiderClosed(self, spider): #import pprint as pp #pp.pprint(spider.movieinfo) try: self.crawledMovieInfo = spider.movieinfo except: self.crawledMovieInfo = None ''' def onSpiderClosed(self, spider): self.numCids = 0 self.listView.refresh() def onItemScraped(self, item, response, spider): if not response.meta.get('id'): return cid = response.meta['id'] #print(cid) minfo = dict(item) minfo['path'] = self.fileView.getPath(cid['idx']) if 'releasedate' in minfo: minfo['year'] = minfo['releasedate'].split('-')[0] if 'actor_thumb' in minfo: del minfo['actor_thumb'] #print(response.request.headers) if self.numCids > 1: mfiles = self.fileView.getFiles(cid['idx']) self.updateFromFile(mfiles, cid['idx']) self.updateFromScrapy(minfo) self.infoView.saveMovieInfo() else: self.updateFromScrapy(minfo) #self.onFoundMovie(minfo) def runCrawler(self, **kw): from scrapy import signals site = self.scrapperConfig.get('site', 'r18') if not self.crawler or self.site != site: self.site = site self.crawler = self.runner.create_crawler(site) self.crawler.signals.connect(self.onItemScraped, signals.item_scraped) self.crawler.signals.connect(self.onSpiderClosed, signals.spider_closed) self.runner.crawl(self.crawler, **kw) #deferd = self.runner.crawl(self.crawler, **kw) #deferd.addBoth(self.onScrapDone) def scrap(self, **kw): if kw: kw['outdir'] = self.fileView.rootPath() self.runCrawler(**kw) return selected = self.fileView.getSelectedIndexes() if len(selected) < 1: print('select movie!') return cids = [{'cid':os.path.basename(self.fileView.getPath(idx)), 'idx':idx} for idx in selected] self.numCids = len(cids) #print('num cids:', self.numCids) #print(cids, self.fileView.rootPath()) self.runCrawler(**{'cids':cids}) ''' for index in selected: path = self.fileView.getPath(index) cid = os.path.basename(path) self.runCrawler(**{'keyword':cid, 'outdir':path}) ''' def saveAll(self): self.infoView.saveMovieInfo() self.listView.refresh() def changeDir(self, path): self.fileView.folderList.changeDir(path) def upDir(self): self.fileView.folderList.upDir() def fileRenameTool(self): config = self.globalConfig['FolderView'] from rename_tool import FileRenameDialog dlg = FileRenameDialog(config.get('currdir', ''), self) dlg.exec_()
class WritePanel(QWidget): def __init__(self, parent): super().__init__() self.initUI() def initUI(self): self.centralFrame = QFrame(self) self.centralFrame.setFrameShape(QFrame.NoFrame) self.centralFrame.setFrameShadow(QFrame.Raised) self.centralFrame.setContentsMargins(0, 0, 0, 0) self.centralFrame.setStyleSheet("background: black;" "border: 1px solid gray;" "border-radius: 5px;") self.contentFrame = QFrame(self.centralFrame) self.contentFrame.setFrameShape(QFrame.NoFrame) self.contentFrame.setFrameShadow(QFrame.Raised) self.contentFrame.setContentsMargins(0, 0, 0, 0) self.contentFrame.setStyleSheet("border: none;") self.antPanelFrame = QFrame(self.contentFrame) self.antPanelFrame.setFrameShape(QFrame.NoFrame) self.antPanelFrame.setFrameShadow(QFrame.Raised) self.antPanelFrame.setContentsMargins(0, 0, 0, 0) self.antPanelFrame.setStyleSheet("border: none;") self.antPanel = ANTPanel(self.antPanelFrame, alignment=ANTPanel.ALIGN_GRID, devicesStyle=ANTPanel.LIST_BOX) self.devices = self.antPanel.devices self.profiles = self.antPanel.profiles self.dataPages = self.antPanel.dataPages self.pageMeasurements = self.antPanel.pageMeasurements self.antPanelLayout = QHBoxLayout(self.antPanelFrame) self.antPanelLayout.addWidget(self.antPanel) self.antPanelLayout.setContentsMargins(0, 0, 0, 0) self.writerFrame = QFrame(self.contentFrame) self.writerFrame.setFrameShape(QFrame.NoFrame) self.writerFrame.setFrameShadow(QFrame.Raised) self.writerFrame.setContentsMargins(10, 10, 10, 10) self.writerFrame.setStyleSheet("border: none;") self.writerPanelFrame = QFrame(self.writerFrame) self.writerPanelFrame.setFrameShape(QFrame.NoFrame) self.writerPanelFrame.setFrameShadow(QFrame.Raised) self.writerPanelFrame.setContentsMargins(0, 0, 0, 0) self.writerPanelFrame.setStyleSheet("border: none;") self.udpPanel = UdpPanel(self.writerFrame) self.csvPanel = CSVPanel(self.writerFrame) self.writerPanel = QTabWidget(self.writerFrame) self.writerPanel.addTab(self.udpPanel, 'UDP') self.writerPanel.addTab(self.csvPanel, 'CSV') self.writerPanel.setContentsMargins(10, 10, 10, 10) self.writerPanel.setStyleSheet("QTabBar::tab { " "height: 30px; " "width: 100px; " "background-color: rgb(39, 44, 54);" "font: 14px;" "border-radius: 1px;" "}" "QTabBar::tab:selected { " "border: 1px solid gray;" "}" "QTabBar::tab:hover{" "background-color: rgb(85, 170, 255);" "}" "QTabWidget::pane {" "border: 1px solid gray;" "}") self.writerPanelLayout = QHBoxLayout(self.writerPanelFrame) self.writerPanelLayout.addWidget(self.writerPanel) self.writerPanelLayout.setContentsMargins(0, 0, 0, 0) self.logPanelFrame = QFrame(self.writerFrame) self.logPanelFrame.setFrameShape(QFrame.NoFrame) self.logPanelFrame.setFrameShadow(QFrame.Raised) self.logPanelFrame.setContentsMargins(0, 0, 0, 0) self.logPanelFrame.setStyleSheet("background: rgb(15,15,15);" "border: 1px solid gray;" ) self.logPanel = QTextEdit(self.logPanelFrame) self.logPanel.setStyleSheet("border: none;") self.logPanel.setReadOnly(True) self.logPanelLayout = QHBoxLayout(self.logPanelFrame) self.logPanelLayout.addWidget(self.logPanel) self.logPanelLayout.setContentsMargins(0, 0, 0, 0) self.writerLayout = QVBoxLayout(self.writerFrame) self.writerLayout.addWidget(self.writerPanelFrame) self.writerLayout.addWidget(self.logPanelFrame) self.writerLayout.setContentsMargins(0, 0, 0, 0) self.contentLayout = QHBoxLayout(self.contentFrame) self.contentLayout.addWidget(self.antPanelFrame, stretch=1) self.contentLayout.addWidget(self.writerFrame, stretch=1) self.contentLayout.setContentsMargins(0, 0, 0, 0) self.centralLayout = QHBoxLayout(self.centralFrame) self.centralLayout.addWidget(self.contentFrame) self.centralLayout.setContentsMargins(0, 0, 0, 0) self.uiLayout = QHBoxLayout(self) self.uiLayout.addWidget(self.centralFrame) self.uiLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.uiLayout) self.setContentsMargins(0, 0, 0, 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)