class PyMultiPageWidget(QWidget): def __init__(self, parent=None): super(PyMultiPageWidget, self).__init__(parent) self.value = 0 self.bt = QPushButton('switch', self) self.bt.clicked.connect(self.switch) self.stackWidget = QStackedWidget() self.layout = QVBoxLayout() self.layout.addWidget(self.bt) self.layout.addWidget(self.stackWidget) self.setLayout(self.layout) self.resize(500, 400) def switch(self): self.value = 1 - self.value bt = QPushButton('new') if self.value: self.addPage(bt) else: self.removePage(0) @pyqtSlot(QWidget) def addPage(self, page): index = self.stackWidget.count() page.setParent(self.stackWidget) self.stackWidget.insertWidget(index, page) @pyqtSlot(int) def removePage(self, index): widget = self.stackWidget.widget(index) self.stackWidget.removeWidget(widget)
class IPFSHashExplorerStack(GalacteekTab): """ Organizes IPFSHashExplorerWidgets with a QStackedWidget """ def __init__(self, gWindow, hashRef, maxItems=16, parent=None): super(IPFSHashExplorerStack, self).__init__(gWindow) self.rootHash = hashRef self.maxItems = maxItems self.stack = QStackedWidget(self) self.exLayout = QVBoxLayout() self.exLayout.addWidget(self.stack) self.vLayout.addLayout(self.exLayout) if self.rootHash: self.viewHash(self.rootHash) def tabDestroyedPost(self): self.stack.setParent(None) self.stack.deleteLater() @property def itemsCount(self): return self.stack.count() def viewHash(self, hashRef, addClose=False, autoOpenFolders=False, parentView=None): view = IPFSHashExplorerWidget(hashRef, parent=self, addClose=addClose, showCidLabel=True, autoOpenFolders=autoOpenFolders, parentView=parentView) view.closeRequest.connect(partialEnsure(self.remove, view)) view.directoryOpenRequest.connect(lambda nView, cid: self.viewHash( cid, addClose=True, parentView=nView)) self.stack.insertWidget(self.stack.count(), view) self.stack.setCurrentWidget(view) view.reFocus() return True async def remove(self, view): try: view.cancelTasks() self.stack.removeWidget(view) except: pass async def onClose(self): for idx in range(self.stack.count()): widget = self.stack.widget(idx) await widget.cleanup() return True
class Root(QMainWindow): task_list_index = 0 task_view_index = 1 def __init__(self): super().__init__() self.model = None self.task_view = None self.initUI() def initUI(self): # self.cal = QCalendarWidget(self) # self.cal.setVerticalHeaderFormat(QCalendarWidget.NoVerticalHeader) # self.cal.setGeometry(0, 0, 250, 250) self.model = TaskModel() self.central = QStackedWidget() task_list = TaskList(self.model) task_list.open.connect(self.task_open) self.central.insertWidget(Root.task_list_index, task_list) self.task_view = TaskView(self.model) self.task_view.close.connect(self.task_view_close) self.central.insertWidget(Root.task_view_index, self.task_view) self.central.setCurrentIndex(Root.task_list_index) self.setCentralWidget(self.central) # QDialog flags: # Qt.Dialog | # Qt.WindowTitleHint | # Qt.WindowSystemMenuHint | # Qt.WindowContextHelpButtonHint | # Qt.WindowCloseButtonHint self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint) self.setGeometry(700, 300, 250, 300) self.setWindowTitle('Calendar') @pyqtSlot(int) def task_open(self, index): self.task_view.set_task(index) self.central.setCurrentIndex(Root.task_view_index) @pyqtSlot() def task_view_close(self): self.central.setCurrentIndex(Root.task_list_index) def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.close()
class Example(QWidget): def __init__(self): super().__init__() self.initUI() self.stacked_widget.currentChanged.connect(self.set_button_state) self.next_button.clicked.connect(self.next_page) self.prev_button.clicked.connect(self.prev_page) def initUI(self): self.next_button = QPushButton('Next') self.prev_button = QPushButton('Previous') self.next_button.setEnabled(False) self.prev_button.setEnabled(False) self.stacked_widget = QStackedWidget() hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.prev_button) hbox.addWidget(self.next_button) vbox = QVBoxLayout() vbox.addWidget(self.stacked_widget) vbox.addLayout(hbox) self.setLayout(vbox) def set_button_state(self, index): self.prev_button.setEnabled(index > 0) n_pages = len(self.stacked_widget) self.next_button.setEnabled( index % n_pages < n_pages - 1) def insert_page(self, widget, index=-1): self.stacked_widget.insertWidget(index, widget) self.set_button_state(self.stacked_widget.currentIndex()) def next_page(self): new_index = self.stacked_widget.currentIndex()+1 if new_index < len(self.stacked_widget): self.stacked_widget.setCurrentIndex(new_index) def prev_page(self): new_index = self.stacked_widget.currentIndex()-1 if new_index >= 0: self.stacked_widget.setCurrentIndex(new_index)
class Demo(QWidget): def __init__(self, parent=None, *args, **kwargs): super(Demo, self).__init__(parent, *args, **kwargs) # 整体水平盒子布局 self.hbox = QHBoxLayout() self.setLayout(self.hbox) self.vbox = QVBoxLayout() self.stacked = QStackedWidget() self.hbox.addLayout(self.vbox) self.hbox.addWidget(self.stacked) self.btn1 = QPushButton('btn1') self.btn2 = QPushButton('btn2') self.btn3 = QPushButton('btn3') self.btn1.setObjectName('btn1') self.btn2.setObjectName('btn2') self.btn3.setObjectName('btn3') self.vbox.addWidget(self.btn1) self.vbox.addWidget(self.btn2) self.vbox.addWidget(self.btn3) self.lab1 = QLabel('页面1') self.lab2 = QLabel('页面2') self.lab3 = QLabel('页面3') self.stacked.insertWidget(0, self.lab1) self.stacked.insertWidget(1, self.lab2) self.stacked.insertWidget(2, self.lab3) QMetaObject.connectSlotsByName(self) @pyqtSlot() def on_btn1_clicked(self): self.stacked.setCurrentIndex(0) @pyqtSlot() def on_btn2_clicked(self): self.stacked.setCurrentIndex(1) @pyqtSlot() def on_btn3_clicked(self): self.stacked.setCurrentIndex(2)
class IPFSHashExplorerStack(GalacteekTab): """ Organizes IPFSHashExplorerWidgets with a QStackedWidget """ def __init__(self, gWindow, hashRef, maxItems=16, parent=None): super(IPFSHashExplorerStack, self).__init__(gWindow) self.rootHash = hashRef self.maxItems = maxItems self.stack = QStackedWidget(self) self.exLayout = QVBoxLayout() self.exLayout.addWidget(self.stack) self.vLayout.addLayout(self.exLayout) if self.rootHash: self.viewHash(self.rootHash) @property def itemsCount(self): return self.stack.count() def viewHash(self, hashRef, addClose=False, autoOpenFolders=False): view = IPFSHashExplorerWidget(hashRef, parent=self, addClose=addClose, showCidLabel=True, autoOpenFolders=autoOpenFolders) view.closeRequest.connect(functools.partial(self.remove, view)) view.directoryOpenRequest.connect( lambda cid: self.viewHash(cid, addClose=True)) self.stack.insertWidget(self.stack.count(), view) self.stack.setCurrentWidget(view) view.reFocus() return True def remove(self, view): try: self.stack.removeWidget(view) except: pass
class Timer(Base): def __init__(self, observer: Observer, name: str, foreground_color="#ffffff", font_name=""): super().__init__(name, foreground_color, font_name) self.main_layout = QGridLayout() self.central_widget = QStackedWidget() self.central_widget.insertWidget(0, TimerOverview(observer, "TimerOverview", self, foreground_color)) self.central_widget.insertWidget(1, AddTimer(observer, "AddTimer", self, foreground_color)) self.central_widget.setCurrentIndex(0) self.main_layout.addWidget(self.central_widget) self.setLayout(self.main_layout) def pass_timer(self, timer_config: dict): self.central_widget.widget(0).add_timer(timer_config) def switch_central_widget(self): max_value = self.central_widget.count() index = self.central_widget.currentIndex() self.central_widget.setCurrentIndex((index + 1) % max_value)
class MainWindow(QWidget): def __init__(self): super().__init__() layout = QVBoxLayout() self.stackedWidget = QStackedWidget() self.stackedWidget.addWidget(ClockPanel()) self.alarms_panel = AlarmsPanel() self.stackedWidget.addWidget(self.alarms_panel) self.stackedWidget.addWidget(SettingsPanel()) layout.addWidget(self.stackedWidget) menu_buttons = MenuButtons() menu_buttons.switch_panel.connect(self.switch_panel) layout.addWidget(menu_buttons) self.alarms_panel.edit_alarms.connect(self.display_edit_alarm) self.setLayout(layout) @pyqtSlot(int, name="switch_panel") def switch_panel(self, panel_index): self.stackedWidget.setCurrentIndex(panel_index) @pyqtSlot(int, name="edit_alarm") def display_edit_alarm(self, alarm_id): print('EDIT ' + str(alarm_id)) # drop alarms panel edit_alarm_panel = EditAlarmPanel(alarm_id) self.stackedWidget.insertWidget(1, edit_alarm_panel) self.stackedWidget.setCurrentIndex(1) self.stackedWidget.removeWidget(self.alarms_panel) # display edit alarm panel edit_alarm_panel.quit_signal.connect(self.hello) @pyqtSlot(name="quit") def hello(self): print('should close the edit alarm panel')
class MainArea(QWidget): """A class responsible for organizing artist/album/playlist/now playing tabs and generally access to library contents.""" def __init__(self, control, upperBox: UpperBox) -> None: super().__init__() self.control = control self.songListArea = upperBox.songList self.layout = QVBoxLayout() self.buttons = QWidget() self.setLayout(self.layout) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.buttons) self.buttonLayout = QHBoxLayout() self.labels = {"Artists": QPushButton(), "Albums": QPushButton(), "Playlists": QPushButton(), "Now Playing": QPushButton()} self.setButtons() line = QFrame() line.setFrameShape(QFrame.HLine) self.layout.addWidget(line) self.mainArea = QStackedWidget() self.layout.addWidget(self.mainArea) self.artistScrollArea = MainScrollArea(FlowLayout) self.artistLayout = self.artistScrollArea.widget().layout() self.mainArea.insertWidget(0, self.artistScrollArea) self.albumScrollArea = MainScrollArea(FlowLayout) self.albumLayout = self.albumScrollArea.widget().layout() self.mainArea.insertWidget(1, self.albumScrollArea) self.playlistScrollArea = MainScrollArea(FlowLayout) self.playlistLayout = self.playlistScrollArea.widget().layout() self.mainArea.insertWidget(2, self.playlistScrollArea) self.nowPlayingScrollArea = MainScrollArea(QGridLayout) self.nowPlayingLayout = self.nowPlayingScrollArea.widget().layout() self.nowPlayingLayout.setAlignment(Qt.AlignTop) self.nowPlayingLayout.setHorizontalSpacing(0) self.nowPlayingLayout.setVerticalSpacing(0) self.nowPlayingLayout.setContentsMargins(0, 0, 0, 0) self.nowPlayingLayout.setColumnStretch(0, 1) self.nowPlayingLayout.setColumnStretch(1, 1) self.nowPlayingLayout.setColumnStretch(3, 2) self.mainArea.insertWidget(3, self.nowPlayingScrollArea) self.nowPlayingSong = None self.garbageProtector = {} self.pixmaps = {"artist": artistPixmap, "album": albumPixmap, "playlist": playlistPixmap} self.activePixmaps = [] self.index = 0 for n in range(1, 8): self.activePixmaps.append(QPixmap(f"{location}active{n}.png")) for scrollArea in [self.artistScrollArea, self.albumScrollArea, self.playlistScrollArea, self.nowPlayingScrollArea]: scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) scrollArea.setWidgetResizable(True) scrollArea.setFrameShape(QFrame.NoFrame) def setButtons(self) -> None: """Creates buttons for switching between tabs.""" self.buttonLayout.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.buttonLayout.setSpacing(20) self.buttons.setLayout(self.buttonLayout) self.buttons.setFixedHeight(45) for label in self.labels: button = self.labels[label] button.setText(label) font = QFont() font.setBold(True) font.setPointSize(12) button.setFont(font) button.setStyleSheet("color:#afafaf;" "text-align:top;" "border-style: none;" "background-color:#141414;") button.setFixedHeight(25) self.buttonLayout.addWidget(button) self.labels["Artists"].clicked.connect(lambda x: self.showArea(0)) self.labels["Albums"].clicked.connect(lambda x: self.showArea(1)) self.labels["Playlists"].clicked.connect(lambda x: self.showArea(2)) self.labels["Now Playing"].clicked.connect(lambda x: self.showArea(3)) def setAreas(self, library) -> None: """Called after the GUI has been shown, draws widgets for all artists/albums/playlists in the library.""" self.setMainAreaArtists(library) self.setMainAreaAlbums(library) self.setMainAreaPlaylists(library) self.setNowPlayingArea(library) def updateView(self, library) -> None: areas = {self.artistLayout: library.artists, self.albumLayout: library.albums, self.playlistLayout: library.playlists} types = {self.artistLayout: "artist", self.albumLayout: "album", self.playlistLayout: "playlist"} for area in areas: fieldNames = [] toBeRemoved = [] for field in area.items: fieldNames.append(field.widget().name) if field.widget().name not in areas[area]: toBeRemoved.append(field) if len(toBeRemoved): for field in toBeRemoved: area.removeItem(field) field.widget().hide() field.widget().deleteLater() for libraryItem in areas[area]: if libraryItem not in fieldNames: self.addItemToLayout(area, types[area], libraryItem) fieldNames.append(libraryItem) def addItemToLayout(self, layout: QLayout, isType: str, name: str) -> None: item = MediaWidget(self.control, isType, name) item.setFixedSize(160, 195) itemLayout = QVBoxLayout() item.setLayout(itemLayout) label = QLabel() label.setFixedSize(150, 150) label.setPixmap(QPixmap(self.pixmaps[isType])) label.setScaledContents(True) itemLayout.addWidget(label) label = QLabel(name) label.setFixedWidth(150) label.setStyleSheet("color:#afafaf;" "font-size: 12px;" "font-weight: bold;") label.setAlignment(Qt.AlignCenter) label.setWordWrap(True) itemLayout.addWidget(label) layout.addWidget(item) def setMainAreaArtists(self, library) -> None: clearLayout(self.artistLayout) if library is not None: for artist in library.artists: self.addItemToLayout(self.artistLayout, "artist", artist) def setMainAreaAlbums(self, library) -> None: clearLayout(self.albumLayout) if library is not None: for album in library.albums: self.addItemToLayout(self.albumLayout, "album", album) def setMainAreaPlaylists(self, library) -> None: clearLayout(self.playlistLayout) if library is not None: for playlist in library.playlists: self.addItemToLayout(self.playlistLayout, "playlist", playlist) def setNowPlayingArea(self, library, clearOnly: bool = False) -> None: clearLayout(self.nowPlayingLayout) self.garbageProtector = {} self.nowPlayingSong = None if library is not None: column = 0 row = 0 for fieldName in ["Artist", "Album", "Track", "Title", "", "Length"]: field = QLabel(fieldName) field.setStyleSheet("QWidget {" " color:#afafaf;" " font-size: 15px;" " font-weight: bold;" " border-style: none none solid none;" " border-width: 2px;" " border-color: #afafaf;" "}") self.nowPlayingLayout.addWidget(field, row, column) column += 1 row += 1 if clearOnly: return for n in range(self.control.playlist.mediaCount()): media = self.control.playlist.media(n) song = media.request().url().toLocalFile().replace("/", "\\") if song in library.library: column = 0 self.garbageProtector[song] = [] for field in [ARTIST, ALBUM, TRACK, NAME, "pixmap", LENGTH]: songWidget = SongWidget(self.control, song, True) songWidget.setLayout(QHBoxLayout()) songWidget.setStyleSheet("QLabel {" " color:#afafaf;" " font-size: 12px;" " border-style: none none solid none;" " border-width: 0.5px;" " border-color: #3c3c3c;" "}") label = QLabel() if field != "pixmap": label.setText(library.library[song][field]) if field == LENGTH: label.setAlignment(Qt.AlignRight) else: label.setFixedSize(15, 15) label.setScaledContents(True) songWidget.layout().addWidget(label) songWidget.layout().setContentsMargins(0, 15, 0, 0) self.garbageProtector[song].append(label) self.nowPlayingLayout.addWidget(songWidget, row, column) column += 1 row += 1 def updateActiveSong(self, currentIndex: int) -> None: """Shows a small image on the currently playing song for visual feedback.""" if self.nowPlayingSong is not None: self.nowPlayingSong.clear() self.nowPlayingSong = None if (item := self.nowPlayingLayout.itemAtPosition(currentIndex + 1, 4)) is not None: label = item.widget().layout().itemAt(0).widget() self.nowPlayingSong = label
class TilesetDock(QDockWidget): ## # Emitted when the current tile changed. ## currentTileChanged = pyqtSignal(list) ## # Emitted when the currently selected tiles changed. ## stampCaptured = pyqtSignal(TileStamp) ## # Emitted when files are dropped at the tileset dock. ## tilesetsDropped = pyqtSignal(QStringList) newTileset = pyqtSignal() ## # Constructor. ## def __init__(self, parent=None): super().__init__(parent) # Shared tileset references because the dock wants to add new tiles self.mTilesets = QVector() self.mCurrentTilesets = QMap() self.mMapDocument = None self.mTabBar = QTabBar() self.mViewStack = QStackedWidget() self.mToolBar = QToolBar() self.mCurrentTile = None self.mCurrentTiles = None self.mNewTileset = QAction(self) self.mImportTileset = QAction(self) self.mExportTileset = QAction(self) self.mPropertiesTileset = QAction(self) self.mDeleteTileset = QAction(self) self.mEditTerrain = QAction(self) self.mAddTiles = QAction(self) self.mRemoveTiles = QAction(self) self.mTilesetMenuButton = TilesetMenuButton(self) self.mTilesetMenu = QMenu(self) # opens on click of mTilesetMenu self.mTilesetActionGroup = QActionGroup(self) self.mTilesetMenuMapper = None # needed due to dynamic content self.mEmittingStampCaptured = False self.mSynchronizingSelection = False self.setObjectName("TilesetDock") self.mTabBar.setMovable(True) self.mTabBar.setUsesScrollButtons(True) self.mTabBar.currentChanged.connect(self.updateActions) self.mTabBar.tabMoved.connect(self.moveTileset) w = QWidget(self) horizontal = QHBoxLayout() horizontal.setSpacing(0) horizontal.addWidget(self.mTabBar) horizontal.addWidget(self.mTilesetMenuButton) vertical = QVBoxLayout(w) vertical.setSpacing(0) vertical.setContentsMargins(5, 5, 5, 5) vertical.addLayout(horizontal) vertical.addWidget(self.mViewStack) horizontal = QHBoxLayout() horizontal.setSpacing(0) horizontal.addWidget(self.mToolBar, 1) vertical.addLayout(horizontal) self.mNewTileset.setIcon(QIcon(":images/16x16/document-new.png")) self.mImportTileset.setIcon(QIcon(":images/16x16/document-import.png")) self.mExportTileset.setIcon(QIcon(":images/16x16/document-export.png")) self.mPropertiesTileset.setIcon( QIcon(":images/16x16/document-properties.png")) self.mDeleteTileset.setIcon(QIcon(":images/16x16/edit-delete.png")) self.mEditTerrain.setIcon(QIcon(":images/16x16/terrain.png")) self.mAddTiles.setIcon(QIcon(":images/16x16/add.png")) self.mRemoveTiles.setIcon(QIcon(":images/16x16/remove.png")) Utils.setThemeIcon(self.mNewTileset, "document-new") Utils.setThemeIcon(self.mImportTileset, "document-import") Utils.setThemeIcon(self.mExportTileset, "document-export") Utils.setThemeIcon(self.mPropertiesTileset, "document-properties") Utils.setThemeIcon(self.mDeleteTileset, "edit-delete") Utils.setThemeIcon(self.mAddTiles, "add") Utils.setThemeIcon(self.mRemoveTiles, "remove") self.mNewTileset.triggered.connect(self.newTileset) self.mImportTileset.triggered.connect(self.importTileset) self.mExportTileset.triggered.connect(self.exportTileset) self.mPropertiesTileset.triggered.connect(self.editTilesetProperties) self.mDeleteTileset.triggered.connect(self.removeTileset) self.mEditTerrain.triggered.connect(self.editTerrain) self.mAddTiles.triggered.connect(self.addTiles) self.mRemoveTiles.triggered.connect(self.removeTiles) self.mToolBar.addAction(self.mNewTileset) self.mToolBar.setIconSize(QSize(16, 16)) self.mToolBar.addAction(self.mImportTileset) self.mToolBar.addAction(self.mExportTileset) self.mToolBar.addAction(self.mPropertiesTileset) self.mToolBar.addAction(self.mDeleteTileset) self.mToolBar.addAction(self.mEditTerrain) self.mToolBar.addAction(self.mAddTiles) self.mToolBar.addAction(self.mRemoveTiles) self.mZoomable = Zoomable(self) self.mZoomComboBox = QComboBox() self.mZoomable.connectToComboBox(self.mZoomComboBox) horizontal.addWidget(self.mZoomComboBox) self.mViewStack.currentChanged.connect(self.updateCurrentTiles) TilesetManager.instance().tilesetChanged.connect(self.tilesetChanged) DocumentManager.instance().documentAboutToClose.connect( self.documentAboutToClose) self.mTilesetMenuButton.setMenu(self.mTilesetMenu) self.mTilesetMenu.aboutToShow.connect(self.refreshTilesetMenu) self.setWidget(w) self.retranslateUi() self.setAcceptDrops(True) self.updateActions() def __del__(self): del self.mCurrentTiles ## # Sets the map for which the tilesets should be displayed. ## def setMapDocument(self, mapDocument): if (self.mMapDocument == mapDocument): return # Hide while we update the tab bar, to avoid repeated layouting if sys.platform != 'darwin': self.widget().hide() self.setCurrentTiles(None) self.setCurrentTile(None) if (self.mMapDocument): # Remember the last visible tileset for this map tilesetName = self.mTabBar.tabText(self.mTabBar.currentIndex()) self.mCurrentTilesets.insert(self.mMapDocument, tilesetName) # Clear previous content while (self.mTabBar.count()): self.mTabBar.removeTab(0) while (self.mViewStack.count()): self.mViewStack.removeWidget(self.mViewStack.widget(0)) #self.mTilesets.clear() # Clear all connections to the previous document if (self.mMapDocument): self.mMapDocument.disconnect() self.mMapDocument = mapDocument if (self.mMapDocument): self.mTilesets = self.mMapDocument.map().tilesets() for tileset in self.mTilesets: view = TilesetView() view.setMapDocument(self.mMapDocument) view.setZoomable(self.mZoomable) self.mTabBar.addTab(tileset.name()) self.mViewStack.addWidget(view) self.mMapDocument.tilesetAdded.connect(self.tilesetAdded) self.mMapDocument.tilesetRemoved.connect(self.tilesetRemoved) self.mMapDocument.tilesetMoved.connect(self.tilesetMoved) self.mMapDocument.tilesetNameChanged.connect( self.tilesetNameChanged) self.mMapDocument.tilesetFileNameChanged.connect( self.updateActions) self.mMapDocument.tilesetChanged.connect(self.tilesetChanged) self.mMapDocument.tileAnimationChanged.connect( self.tileAnimationChanged) cacheName = self.mCurrentTilesets.take(self.mMapDocument) for i in range(self.mTabBar.count()): if (self.mTabBar.tabText(i) == cacheName): self.mTabBar.setCurrentIndex(i) break object = self.mMapDocument.currentObject() if object: if object.typeId() == Object.TileType: self.setCurrentTile(object) self.updateActions() if sys.platform != 'darwin': self.widget().show() ## # Synchronizes the selection with the given stamp. Ignored when the stamp is # changing because of a selection change in the TilesetDock. ## def selectTilesInStamp(self, stamp): if self.mEmittingStampCaptured: return processed = QSet() selections = QMap() for variation in stamp.variations(): tileLayer = variation.tileLayer() for cell in tileLayer: tile = cell.tile if tile: if (processed.contains(tile)): continue processed.insert(tile) # avoid spending time on duplicates tileset = tile.tileset() tilesetIndex = self.mTilesets.indexOf( tileset.sharedPointer()) if (tilesetIndex != -1): view = self.tilesetViewAt(tilesetIndex) if (not view.model()): # Lazily set up the model self.setupTilesetModel(view, tileset) model = view.tilesetModel() modelIndex = model.tileIndex(tile) selectionModel = view.selectionModel() _x = QItemSelection() _x.select(modelIndex, modelIndex) selections[selectionModel] = _x if (not selections.isEmpty()): self.mSynchronizingSelection = True # Mark captured tiles as selected for i in selections: selectionModel = i[0] selection = i[1] selectionModel.select(selection, QItemSelectionModel.SelectCurrent) # Show/edit properties of all captured tiles self.mMapDocument.setSelectedTiles(processed.toList()) # Update the current tile (useful for animation and collision editors) first = selections.first() selectionModel = first[0] selection = first[1] currentIndex = QModelIndex(selection.first().topLeft()) if (selectionModel.currentIndex() != currentIndex): selectionModel.setCurrentIndex(currentIndex, QItemSelectionModel.NoUpdate) else: self.currentChanged(currentIndex) self.mSynchronizingSelection = False def currentTilesetChanged(self): view = self.currentTilesetView() if view: s = view.selectionModel() if s: self.setCurrentTile(view.tilesetModel().tileAt( s.currentIndex())) ## # Returns the currently selected tile. ## def currentTile(self): return self.mCurrentTile def changeEvent(self, e): super().changeEvent(e) x = e.type() if x == QEvent.LanguageChange: self.retranslateUi() else: pass def dragEnterEvent(self, e): urls = e.mimeData().urls() if (not urls.isEmpty() and not urls.at(0).toLocalFile().isEmpty()): e.accept() def dropEvent(self, e): paths = QStringList() for url in e.mimeData().urls(): localFile = url.toLocalFile() if (not localFile.isEmpty()): paths.append(localFile) if (not paths.isEmpty()): self.tilesetsDropped.emit(paths) e.accept() def selectionChanged(self): self.updateActions() if not self.mSynchronizingSelection: self.updateCurrentTiles() def currentChanged(self, index): if (not index.isValid()): return model = index.model() self.setCurrentTile(model.tileAt(index)) def updateActions(self): external = False hasImageSource = False hasSelection = False view = None index = self.mTabBar.currentIndex() if (index > -1): view = self.tilesetViewAt(index) if (view): tileset = self.mTilesets.at(index) if (not view.model()): # Lazily set up the model self.setupTilesetModel(view, tileset) self.mViewStack.setCurrentIndex(index) external = tileset.isExternal() hasImageSource = tileset.imageSource() != '' hasSelection = view.selectionModel().hasSelection() tilesetIsDisplayed = view != None mapIsDisplayed = self.mMapDocument != None self.mNewTileset.setEnabled(mapIsDisplayed) self.mImportTileset.setEnabled(tilesetIsDisplayed and external) self.mExportTileset.setEnabled(tilesetIsDisplayed and not external) self.mPropertiesTileset.setEnabled(tilesetIsDisplayed and not external) self.mDeleteTileset.setEnabled(tilesetIsDisplayed) self.mEditTerrain.setEnabled(tilesetIsDisplayed and not external) self.mAddTiles.setEnabled(tilesetIsDisplayed and not hasImageSource and not external) self.mRemoveTiles.setEnabled(tilesetIsDisplayed and not hasImageSource and hasSelection and not external) def updateCurrentTiles(self): view = self.currentTilesetView() if (not view): return s = view.selectionModel() if (not s): return indexes = s.selection().indexes() if len(indexes) == 0: return first = indexes[0] minX = first.column() maxX = first.column() minY = first.row() maxY = first.row() for index in indexes: if minX > index.column(): minX = index.column() if maxX < index.column(): maxX = index.column() if minY > index.row(): minY = index.row() if maxY < index.row(): maxY = index.row() # Create a tile layer from the current selection tileLayer = TileLayer(QString(), 0, 0, maxX - minX + 1, maxY - minY + 1) model = view.tilesetModel() for index in indexes: tileLayer.setCell(index.column() - minX, index.row() - minY, Cell(model.tileAt(index))) self.setCurrentTiles(tileLayer) def indexPressed(self, index): view = self.currentTilesetView() tile = view.tilesetModel().tileAt(index) if tile: self.mMapDocument.setCurrentObject(tile) def tilesetAdded(self, index, tileset): view = TilesetView() view.setMapDocument(self.mMapDocument) view.setZoomable(self.mZoomable) self.mTilesets.insert(index, tileset.sharedPointer()) self.mTabBar.insertTab(index, tileset.name()) self.mViewStack.insertWidget(index, view) self.updateActions() def tilesetChanged(self, tileset): # Update the affected tileset model, if it exists index = indexOf(self.mTilesets, tileset) if (index < 0): return model = self.tilesetViewAt(index).tilesetModel() if model: model.tilesetChanged() def tilesetRemoved(self, tileset): # Delete the related tileset view index = indexOf(self.mTilesets, tileset) self.mTilesets.removeAt(index) self.mTabBar.removeTab(index) self.tilesetViewAt(index).close() # Make sure we don't reference this tileset anymore if (self.mCurrentTiles): # TODO: Don't clean unnecessarily (but first the concept of # "current brush" would need to be introduced) cleaned = self.mCurrentTiles.clone() cleaned.removeReferencesToTileset(tileset) self.setCurrentTiles(cleaned) if (self.mCurrentTile and self.mCurrentTile.tileset() == tileset): self.setCurrentTile(None) self.updateActions() def tilesetMoved(self, _from, to): self.mTilesets.insert(to, self.mTilesets.takeAt(_from)) # Move the related tileset views widget = self.mViewStack.widget(_from) self.mViewStack.removeWidget(widget) self.mViewStack.insertWidget(to, widget) self.mViewStack.setCurrentIndex(self.mTabBar.currentIndex()) # Update the titles of the affected tabs start = min(_from, to) end = max(_from, to) for i in range(start, end + 1): tileset = self.mTilesets.at(i) if (self.mTabBar.tabText(i) != tileset.name()): self.mTabBar.setTabText(i, tileset.name()) def tilesetNameChanged(self, tileset): index = indexOf(self.mTilesets, tileset) self.mTabBar.setTabText(index, tileset.name()) def tileAnimationChanged(self, tile): view = self.currentTilesetView() if view: model = view.tilesetModel() if model: model.tileChanged(tile) ## # Removes the currently selected tileset. ## def removeTileset(self, *args): l = len(args) if l == 0: currentIndex = self.mViewStack.currentIndex() if (currentIndex != -1): self.removeTileset(self.mViewStack.currentIndex()) elif l == 1: ## # Removes the tileset at the given index. Prompting the user when the tileset # is in use by the map. ## index = args[0] tileset = self.mTilesets.at(index).data() inUse = self.mMapDocument.map().isTilesetUsed(tileset) # If the tileset is in use, warn the user and confirm removal if (inUse): warning = QMessageBox( QMessageBox.Warning, self.tr("Remove Tileset"), self.tr("The tileset \"%s\" is still in use by the map!" % tileset.name()), QMessageBox.Yes | QMessageBox.No, self) warning.setDefaultButton(QMessageBox.Yes) warning.setInformativeText( self.tr("Remove this tileset and all references " "to the tiles in this tileset?")) if (warning.exec() != QMessageBox.Yes): return remove = RemoveTileset(self.mMapDocument, index, tileset) undoStack = self.mMapDocument.undoStack() if (inUse): # Remove references to tiles in this tileset from the current map def referencesTileset(cell): tile = cell.tile if tile: return tile.tileset() == tileset return False undoStack.beginMacro(remove.text()) removeTileReferences(self.mMapDocument, referencesTileset) undoStack.push(remove) if (inUse): undoStack.endMacro() def moveTileset(self, _from, to): command = MoveTileset(self.mMapDocument, _from, to) self.mMapDocument.undoStack().push(command) def editTilesetProperties(self): tileset = self.currentTileset() if (not tileset): return self.mMapDocument.setCurrentObject(tileset) self.mMapDocument.emitEditCurrentObject() def importTileset(self): tileset = self.currentTileset() if (not tileset): return command = SetTilesetFileName(self.mMapDocument, tileset, QString()) self.mMapDocument.undoStack().push(command) def exportTileset(self): tileset = self.currentTileset() if (not tileset): return tsxFilter = self.tr("Tiled tileset files (*.tsx)") helper = FormatHelper(FileFormat.ReadWrite, tsxFilter) prefs = preferences.Preferences.instance() suggestedFileName = prefs.lastPath( preferences.Preferences.ExternalTileset) suggestedFileName += '/' suggestedFileName += tileset.name() extension = ".tsx" if (not suggestedFileName.endswith(extension)): suggestedFileName += extension selectedFilter = tsxFilter fileName, _ = QFileDialog.getSaveFileName(self, self.tr("Export Tileset"), suggestedFileName, helper.filter(), selectedFilter) if fileName == '': return prefs.setLastPath(preferences.Preferences.ExternalTileset, QFileInfo(fileName).path()) tsxFormat = TsxTilesetFormat() format = helper.formatByNameFilter(selectedFilter) if not format: format = tsxFormat if format.write(tileset, fileName): command = SetTilesetFileName(self.mMapDocument, tileset, fileName) self.mMapDocument.undoStack().push(command) else: error = format.errorString() QMessageBox.critical(self.window(), self.tr("Export Tileset"), self.tr("Error saving tileset: %s" % error)) def editTerrain(self): tileset = self.currentTileset() if (not tileset): return editTerrainDialog = EditTerrainDialog(self.mMapDocument, tileset, self) editTerrainDialog.exec() def addTiles(self): tileset = self.currentTileset() if (not tileset): return prefs = preferences.Preferences.instance() startLocation = QFileInfo( prefs.lastPath(preferences.Preferences.ImageFile)).absolutePath() filter = Utils.readableImageFormatsFilter() files = QFileDialog.getOpenFileNames(self.window(), self.tr("Add Tiles"), startLocation, filter) tiles = QList() id = tileset.tileCount() for file in files: image = QPixmap(file) if (not image.isNull()): tiles.append(Tile(image, file, id, tileset)) id += 1 else: warning = QMessageBox(QMessageBox.Warning, self.tr("Add Tiles"), self.tr("Could not load \"%s\"!" % file), QMessageBox.Ignore | QMessageBox.Cancel, self.window()) warning.setDefaultButton(QMessageBox.Ignore) if (warning.exec() != QMessageBox.Ignore): tiles.clear() return if (tiles.isEmpty()): return prefs.setLastPath(preferences.Preferences.ImageFile, files.last()) self.mMapDocument.undoStack().push( AddTiles(self.mMapDocument, tileset, tiles)) def removeTiles(self): view = self.currentTilesetView() if (not view): return if (not view.selectionModel().hasSelection()): return indexes = view.selectionModel().selectedIndexes() model = view.tilesetModel() tileIds = RangeSet() tiles = QList() for index in indexes: tile = model.tileAt(index) if tile: tileIds.insert(tile.id()) tiles.append(tile) def matchesAnyTile(cell): tile = cell.tile if tile: return tiles.contains(tile) return False inUse = self.hasTileReferences(self.mMapDocument, matchesAnyTile) # If the tileset is in use, warn the user and confirm removal if (inUse): warning = QMessageBox( QMessageBox.Warning, self.tr("Remove Tiles"), self.tr("One or more of the tiles to be removed are " "still in use by the map!"), QMessageBox.Yes | QMessageBox.No, self) warning.setDefaultButton(QMessageBox.Yes) warning.setInformativeText( self.tr("Remove all references to these tiles?")) if (warning.exec() != QMessageBox.Yes): return undoStack = self.mMapDocument.undoStack() undoStack.beginMacro(self.tr("Remove Tiles")) removeTileReferences(self.mMapDocument, matchesAnyTile) # Iterate backwards over the ranges in order to keep the indexes valid firstRange = tileIds.begin() it = tileIds.end() if (it == firstRange): # no range return tileset = view.tilesetModel().tileset() while (it != firstRange): it -= 1 item = tileIds.item(it) length = item[1] - item[0] + 1 undoStack.push( RemoveTiles(self.mMapDocument, tileset, item[0], length)) undoStack.endMacro() # Clear the current tiles, will be referencing the removed tiles self.setCurrentTiles(None) self.setCurrentTile(None) def documentAboutToClose(self, mapDocument): self.mCurrentTilesets.remove(mapDocument) def refreshTilesetMenu(self): self.mTilesetMenu.clear() if (self.mTilesetMenuMapper): self.mTabBar.disconnect(self.mTilesetMenuMapper) del self.mTilesetMenuMapper self.mTilesetMenuMapper = QSignalMapper(self) self.mTilesetMenuMapper.mapped.connect(self.mTabBar.setCurrentIndex) currentIndex = self.mTabBar.currentIndex() for i in range(self.mTabBar.count()): action = QAction(self.mTabBar.tabText(i), self) action.setCheckable(True) self.mTilesetActionGroup.addAction(action) if (i == currentIndex): action.setChecked(True) self.mTilesetMenu.addAction(action) action.triggered.connect(self.mTilesetMenuMapper.map) self.mTilesetMenuMapper.setMapping(action, i) def setCurrentTile(self, tile): if (self.mCurrentTile == tile): return self.mCurrentTile = tile self.currentTileChanged.emit([tile]) if (tile): self.mMapDocument.setCurrentObject(tile) def setCurrentTiles(self, tiles): if (self.mCurrentTiles == tiles): return del self.mCurrentTiles self.mCurrentTiles = tiles # Set the selected tiles on the map document if (tiles): selectedTiles = QList() for y in range(tiles.height()): for x in range(tiles.width()): cell = tiles.cellAt(x, y) if (not cell.isEmpty()): selectedTiles.append(cell.tile) self.mMapDocument.setSelectedTiles(selectedTiles) # Create a tile stamp with these tiles map = self.mMapDocument.map() stamp = Map(map.orientation(), tiles.width(), tiles.height(), map.tileWidth(), map.tileHeight()) stamp.addLayer(tiles.clone()) stamp.addTilesets(tiles.usedTilesets()) self.mEmittingStampCaptured = True self.stampCaptured.emit(TileStamp(stamp)) self.mEmittingStampCaptured = False def retranslateUi(self): self.setWindowTitle(self.tr("Tilesets")) self.mNewTileset.setText(self.tr("New Tileset")) self.mImportTileset.setText(self.tr("Import Tileset")) self.mExportTileset.setText(self.tr("Export Tileset As...")) self.mPropertiesTileset.setText(self.tr("Tileset Properties")) self.mDeleteTileset.setText(self.tr("Remove Tileset")) self.mEditTerrain.setText(self.tr("Edit Terrain Information")) self.mAddTiles.setText(self.tr("Add Tiles")) self.mRemoveTiles.setText(self.tr("Remove Tiles")) def currentTileset(self): index = self.mTabBar.currentIndex() if (index == -1): return None return self.mTilesets.at(index) def currentTilesetView(self): return self.mViewStack.currentWidget() def tilesetViewAt(self, index): return self.mViewStack.widget(index) def setupTilesetModel(self, view, tileset): view.setModel(TilesetModel(tileset, view)) s = view.selectionModel() s.selectionChanged.connect(self.selectionChanged) s.currentChanged.connect(self.currentChanged) view.pressed.connect(self.indexPressed)
class BooleanWidget(QWidget, NinjaWidget): def __init__(self, entity_data, parent=None): self._boolean_data = entity_data widget_name = self._parse_widget_name( self._boolean_data[EntityNameMorphology.ENTITY_NAME.value]) QWidget.__init__(self, widget_name=widget_name) NinjaWidget.__init__(self, widget_name=widget_name) self._boolean_behaviour = {} self._booleans_stacked_widget = None self._status_message_from_communication = {} self._current_is_on = None self._frame = None self._parse_status_behaviour() self._build_ui() self._set_style() self._init_connections() def _init_connections(self): communication_instance.signal_status_update.connect( self._slot_incoming_status) def _set_style(self): self.setMaximumWidth(_Parameters.TOTAL_WIDGET_WIDTH.value) self.setMaximumHeight(_Parameters.TOTAL_WIDGET_HEIGHT.value) # self._frame.setParent(self) # self._frame.setStyleSheet('border: 1px solid black;') def _parse_status_behaviour(self): status_behaviour_str = {} with open(self._boolean_data[EntityNameMorphology.ENTITY_FOLDER.value], 'r') as file: status_behaviour_str = file.read() try: self._boolean_behaviour = eval(status_behaviour_str) except Exception as e: self._log('eval failed with: {}'.format(status_behaviour_str)) def _build_ui(self): # self._frame = QFrame() # horizontal_layout = QHBoxLayout(self._frame) horizontal_layout = QHBoxLayout(self) self.setLayout(horizontal_layout) self._booleans_stacked_widget = QStackedWidget() self._init_booleans_types() header_label = QLabel() header_label.setText( self._boolean_behaviour[StatusBehaviourKey.LABEL_TEXT.value]) header_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) # header_label.setMaximumWidth(_Parameters.HEADER_LABEL_WIDTH.value) # header_label.setMaximumHeight(_Parameters.HEADER_LABEL_HEIGHT.value) self._set_boolean_type() # Order is important horizontal_layout.addWidget(header_label) horizontal_layout.addWidget(self._booleans_stacked_widget) def _init_booleans_types(self): self._init_boolean_type(_BooleanType.NONE.value, _Parameters.NONE_ICON_NAME.value) self._init_boolean_type(_BooleanType.ON.value, _Parameters.TRUE_ICON_NAME.value) self._init_boolean_type(_BooleanType.OFF.value, _Parameters.FALSE_ICON_NAME.value) def _init_boolean_type(self, index, resource_name): boolean_label = QLabel() boolean_label.setMaximumWidth(_Parameters.BOOLEAN_BULB_WIDTH.value) # boolean_label.setMinimumWidth(20) boolean_label.setMaximumHeight(_Parameters.BOOLEAN_BULB_HEIGHT.value) # boolean_label.setMinimumHeight(20) boolean_path = os.path.join(General.RESOURCES_FOLDER.value, resource_name) boolean_pixmap = QPixmap(boolean_path) boolean_pixmap.scaled(boolean_label.size(), Qt.KeepAspectRatio) boolean_label.setPixmap(boolean_pixmap) boolean_label.setScaledContents(True) self._booleans_stacked_widget.insertWidget(index, boolean_label) def _set_boolean_type(self): index = 0 if self._current_is_on is None: index = _BooleanType.NONE.value elif self._current_is_on: index = _BooleanType.ON.value else: index = _BooleanType.OFF.value self._booleans_stacked_widget.setCurrentIndex(index) @pyqtSlot('QString') def _slot_incoming_status(self, message): received_json = json.loads(message) self._status_message_from_communication = received_json try: required_status = self._boolean_behaviour[ StatusBehaviourKey.STATUS_FROM_COMMUNICATION.value] if self._status_message_from_communication[ 'status'] == required_status: first_key = self._boolean_behaviour[ StatusBehaviourKey.PATH_IN_MESSAGE.value][0] compliment_keys = self._boolean_behaviour[ StatusBehaviourKey.PATH_IN_MESSAGE.value][1:] # Extract keys status = self._status_message_from_communication[first_key] for key in compliment_keys: status = status[key] self._current_is_on = bool(status) self._set_boolean_type() except Exception as e: self._log( 'Path in message wasn\'t correct is {}, Error was {}'.format( self._boolean_data[ EntityNameMorphology.ENTITY_FOLDER.value], str(e)))
class Main(QWidget): def __init__(self): super().__init__() self.initUI() self.stacked_widget.currentChanged.connect(self.set_button_state) self.next_button.clicked.connect(self.next_page) self.setGeometry(300, 300, 750, 800) self.mouse_clik_counter = 0 self.player = Client() self.currentPlayer = None self.thread = ServerListener(self.player.client) self.thread.route.connect(self.routeGame) def closeEvent(self, event): if self.player.playerID: self.player.disconnect() def initUI(self): self.next_button = QPushButton('Dalej') self.next_button.setEnabled(False) self.stacked_widget = QStackedWidget() hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.next_button) vbox = QVBoxLayout() vbox.addWidget(self.stacked_widget) vbox.addLayout(hbox) self.setLayout(vbox) def set_button_state(self, index): n_pages = len(self.stacked_widget) self.next_button.setEnabled(index % n_pages < n_pages - 1) def insert_page(self, widget, index=-1): self.stacked_widget.insertWidget(index, widget) self.set_button_state(self.stacked_widget.currentIndex()) def next_page(self): new_index = self.stacked_widget.currentIndex() + 1 if new_index < len(self.stacked_widget): self.stacked_widget.setCurrentIndex(new_index) if self.mouse_clik_counter == 0: self.next_button.setText("Graj!") self.mouse_clik_counter += 1 self.player.register(self.player_name_input.text()) self.refreshList() elif self.mouse_clik_counter == 1: pass def welcomeTabUI(self): """Create the Welcome page UI.""" self.grid = QFormLayout() self.grid.setFormAlignment(Qt.AlignCenter | Qt.AlignCenter | Qt.AlignCenter) self.player_name_input = QLineEdit('Player') self.player_name_label = QLabel("Podaj swoją nazwę gracza", self) self.title_label = QLabel("Witaj w Connect4", self) self.title_label.setStyleSheet("font: 30pt Century Gothic") self.player_name_label.setStyleSheet("font: 15pt Century Gothic") self.title_label.setAlignment(Qt.AlignLeading | Qt.AlignCenter | Qt.AlignCenter) self.player_name_label.setAlignment(Qt.AlignCenter | Qt.AlignCenter | Qt.AlignCenter) self.player_name_input.setAlignment(Qt.AlignCenter | Qt.AlignCenter | Qt.AlignCenter) self.grid.addWidget(self.title_label) self.grid.addWidget(self.player_name_label) self.grid.addWidget(self.player_name_input) generalTab = QWidget() generalTab.setLayout(self.grid) return generalTab def gameTabUI(self): """Create the Game page UI.""" generalTab = QWidget() self.resultTable = ResulTable() self.game = Game() layout = QHBoxLayout() layout.addWidget(self.game) layout.addWidget(self.resultTable) generalTab.setLayout(layout) return generalTab def networkTabUI(self): """init boxes""" self.networkTab = QWidget() self.layout_main = QVBoxLayout() self.layout_create_room = QHBoxLayout() """Create room layout""" self.room_name_input = QLineEdit(self) self.room_name_label = QLabel("Nazwa", self) self.layout_create_room.addWidget(self.room_name_label) self.layout_create_room.addWidget(self.room_name_input) """Main layout""" self.list = QListWidget() self.list.currentItemChanged.connect(self.selected_room) self.btn_add_room = QPushButton('Dodaj pokój') self.btn_add_room.clicked.connect(self.create_room) self.btn_get_rooms = QPushButton('Odśwież listę pokoi') self.btn_get_rooms.clicked.connect(self.refreshList) self.selected_room_input = QLineEdit() self.btn_enter_room = QPushButton('Wejdź do pokoju') self.btn_enter_room.clicked.connect(self.enterToRoom) self.info_label = QLabel() self.info_label.setStyleSheet("font: 15pt Century Gothic; color: red") self.layout_main.addWidget(QLabel("Stwórz nowy pokój", self)) self.layout_main.addLayout(self.layout_create_room) self.layout_main.addWidget(self.btn_add_room) self.layout_main.addWidget(self.btn_get_rooms) self.layout_main.addWidget(QHLine()) self.layout_main.addWidget(QLabel("Wybierz pokój", self)) self.layout_main.addWidget(self.list) self.layout_main.addWidget(self.selected_room_input) self.layout_main.addWidget(self.btn_enter_room) self.layout_main.addWidget(self.info_label) self.networkTab.setLayout(self.layout_main) return self.networkTab def refreshList(self): self.rooms = self.player.getRoomList() self.rooms.sort(key=lambda x: x[0]) self.list.clear() for room in self.rooms: self.list.addItem( f"{room[0]} The current number of players {room[2]}") def selected_room(self): selectedRoom = self.rooms[self.list.currentRow()] self.selected_room_input.setText(selectedRoom[0]) def create_room(self): if self.room_name_input.text(): self.player.createRoom(self.room_name_input.text()) self.refreshList() self.thread.start() self.info_label.setText( f"Stworzono pokój: {self.room_name_input.text()}. Poczekaj na drugiego gracza." ) self.btn_add_room.setDisabled(True) self.btn_enter_room.setDisabled(True) self.btn_get_rooms.setDisabled(True) else: self.info_label.setText("Wpisz nazwę pokoju") def enterToRoom(self): if len(self.selected_room_input.text()) > 0: for room in self.rooms: if room[0] == self.selected_room_input.text(): if self.player.joinToRoom(room[1]): self.routeGame({'action': 'startGame'}) else: self.info_label.setText("Nie można wejść do pokoju") break else: self.info_label.setText("Nie znaleziono pokoju") else: self.info_label.setText("Nie wybrano pokoju") def routeGame(self, data): action = data['action'] if action == 'startGame': self.currentPlayer = self.player.getCurrentPlayer() if self.currentPlayer[1] != self.player.playerID: self.thread.start() self.game.currentPlayer = self.currentPlayer self.game.player = self.player self.game.thread = self.thread self.game.resultTable = self.resultTable self.resultTable.setCurrentPlayer(self.currentPlayer[0]) self.next_page() elif action == 'changePlayer': self.currentPlayer = self.player.getCurrentPlayer() self.resultTable.setCurrentPlayer(self.currentPlayer[0]) self.game.currentPlayer = self.currentPlayer self.resultTable.setCurrentPlayer(self.currentPlayer[0])
class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.initUI() self.stacked_widget.currentChanged.connect(self.set_button_state) self.next_button.clicked.connect(self.next_page) self.prev_button.clicked.connect(self.prev_page) def initUI(self): self.next_button = QPushButton('Next') self.prev_button = QPushButton('Previous') self.next_button.setEnabled(False) self.prev_button.setEnabled(False) self.stacked_widget = QStackedWidget() widget = QtWidgets.QWidget() self.setCentralWidget(widget) hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.prev_button) hbox.addWidget(self.next_button) vbox = QVBoxLayout() vbox.addWidget(self.stacked_widget) vbox.addLayout(hbox) h = HomeScreen(self) self.insert_page(h.label1) navigation = Navigation(sample, self) self.insert_page(navigation.horizontalGroupBox) #add the toolbar to the main window self.toolbar = navigation.toolbar self.addToolBar(self.toolbar) #start with the toolbar hidden self.toolbar.toggleViewAction().setChecked(True) self.toolbar.toggleViewAction().trigger() # create main layout widget.setLayout(vbox) def set_button_state(self, index): self.prev_button.setEnabled(index > 0) n_pages = len(self.stacked_widget) self.next_button.setEnabled( index % n_pages < n_pages - 1) def insert_page(self, widget, index=-1): self.stacked_widget.insertWidget(index, widget) self.set_button_state(self.stacked_widget.currentIndex()) def next_page(self): new_index = self.stacked_widget.currentIndex()+1 if new_index < len(self.stacked_widget): self.stacked_widget.setCurrentIndex(new_index) self.toolbar.toggleViewAction().trigger() def prev_page(self): new_index = self.stacked_widget.currentIndex()-1 if new_index >= 0: self.stacked_widget.setCurrentIndex(new_index) self.toolbar.toggleViewAction().trigger()
class SubTabWidget(QWidget): _tabChanged = pyqtSignal(int, name = "tabChanged") def __init__(self, subtitleData, videoWidget, parent = None): super(SubTabWidget, self).__init__(parent) self._subtitleData = subtitleData self.__initTabWidget(videoWidget) def __initTabWidget(self, videoWidget): settings = SubSettings() mainLayout = QVBoxLayout(self) mainLayout.setContentsMargins(0, 0, 0, 0) mainLayout.setSpacing(0) #TabBar self.tabBar = QTabBar(self) # Splitter (bookmarks + pages) self.splitter = QSplitter(self) self.splitter.setObjectName("sidebar_splitter") self._toolbox = ToolBox(self._subtitleData, self) self._toolbox.setObjectName("sidebar") self._toolbox.setMinimumWidth(100) self._toolbox.addTool(Details(self._subtitleData, self)) self._toolbox.addTool(Synchronizer(videoWidget, self._subtitleData, self)) self._toolbox.addTool(History(self)) self.rightWidget = QWidget() rightLayout = QGridLayout() rightLayout.setContentsMargins(0, 0, 0, 0) self.rightWidget.setLayout(rightLayout) self._mainTab = FileList(_("Subtitles"), self._subtitleData, self) self.pages = QStackedWidget(self) rightLayout.addWidget(self.pages, 0, 0) self.tabBar.addTab(self._mainTab.name) self.pages.addWidget(self._mainTab) self.splitter.addWidget(self._toolbox) self.splitter.addWidget(self.rightWidget) self.__drawSplitterHandle(1) # Setting widgets mainLayout.addWidget(self.tabBar) mainLayout.addWidget(self.splitter) # Widgets settings self.tabBar.setMovable(True) self.tabBar.setTabsClosable(True) self.tabBar.setExpanding(False) # Don't resize left panel if it's not needed leftWidgetIndex = self.splitter.indexOf(self._toolbox) rightWidgetIndex = self.splitter.indexOf(self.rightWidget) self.splitter.setStretchFactor(leftWidgetIndex, 0) self.splitter.setStretchFactor(rightWidgetIndex, 1) self.splitter.setCollapsible(leftWidgetIndex, False) self.splitter.setSizes([250]) # Some signals self.tabBar.currentChanged.connect(self.showTab) self.tabBar.tabCloseRequested.connect(self.closeTab) self.tabBar.tabMoved.connect(self.moveTab) self._mainTab.requestOpen.connect(self.openTab) self._mainTab.requestRemove.connect(self.removeFile) self.tabChanged.connect(lambda i: self._toolbox.setContentFor(self.tab(i))) self.setLayout(mainLayout) def __addTab(self, filePath): """Returns existing tab index. Creates a new one if it isn't opened and returns its index otherwise.""" for i in range(self.tabBar.count()): widget = self.pages.widget(i) if not widget.isStatic and filePath == widget.filePath: return i tab = SubtitleEditor(filePath, self._subtitleData, self) newIndex = self.tabBar.addTab(self._createTabName(tab.name, tab.history.isClean())) tab.history.cleanChanged.connect( lambda clean: self._cleanStateForFileChanged(filePath, clean)) self.pages.addWidget(tab) return newIndex def __drawSplitterHandle(self, index): splitterHandle = self.splitter.handle(index) splitterLayout = QVBoxLayout(splitterHandle) splitterLayout.setSpacing(0) splitterLayout.setContentsMargins(0, 0, 0, 0) line = QFrame(splitterHandle) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) splitterLayout.addWidget(line) splitterHandle.setLayout(splitterLayout) def _createTabName(self, name, cleanState): if cleanState is True: return name else: return "%s +" % name def _cleanStateForFileChanged(self, filePath, cleanState): page = self.tabByPath(filePath) if page is not None: for i in range(self.tabBar.count()): if self.tabBar.tabText(i)[:len(page.name)] == page.name: self.tabBar.setTabText(i, self._createTabName(page.name, cleanState)) return def saveWidgetState(self, settings): settings.setState(self.splitter, self.splitter.saveState()) settings.setHidden(self._toolbox, self._toolbox.isHidden()) def restoreWidgetState(self, settings): self.showPanel(not settings.getHidden(self._toolbox)) splitterState = settings.getState(self.splitter) if not splitterState.isEmpty(): self.splitter.restoreState(settings.getState(self.splitter)) @pyqtSlot(str, bool) def openTab(self, filePath, background=False): if self._subtitleData.fileExists(filePath): tabIndex = self.__addTab(filePath) if background is False: self.showTab(tabIndex) else: log.error(_("SubtitleEditor not created for %s!" % filePath)) @pyqtSlot(str) def removeFile(self, filePath): tab = self.tabByPath(filePath) command = RemoveFile(filePath) if tab is not None: index = self.pages.indexOf(tab) if self.closeTab(index): self._subtitleData.execute(command) else: self._subtitleData.execute(command) @pyqtSlot(int) def closeTab(self, index): tab = self.tab(index) if tab.canClose(): widgetToRemove = self.pages.widget(index) self.tabBar.removeTab(index) self.pages.removeWidget(widgetToRemove) widgetToRemove.deleteLater() return True return False def count(self): return self.tabBar.count() def currentIndex(self): return self.tabBar.currentIndex() def currentPage(self): return self.pages.currentWidget() @pyqtSlot(int, int) def moveTab(self, fromIndex, toIndex): fromWidget = self.pages.widget(fromIndex) toWidget = self.pages.widget(toIndex) if fromWidget.isStatic or toWidget.isStatic: self.tabBar.blockSignals(True) # signals would cause infinite recursion self.tabBar.moveTab(toIndex, fromIndex) self.tabBar.blockSignals(False) return else: self.pages.removeWidget(fromWidget) self.pages.removeWidget(toWidget) if fromIndex < toIndex: self.pages.insertWidget(fromIndex, toWidget) self.pages.insertWidget(toIndex, fromWidget) else: self.pages.insertWidget(toIndex, fromWidget) self.pages.insertWidget(fromIndex, toWidget) # Hack # Qt changes tabs during mouse drag and dropping. The next line is added # to prevent it. self.showTab(self.tabBar.currentIndex()) @pyqtSlot(int) def showTab(self, index): showWidget = self.pages.widget(index) if showWidget: self.pages.setCurrentWidget(showWidget) self.tabBar.blockSignals(True) self.tabBar.setCurrentIndex(index) self.tabBar.blockSignals(False) # Try to update current tab. showWidget.updateTab() self._tabChanged.emit(index) def showPanel(self, val): if val is True: self._toolbox.show() else: self._toolbox.hide() def togglePanel(self): if self._toolbox.isHidden(): self._toolbox.show() else: self._toolbox.hide() def tab(self, index): return self.pages.widget(index) def tabByPath(self, path): for i in range(self.pages.count()): page = self.tab(i) if not page.isStatic and page.filePath == path: return page return None @property def fileList(self): return self._mainTab
class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.label3 = QtWidgets.QLabel() self.label3.setGeometry(QtCore.QRect(10, 210, 500, 23)) self.label3.setObjectName("label3") self.btn_Action = QtWidgets.QPushButton() self.btn_Action.setGeometry(QtCore.QRect(220, 200, 75, 23)) self.btn_Action.setObjectName("btn_Action") self.gridLayout3 = QtWidgets.QGridLayout() self.gridLayout3.addWidget(self.label3, 0, 3, 7, 8) self.gridLayout3.addWidget(self.btn_Action, 0, 3, 3, 3) self.btn_Action.setText("View Chart") self.label3.setText('File Uploaded, check console for its contents') self.stacked_widget = QStackedWidget() self.stacked_widget.currentChanged.connect(self.set_button_state) self.btn_Action.clicked.connect(self.next_page) widget = QtWidgets.QWidget() self.setCentralWidget(widget) hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.btn_Action) vbox = QVBoxLayout() vbox.addWidget(self.stacked_widget) vbox.addLayout(hbox) #add the to the main window self.toolbar = QToolBar("Edit", self) h = HomeScreen(self) h.pushButton.clicked.connect(self.file_open) self.insert_page(h.centralwidget) self.addToolBar(self.toolbar) #start with the toolbar hidden self.toolbar.toggleViewAction().setChecked(True) self.toolbar.toggleViewAction().trigger() # create main layout widget.setLayout(vbox) def file_open(self): name, _ = QtWidgets.QFileDialog.getOpenFileName( None, 'Open File', options=QtWidgets.QFileDialog.DontUseNativeDialog) classObj = FileOpen.openFile(name) #print(classObj) #chart = Chart('pie1', classObj, self) #self.insert_page(chart.chartview) navigation = Navigation(classObj, self) #self.addToolBar(navigation.toolbar) self.insert_page(navigation.horizontalGroupBox) #chart = Chart('pie1', classObj, self) '''name, _ = QtWidgets.QFileDialog.getOpenFileName(None, 'Open File', options=QtWidgets.QFileDialog.DontUseNativeDialog) file = open(name, 'r') with file as json_file: text = json.load(json_file) #self.label3.setText('File Uploaded, check console for its contents') #chart = Chart('Alloys', text, self) #self.insert_page(chart.chartview) navigation = Navigation(text, self) self.addToolBar(navigation.toolbar) self.insert_page(navigation.horizontalGroupBox)''' def set_button_state(self, index): #self.prev_button.setEnabled(index > 0) n_pages = len(self.stacked_widget) self.btn_Action.setEnabled(index % n_pages < n_pages - 1) def insert_page(self, widget, index=-1): self.stacked_widget.insertWidget(index, widget) self.set_button_state(self.stacked_widget.currentIndex()) def next_page(self): new_index = self.stacked_widget.currentIndex() + 1 if new_index < len(self.stacked_widget): self.stacked_widget.setCurrentIndex(new_index) self.toolbar.toggleViewAction().trigger()
class TabBarWindow(TabWindow): """Implementation which uses a separate QTabBar and QStackedWidget. The Tab bar is placed next to the menu bar to save real estate.""" def __init__(self, app, **kwargs): super().__init__(app, **kwargs) def _setupUi(self): self.setWindowTitle(self.app.NAME) self.resize(640, 480) self.tabBar = QTabBar() self.verticalLayout = QVBoxLayout() self.verticalLayout.setContentsMargins(0, 0, 0, 0) self._setupActions() self._setupMenu() self.centralWidget = QWidget(self) self.setCentralWidget(self.centralWidget) self.stackedWidget = QStackedWidget() self.centralWidget.setLayout(self.verticalLayout) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.addWidget(self.menubar, 0, Qt.AlignTop) self.horizontalLayout.addWidget(self.tabBar, 0, Qt.AlignTop) self.verticalLayout.addLayout(self.horizontalLayout) self.verticalLayout.addWidget(self.stackedWidget) self.tabBar.currentChanged.connect(self.showWidget) self.tabBar.tabCloseRequested.connect(self.onTabCloseRequested) self.stackedWidget.currentChanged.connect(self.updateMenuBar) self.stackedWidget.widgetRemoved.connect(self.onRemovedWidget) self.tabBar.setTabsClosable(True) self.restoreGeometry() def addTab(self, page, title, switch=True): stack_index = self.stackedWidget.insertWidget(-1, page) tab_index = self.tabBar.addTab(title) if isinstance(page, DirectoriesDialog): self.tabBar.setTabButton(tab_index, QTabBar.RightSide, None) if switch: # switch to the added tab immediately upon creation self.setTabIndex(tab_index) self.stackedWidget.setCurrentWidget(page) return stack_index @pyqtSlot(int) def showWidget(self, index): if index >= 0 and index <= self.stackedWidget.count() - 1: self.stackedWidget.setCurrentIndex(index) # if not self.tabBar.isTabVisible(index): self.setTabVisible(index, True) def indexOfWidget(self, widget): # Warning: this may return -1 if widget is not a child of stackedwidget return self.stackedWidget.indexOf(widget) def setCurrentIndex(self, tab_index): # The signal will handle switching the stackwidget's widget self.setTabIndex(tab_index) # self.stackedWidget.setCurrentWidget(self.stackedWidget.widget(tab_index)) @pyqtSlot(int) def setTabIndex(self, index): if index is None: return self.tabBar.setCurrentIndex(index) def setTabVisible(self, index, value): return self.tabBar.setTabVisible(index, value) @pyqtSlot(int) def onRemovedWidget(self, index): self.removeTab(index) @pyqtSlot(int) def removeTab(self, index): # No need to remove the widget here: # self.stackedWidget.removeWidget(self.stackedWidget.widget(index)) return self.tabBar.removeTab(index) @pyqtSlot(int) def removeWidget(self, widget): return self.stackedWidget.removeWidget(widget) def isTabVisible(self, index): return self.tabBar.isTabVisible(index) def getCurrentIndex(self): return self.stackedWidget.currentIndex() def getWidgetAtIndex(self, index): return self.stackedWidget.widget(index) def getCount(self): return self.stackedWidget.count() @pyqtSlot() def toggleTabBar(self): value = self.sender().isChecked() self.actionToggleTabs.setChecked(value) self.tabBar.setVisible(value) @pyqtSlot(int) def onTabCloseRequested(self, index): current_widget = self.getWidgetAtIndex(index) if isinstance(current_widget, DirectoriesDialog): # On MacOS, the tab has a close button even though we explicitely # set it to None in order to hide it. This should prevent # the "Directories" tab from closing by mistake. return current_widget.close() self.stackedWidget.removeWidget(current_widget)
class MainWindow(QWidget, app_ui): global_vars = {} def __init__(self, parent=None): super(MainWindow, self).__init__(parent) QWidget.__init__(self) self.setupUi(self) self.def_setup = MainWindowSettings(self) self.def_setup.init_setup() self.def_setup.small_size() self.ClearSessionAction = QAction("Clear session", self, shortcut="Ctrl+W", triggered=self.reset_input) self.input.addAction(self.ClearSessionAction) self.stackedWidget = QStackedWidget() self.main_grid_layout.addWidget(self.stackedWidget) self.setWindowIcon(QIcon(base_dir + "icons/logo.png")) self.exts = {} self.count = 0 self.set_plugins() # search and get all plugins information # self.set_plugins_widgets() # for set all plugins self.input.textChanged.connect(self.set_plugin) self.input.textChanged.connect(self.search_plugin) # self.input.returnPressed.connect(self.command_manager) self.createActions() self.createTrayIcon() self.trayIcon.show() self.set_input_focus() def set_plugins(self): for d in glob(base_dir + "exts/*.ext/package.json"): script = self.get_json_value(d, "script", "main.py") path = os.path.dirname(d) + "/" + script kw = str(self.get_json_value(d, "key_word")).strip() if (kw and script and path): self.exts.update({ kw: (self.count, _pkg.Import(path).Plugin, os.path.dirname(d) + "/") }) self.count += 1 def get_json_value(self, _file: str, key: str, value: str = ""): return json.load(open(str(_file))).get(key.lower(), value) def set_plugin(self, text: str): kw = text.rstrip(":").strip() is_ext = text.endswith(":") if is_ext and kw in ("end", "clear", "cls"): self.def_setup.small_size() self.reset_input() self.input.addAction(self.ClearSessionAction) elif is_ext and kw in ("exit", "quit"): self.close() self.input.clear() elif is_ext and kw in ("update", "reload"): self.set_plugins() self.input.clear() elif is_ext and kw in list(self.exts.keys()): self.run_plugin(kw) def reset_input(self): ## delete last input self.gridLayout_2.removeWidget(self.input) self.input.deleteLater() ## get new input line without any event self.set_new_line() ## default setup for line input self.def_setup.remove_session() self.set_input_focus() def set_new_line(self): ## create line edit by object name input self.input = QLineEdit(self) self.input.setObjectName("input") ## add line to layout self.gridLayout_2.addWidget(self.input, 0, 1, 1, 1) ## set default setup for line self.def_setup.input_setup() ## connects functions # self.input.returnPressed.connect(self.command_manager) self.input.textChanged.connect(self.search_plugin) self.input.textChanged.connect(self.set_plugin) def set_plugins_widgets(self): for _, v in self.exts.items(): self.stackedWidget.addWidget(v[1](self.input)) def set_widget_by_name(self, name: str = ""): self.stackedWidget.setCurrentIndex(self.exts[name][0]) def get_ext_value(self, ext: str, key: str = "", value: str = ""): root_path = self.exts[ext][2] return self.get_json_value(root_path + "package.json", key, value), root_path def search_plugin(self, text: str): kw = text.rstrip(":").strip() is_ext = text.endswith(":") if is_ext and kw in list(self.exts.keys()): self.run_plugin(kw) def run_plugin(self, key_word: str): path = self.exts[key_word][2] icon = QIcon(path + self.get_ext_value(key_word, "icon")[0]) self.input.clear() self.input.setPlaceholderText(f"Session: {key_word}") self.btn_ext.setText(key_word) self.btn_ext.setIcon(icon) control = Controls(self) self.stackedWidget.insertWidget( 0, self.exts[key_word][1](self.input, _pkg, control)) self.stackedWidget.setCurrentIndex(self.exts[key_word][0]) self.def_setup.larg_size() self.set_input_focus() def createActions(self): self.hideAction = QAction("H&ide/S&how", self, shortcut="Alt+Space", triggered=self.check_win) self.quitAction = QAction(_pkg.get_sys_icon("application-exit"), "&Quit", self, triggered=QApplication.instance().quit) # self.showAction = QAction("S&how", self, shortcut="Alt+K", triggered=self.check_win) def check_win(self): if self.isHidden(): self.show() else: self.hide() def set_input_focus(self): self.input_frame.setFocus() self.input.setFocus() def createTrayIcon(self): self.trayIconMenu = QMenu(self) self.trayIconMenu.addAction(self.hideAction) self.trayIconMenu.addAction(self.quitAction) # self.trayIconMenu.addAction(self.showAction) self.trayIcon = QSystemTrayIcon(_pkg.icon_path("logo.png", True)) self.trayIcon.setContextMenu(self.trayIconMenu) self.trayIcon.activated.connect(self.check_win) def showMessage(self, title: str, body: str, icon: int = 1, limit: int = 5): tray = QSystemTrayIcon(_pkg.icon_path("logo.png", True)) icon_ = tray.MessageIcon(icon) tray.showMessage(title, body, icon_, limit * 2000) tray.show()
class Window(QMainWindow): def __init__(self): super().__init__() self.stack = QStackedWidget(self) self.user = None # Instantiate frames for different pages self.main_menu = MenuFrame(self) self.game_frame = GameFrame(self) self.profile_frame = ProfileFrame(self) self.register_frame = RegisterFrame(self) self.login_frame = LoginFrame(self) # Insert frames into a stack self.stack.insertWidget(0, self.main_menu) self.stack.insertWidget(1, self.game_frame) self.stack.insertWidget(2, self.profile_frame) self.stack.insertWidget(3, self.register_frame) self.stack.insertWidget(4, self.login_frame) # Set current frame to main menu self.stack.setCurrentIndex(0) # Set window details self.setCentralWidget(self.stack) self.setWindowTitle("Chess") self.setWindowIcon(QIcon('./assets/icons/pawn_icon.png')) self.setMinimumSize(1200, 900) self.show() def closeEvent(self, event): if self.user: update_user(self.user) # On close, update user wins/losses/draws if self.stack.currentIndex( ) == 1 and not self.game_frame.board.saved: save_prompt = QMessageBox() save_prompt.setWindowIcon( QIcon('./assets/icons/pawn_icon.png')) save_prompt.setIcon(QMessageBox.Warning) save_prompt.setWindowTitle("Chess") save_prompt.setText("Your current progress will be lost.") save_prompt.setInformativeText("Do you want to save the game?") save_prompt.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) save_prompt.setDefaultButton(QMessageBox.Save) save_prompt.button(QMessageBox.Discard).setText("Don't Save") option = save_prompt.exec_() # Save if option == QMessageBox.Save: self.game_frame.board.save() event.accept() # Don't save elif option == QMessageBox.Discard: event.accept() # Cancel else: event.ignore() def sign_in(self, user): self.user = user self.main_menu.name_label.setText(user.username) self.main_menu.bottom_left_stack.setCurrentIndex(1) self.main_menu.bottom_right_stack.setCurrentIndex(1) def sign_out(self): self.user = None self.main_menu.bottom_left_stack.setCurrentIndex(0) self.main_menu.bottom_right_stack.setCurrentIndex(0)
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowTitle("") self.screens_config = [] self.current_screen = 0 self.sub_screens = {} self.button = {} self.central_widget = QStackedWidget() self.number_of_subs = 0 self.main_layout = QGridLayout() self.gui_element_builder = GuiElementsBuilder() def say_hello(self): print("Button clicked, Hello!") def set_central_widget2(self, widget: QWidget): source_button = self.sender() print("set_central_widget2 WidgetName: " + widget.getName()) index = self.central_widget.widget(widget) self.central_widget.setCurrentIndex(index) def set_central_widget(self): source_button = self.sender() for i in range(0, self.number_of_subs): if self.central_widget.widget(i).getName() == source_button.text(): self.central_widget.setCurrentIndex(i) def change_widget(self, widget: QWidget, direction: int): #print("len: " + str(len(self.screens_config["sub"]))) max_screen = len(self.screens_config["sub"]) if direction == 0: self.central_widget.setCurrentIndex( (self.central_widget.currentIndex() - 1) % max_screen) #self.current_screen = (self.current_screen + 1) % max_screen elif direction == 1: self.central_widget.setCurrentIndex( (self.central_widget.currentIndex() + 1) % max_screen) #self.current_screen = (self.current_screen - 1) % max_screen else: print("that not a valid direction") #Farbe sollte im Widget selbst geetzt werden bzw. schon bei Erstellung #for items in self.screens_config['sub']: #b = QColor(self.screens_config['sub'][self.current_screen]["Background"]) #b = QColor(self.screens_config['sub'][self.central_widget.currentIndex()]["Background"]) #p = self.central_widget.palette() #p.setColor(self.central_widget.backgroundRole(), b) #self.central_widget.setPalette(p) #self.central_widget.setAutoFillBackground(True) def init_with_config(self, config: dict): self.screens_config = config # TODO: put in delegation or inheritance #Set Title if 'name' not in config: title = str(config['main']['name']) self.setWindowTitle(title) # Set Resolution window_width = config['main']["resolution"][0] window_height = config['main']["resolution"][1] button_width = config['main']["button-size"][0] button_height = config['main']["button-size"][1] self.number_of_subs = len(config['sub']) else: title = str(config['name']) self.setWindowTitle(title) # Set Resolution window_width = config["resolution"][0] window_height = config["resolution"][1] button_width = config["button-size"][0] button_height = config["button-size"][1] self.number_of_subs = len(self.screens_config["sub"]) self.setFixedSize(window_width, window_height) main_widget = QWidget() main_widget.setLayout(self.main_layout) vbox_menu = QVBoxLayout() vbox_menu.setSizeConstraint(QLayout.SetFixedSize) system_color = "#ffd966" # Header self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.TOP_LEFT, 0, 0), 0, 0) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 30, 650), 0, 1, Qt.AlignTop) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 0, 0), 0, 3, Qt.AlignTop) # Menu self.main_layout.addLayout(vbox_menu, 1, 0) # Footer self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.BOTTOM_LEFT, 0, 0), 2, 0) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 30, 650), 2, 1, Qt.AlignBottom) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 0, 0), 2, 3, Qt.AlignBottom) # button_stylesheet = "background-color:" + system_color +"; border-width: 2px; border-radius: 36px; bordericolor: black; font: bold 14px; min-width: 10em; padding: 6px;" # button_up = QPushButton("\u1403") # button_up.setFixedSize(button_width * window_width/100, button_height * window_height/100) # button_up.setStyleSheet(button_stylesheet) # # button_down = QPushButton("\u1401") # button_down.setFixedSize(button_width * window_width / 100, button_height * window_height / 100) # button_down.setStyleSheet(button_stylesheet) button_ListWidget = QListWidget() button_ListWidget.setStyleSheet( """QListWidget{background: #f2eeed; border: 0px solid #f2eeed;}""" ) # Erstellen der rechten Button-Leiste ############## #vbox_menu.addWidget(button_up) button_width = button_width * window_width / 100 button_height = button_height * window_height / 100 background_color = "#f2eeed" button_size = QSize(button_width, button_height) for i in range(0, self.number_of_subs): subbutton_list_item = QListWidgetItem(button_ListWidget) placeholder_listItem = QListWidgetItem(button_ListWidget) placeholder_listItem.setSizeHint(QSize(button_width, 4)) flag = placeholder_listItem.flags() & Qt.ItemIsUserCheckable placeholder_listItem.setFlags(flag) #subbutton_listItem.setBackground(QColor("#f2eeed")) # Widgets ################################################################################################## if i == 0: self.central_widget.insertWidget(i, Clock()) else: self.central_widget.insertWidget( i, Placeholder(self.screens_config["sub"][i]["name"])) # Buttons ################################################################################################## button_color = self.screens_config['sub'][i]["Background"] self.button[i] = QPushButton(self.screens_config["sub"][i]["name"], self) self.button[i].setFixedSize(button_size) #Button with stylsheet #self.button[i].setStyleSheet("background-color:" +button_color +"; border-width: 2px; border-radius: 10px; bordericolor: black; font: bold 14px; min-width: 10em; padding: 6px;") path_button = Button_full.build_svg( Button_full( button_width, button_height, background_color, self.screens_config["sub"][i]["Background"] + "_button")) self.button[i].setStyleSheet("background-image: url(" + path_button + ");" "border:1px; background-color:" + button_color + ";") #print("Button: " + self.button[i].text() + "Screen: " + self.central_widget.widget(i).getName()) # signals ################################################################################################## #self.button[i].clicked.connect(lambda widget=self.central_widget.widget(i): self.set_central_widget2(self, widget)) self.button[i].clicked.connect( lambda widget=self.central_widget.widget( i): self.set_central_widget()) subbutton_list_item.setSizeHint(button_size) #print(self.button[i].size()) # button_ListWidget.addItem(placeholder_listItem) button_ListWidget.addItem(subbutton_list_item) button_ListWidget.setItemWidget(subbutton_list_item, self.button[i]) button_ListWidget.setMaximumWidth(1000) #vbox_menu.addWidget(self.button[i]) vbox_menu.addWidget(button_ListWidget) #vbox_menu.addWidget(button_down) #downbutton_listItem = QListWidgetItem(button_ListWidget) #downbutton_listItem.setSizeHint(button_down.size()) #button_ListWidget.addItem(downbutton_listItem) #button_ListWidget.setItemWidget(downbutton_listItem, button_down) button_ListWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) button_ListWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) button_ListWidget.setMaximumWidth( button_ListWidget.sizeHintForColumn(0)) ############################################# self.central_widget.setCurrentIndex(1) self.main_layout.addWidget(self.central_widget, 1, 1) self.setCentralWidget(main_widget)
class MenuFrame(QFrame): def __init__(self, parent): super().__init__() self.parent = parent self.setStyleSheet('background-color: #4B4945') menu_img = MenuImage() img_widget = QWidget() # Horizontal box layout used to add space to both sides of the image img_layout = QHBoxLayout() img_layout.addStretch(1) img_layout.addWidget(menu_img, 2) img_layout.addStretch(1) img_widget.setLayout(img_layout) new_game_btn = MenuButton() new_game_btn.setText("New Game") new_game_btn.clicked.connect(self.open_dialog) load_game_btn = MenuButton() load_game_btn.setText("Load Game") load_game_btn.clicked.connect(lambda: self.open_dialog(True)) profile_btn = MenuButton() profile_btn.setText("Profile") profile_btn.clicked.connect(self.profile_page) exit_btn = MenuButton() exit_btn.setText("Exit") exit_btn.clicked.connect(self.exit) button_widget = QWidget() # Vertical box layout used to hold the image widget and buttons button_layout = QVBoxLayout() button_layout.addWidget(img_widget, 2) button_layout.addWidget(new_game_btn, 1) button_layout.addWidget(load_game_btn, 1) button_layout.addWidget(profile_btn, 1) button_layout.addWidget(exit_btn, 1) button_widget.setLayout(button_layout) register_btn = MenuButton() register_btn.setText("Register") register_btn.clicked.connect(self.register_page) login_btn = MenuButton() login_btn.setText("Log In") login_btn.clicked.connect(self.login_page) self.name_label = MenuLabel() logout_btn = MenuButton() logout_btn.setText("Sign out") logout_btn.clicked.connect(self.parent.sign_out) self.bottom_left_stack = QStackedWidget() self.bottom_left_stack.insertWidget(0, register_btn) self.bottom_left_stack.insertWidget(1, self.name_label) self.bottom_left_stack.setCurrentIndex(0) self.bottom_right_stack = QStackedWidget() self.bottom_right_stack.insertWidget(0, login_btn) self.bottom_right_stack.insertWidget(1, logout_btn) self.bottom_right_stack.setCurrentIndex(0) register_widget = QWidget() # Vertical box layout used to position the register button register_layout = QVBoxLayout() register_layout.addStretch(15) register_layout.addWidget(self.bottom_left_stack, 1) register_widget.setLayout(register_layout) login_widget = QWidget() # Vertical box layout used to position the login button login_layout = QVBoxLayout() login_layout.addStretch(15) login_layout.addWidget(self.bottom_right_stack, 1) login_widget.setLayout(login_layout) # Horizontal box layout used to add space to both sides of the image widget and buttons menu_layout = QHBoxLayout() menu_layout.addWidget(register_widget, 1) menu_layout.addStretch(1) menu_layout.addWidget(button_widget, 2) menu_layout.addStretch(1) menu_layout.addWidget(login_widget, 1) self.setLayout(menu_layout) def open_dialog(self, load_game=False): if load_game: if not self.parent.user or not self.parent.user.saved_game: return target_func = self.load_game else: target_func = self.new_game bold_font = QFont() bold_font.setBold(True) menu = QDialog() menu.setWindowIcon(QIcon('./assets/icons/pawn_icon.png')) menu.setWindowTitle("Chess") menu.setStyleSheet('background-color: #4B4945') white_btn = MenuButton() white_btn.setText("White") white_btn.clicked.connect(menu.accept) black_btn = MenuButton() black_btn.setText("Black") black_btn.clicked.connect(menu.accept) player_btn_widget = QWidget() player_btn_layout = QHBoxLayout() player_btn_layout.addWidget(white_btn) player_btn_layout.addWidget(black_btn) player_btn_widget.setLayout(player_btn_layout) computer_btn = MenuButton(font_scale=40) computer_btn.setText("Computer vs Computer") computer_btn.clicked.connect(menu.accept) computer_btn_widget = QWidget() computer_btn_layout = QHBoxLayout() computer_btn_layout.addWidget(computer_btn) computer_btn_widget.setLayout(computer_btn_layout) slider_label = MenuLabel(font_scale=35) slider_label.setText("Difficulty") slider = QSlider(Qt.Horizontal) slider.setMinimum(1) slider.setMaximum(5) slider.setTickInterval(1) slider.setTickPosition(QSlider.TicksBothSides) slider.setStyleSheet( 'QSlider::handle:horizontal {background-color: #E6912C}' 'QSlider::handle:horizontal:hover {background-color: #D37E19}') checkbox = QCheckBox() checkbox.setText("Enable autosave") checkbox.setFont(bold_font) checkbox.setStyleSheet('QCheckBox {color: #E6912C}') white_btn.clicked.connect(lambda: target_func('w', slider.value( ), checkbox.isChecked(), False)) black_btn.clicked.connect(lambda: target_func('b', slider.value( ), checkbox.isChecked(), False)) computer_btn.clicked.connect(lambda: target_func( None, slider.value(), checkbox.isChecked(), True)) layout = QVBoxLayout() layout.addWidget(player_btn_widget) layout.addWidget(computer_btn_widget) layout.addWidget(slider_label) layout.addWidget(slider) if self.parent.user: layout.addSpacing(40) layout.addWidget(checkbox) layout.setSpacing(0) menu.setLayout(layout) menu.exec_() def new_game(self, colour, difficulty, autosave, self_play): self.parent.game_frame.info.move_frame.clear_moves() self.parent.game_frame.board.set_fen(common.starting_fen) self.parent.game_frame.board.user_is_white = True if colour == 'w' else False self.parent.game_frame.board.self_play = self_play self.parent.game_frame.board.difficulty = difficulty self.parent.game_frame.board.autosave = autosave self.parent.game_frame.board.start_game() self.parent.stack.setCurrentIndex(1) def load_game(self, colour, difficulty, autosave, self_play): self.parent.game_frame.board.set_position( copy.deepcopy(self.parent.user.saved_game)) self.parent.game_frame.board.saved = True self.parent.game_frame.info.move_frame.update_moves() self.parent.game_frame.board.user_is_white = True if colour == 'w' else False self.parent.game_frame.board.self_play = self_play self.parent.game_frame.board.difficulty = difficulty self.parent.game_frame.board.autosave = autosave self.parent.game_frame.board.start_game() self.parent.stack.setCurrentIndex(1) def profile_page(self): if self.parent.user: self.parent.profile_frame.update() self.parent.stack.setCurrentIndex(2) def exit(self): self.parent.close() def register_page(self): self.parent.stack.setCurrentIndex(3) def login_page(self): self.parent.stack.setCurrentIndex(4)
class ComprehensionTestApp(QMainWindow): """ @modifies self.symbol_test, self.question1, self.question2 @effects makes a new ComprehensionTestApp """ def __init__(self): super().__init__() self.symbol_tests = QStackedWidget() self.question1 = "Exactly what do you think this symbol means?" self.question2 = "What action would you take in response to this symbol?" self.init_gui() """ @modifies self @effects sets up the main window """ def init_gui(self): exitAct = QAction('&Exit', self) exitAct.setShortcut('Ctrl+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(self.quit) saveAct = QAction('&Save as PDF', self) saveAct.setShortcut('Ctrl+S') saveAct.setStatusTip('Saves as PDF') saveAct.triggered.connect(self.save_as_pdf) importAct = QAction('&Import symbols', self) importAct.setShortcut('Ctrl+I') importAct.setStatusTip( 'Imports all the specified images on to their own test page') importAct.triggered.connect(self.import_symbols) menu_bar = self.menuBar() filemenu = menu_bar.addMenu('&File') filemenu.addAction(importAct) filemenu.addAction(saveAct) filemenu.addAction(exitAct) goToAct = QAction('&Go to page', self) goToAct.setStatusTip('Go to the specified page') goToAct.setShortcut('Ctrl+G') goToAct.triggered.connect(self.go_to_page) newQuestAct = QAction('&Change default questions', self) newQuestAct.setStatusTip( 'Changes the default questions asked about the symbol') newQuestAct.setShortcut('Ctrl+H') newQuestAct.triggered.connect(self.change_questions) moveLeftAct = QAction('&Move current page left', self) moveLeftAct.setShortcut('Ctrl+,') moveLeftAct.setStatusTip('Moves the current page one page to the left') moveLeftAct.triggered.connect(self.move_test_left) moveRightAct = QAction('&Move current page right', self) moveRightAct.setShortcut('Ctrl+.') moveRightAct.setStatusTip( 'Moves the current page one page to the right') moveRightAct.triggered.connect(self.move_test_right) moveToAct = QAction('Move current page to', self) moveToAct.setShortcut('Ctrl+M') moveToAct.setStatusTip('Moves the current page to the specified page') moveToAct.triggered.connect(self.move_to_page) delPagesAct = QAction('Delete pages', self) delPagesAct.setShortcut('Ctrl+D') delPagesAct.setStatusTip('Deletes the specified pages') delPagesAct.triggered.connect(self.delete_pages) editmenu = menu_bar.addMenu('&Edit') editmenu.addAction(delPagesAct) editmenu.addAction(newQuestAct) editmenu.addAction(goToAct) editmenu.addAction(moveLeftAct) editmenu.addAction(moveRightAct) editmenu.addAction(moveToAct) nextAct = QAction(QIcon("next.png"), 'Next page (Ctrl+P)', self) nextAct.setShortcut('Ctrl+P') nextAct.setStatusTip('Goes to the next page') nextAct.triggered.connect(self.next_page) prevAct = QAction(QIcon("prev.png"), "Previous page (Ctrl+O)", self) prevAct.setShortcut('Ctrl+O') prevAct.setStatusTip('Goes to the previous page') prevAct.triggered.connect(self.prev_page) newAct = QAction(QIcon("add.png"), "Add a new page (Ctrl+N)", self) newAct.setShortcut('Ctrl+N') newAct.setStatusTip('Creates a new page') newAct.triggered.connect(self.add_blank_test) remAct = QAction(QIcon("remove.png"), "Delete page (Ctrl+R)", self) remAct.setShortcut('Ctrl+R') remAct.setStatusTip('Deletes the current page') remAct.triggered.connect(self.delete_test) tool_bar = self.addToolBar("Next Page") tool_bar.addAction(prevAct) tool_bar.addAction(nextAct) tool_bar.addAction(newAct) tool_bar.addAction(remAct) self.setWindowTitle("Open Comprehension Test Generator") self.setWindowIcon(QIcon("rubber ducky.png")) self.setGeometry(500, 500, 500, 450) self.add_blank_test() self.setCentralWidget(self.symbol_tests) self.show() """ @modifies none @effects confirms if the user wishes to exit """ def closeEvent(self, event): msg = QMessageBox.question(self, 'Message', "Really quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if msg == QMessageBox.Yes: event.accept() else: event.ignore() """ @modifies none @effects confirms if the user wishes to exit """ def quit(self): msg = QMessageBox.question(self, 'Message', "Really quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if msg == QMessageBox.Yes: qApp.quit() """ @modifies self.symbol_tests @effects adds a blank symbol_test to the end of symbol_tests sets the current symbol_test to the new one """ def add_blank_test(self): page = self.symbol_tests.count() + 1 test = SymbolTestWidget( self, comp_questions=[self.question1, self.question2], pageNumber=page, pageTotal=page) test.set_visual_context("blank image.png") self.symbol_tests.addWidget(test) self.symbol_tests.setCurrentIndex(page - 1) for i in range(0, self.symbol_tests.count() - 1): self.symbol_tests.widget(i).set_numPages(self.symbol_tests.count()) """ @modifies self.symbol_tests @effects changes the current symbol_test to the next one """ def next_page(self): if self.symbol_tests.currentIndex() < self.symbol_tests.count() - 1: self.symbol_tests.setCurrentIndex( self.symbol_tests.currentIndex() + 1) """ @modifies self.symbol_test @effects changes the current symbol_test to the previous one """ def prev_page(self): if self.symbol_tests.currentIndex() > 0: self.symbol_tests.setCurrentIndex( self.symbol_tests.currentIndex() - 1) """ @modifies none @effects saves all the symbol_tests as seperate pages on a PDF document """ def save_as_pdf(self): filename = QFileDialog.getSaveFileName(self, 'Save to PDF', 'c:\\', "*.pdf") if filename != ('', ''): if os.path.exists(filename[0]): try: infile = PdfFileReader(filename[0], 'rb') except: error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) error.setText( "File could not be written to. If the file is currently open, try closing it" ) error.exec_() return if infile.getNumPages() == 0: print("HERE!") doc = QTextDocument() doc.print(printer) printer = QPrinter() printer.setPageSize(QPrinter.A4) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(filename[0]) painter = QPainter() font = QFont("times") font.setPointSize(12) x = painter.begin(printer) if x == False: error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) error.setText( "File could not be saved. If the file is currently open, try closing it" ) error.exec_() return painter.setFont(font) for i in range(0, self.symbol_tests.count()): cur_symbol_test = self.symbol_tests.widget(i) if cur_symbol_test.print_visual_context() == False: pixmap = cur_symbol_test.get_symbol() pixmap = pixmap.scaled(350, 350) painter.drawPixmap(30, 100, pixmap) painter.drawText(750, 20, cur_symbol_test.get_page()) painter.drawText( 420, 200, 350, 400, QtCore.Qt.TextWordWrap, "Context: " + cur_symbol_test.get_context()) painter.drawText(30, 600, cur_symbol_test.get_question1()) painter.drawText(30, 830, cur_symbol_test.get_question2()) cur_pen = painter.pen() line_pen = QPen() line_pen.setWidth(2) painter.setPen(line_pen) painter.drawLine(70, 656, 600, 656) painter.drawLine(70, 712, 600, 712) painter.drawLine(70, 768, 600, 768) painter.drawLine(70, 886, 600, 886) painter.drawLine(70, 942, 600, 942) painter.drawLine(70, 998, 600, 998) painter.setPen(cur_pen) else: pixmap = cur_symbol_test.get_visual_context() pixmap = pixmap.scaled(300, 300) painter.drawPixmap(200, 10, pixmap) pixmap = cur_symbol_test.get_symbol() pixmap = pixmap.scaled(250, 250) painter.drawPixmap(225, 320, pixmap) painter.drawText(750, 20, cur_symbol_test.get_page()) #painter.drawText(420, 200, 350, 400, QtCore.Qt.TextWordWrap, "Context: " + cur_symbol_test.get_context()) painter.drawText(30, 600, cur_symbol_test.get_question1()) painter.drawText(30, 830, cur_symbol_test.get_question2()) cur_pen = painter.pen() line_pen = QPen() line_pen.setWidth(2) painter.setPen(line_pen) painter.drawLine(70, 656, 600, 656) painter.drawLine(70, 712, 600, 712) painter.drawLine(70, 768, 600, 768) painter.drawLine(70, 886, 600, 886) painter.drawLine(70, 942, 600, 942) painter.drawLine(70, 998, 600, 998) painter.setPen(cur_pen) if (i < self.symbol_tests.count() - 1): printer.newPage() painter.end() """ @modifies self.symbol_tests @effects adds all the specified symbols to their own symbol_test and adds those tests to self.symbol_tests """ def import_symbols(self): fnames = QFileDialog.getOpenFileNames(self, 'Open file', 'c:\\', "Image files (*.jpg *.png)") if fnames != ([], ''): for i in range(0, len(fnames[0])): page = self.symbol_tests.count() + 1 test = SymbolTestWidget( self, comp_questions=[self.question1, self.question2], pageNumber=page, pageTotal=page) test.set_symbol(fnames[0][i]) test.set_visual_context("blank image.png") self.symbol_tests.addWidget(test) self.symbol_tests.setCurrentIndex(page - 1) for i in range(0, self.symbol_tests.count()): self.symbol_tests.widget(i).set_numPages( self.symbol_tests.count()) """ @modifies self.symbol_tests @effects removes the current test from self.symbol_tests """ def delete_test(self): msg = QMessageBox.question(self, 'Message', "Delete test?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if msg == QMessageBox.No: return if self.symbol_tests.currentIndex() != 0: cur_idx = self.symbol_tests.currentIndex() self.symbol_tests.setCurrentIndex(cur_idx - 1) self.symbol_tests.removeWidget(self.symbol_tests.widget(cur_idx)) for i in range(0, self.symbol_tests.count()): cur_symbol_test = self.symbol_tests.widget(i) cur_symbol_test.set_numPages(self.symbol_tests.count()) if i >= cur_idx: cur_symbol_test.set_page(i + 1) elif self.symbol_tests.currentIndex( ) == 0 and self.symbol_tests.count() > 1: self.symbol_tests.setCurrentIndex(1) self.symbol_tests.removeWidget(self.symbol_tests.widget(0)) for i in range(0, self.symbol_tests.count()): cur_symbol_test = self.symbol_tests.widget(i) cur_symbol_test.set_numPages(self.symbol_tests.count()) cur_symbol_test.set_page(i + 1) elif self.symbol_tests.currentIndex() == 0 and self.symbol_tests.count( ) == 1: page = 1 test = SymbolTestWidget( self, comp_questions=[self.question1, self.question2], pageNumber=page, pageTotal=page) self.symbol_tests.addWidget(test) self.symbol_tests.setCurrentIndex(1) self.symbol_tests.removeWidget(self.symbol_tests.widget(0)) """ @modifies self.symbol_tests @effects decreases the current symbol_test's index in self.symbol_tests by 1, moves it down 1 postion """ def move_test_left(self): cur_idx = self.symbol_tests.currentIndex() if cur_idx > 0: cur_widget = self.symbol_tests.widget(cur_idx) prev_widget = self.symbol_tests.widget(cur_idx - 1) cur_widget.set_page(int(cur_widget.get_page()) - 1) prev_widget.set_page(int(prev_widget.get_page()) + 1) self.symbol_tests.removeWidget(prev_widget) self.symbol_tests.insertWidget( self.symbol_tests.indexOf(cur_widget) + 1, prev_widget) """ @modifies self.symbol_tests @effects increases the current symbol_test's index in self.symbol_tests by 1, moves it up 1 postion """ def move_test_right(self): cur_idx = self.symbol_tests.currentIndex() if cur_idx < self.symbol_tests.count() - 1: cur_widget = self.symbol_tests.widget(cur_idx) next_widget = self.symbol_tests.widget(cur_idx + 1) cur_widget.set_page(int(cur_widget.get_page()) + 1) next_widget.set_page(int(next_widget.get_page()) - 1) self.symbol_tests.removeWidget(next_widget) self.symbol_tests.insertWidget( self.symbol_tests.indexOf(cur_widget), next_widget) """ @modifies self.symbol_tests @effects moves the current symbol_test to a specified position in self.symbol_tests """ def move_to_page(self): text = QInputDialog.getText(self, "Move Page", "Move current page to: ", QLineEdit.Normal) if text[1] != False: try: x = int(text[0]) if x <= 0 or x > self.symbol_tests.count(): error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) error.setText("Page must be between 1 and " + str(self.symbol_tests.count())) error.exec_() return cur_idx = self.symbol_tests.currentIndex() cur_widget = self.symbol_tests.widget(cur_idx) cur_widget.set_page(x - 1) self.symbol_tests.removeWidget(cur_widget) self.symbol_tests.insertWidget(x - 1, cur_widget) self.symbol_tests.setCurrentIndex(x - 1) for i in range(0, self.symbol_tests.count()): loop_widget = self.symbol_tests.widget(i) loop_widget.set_page(i + 1) except ValueError: error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) error.setText("Can only enter an integer between 1 and " + str(self.symbol_tests.count())) error.exec_() """ @modifies self.symbol_tests @effects sets the surrent symbol_test equal to the one at the specified page """ def go_to_page(self): text = QInputDialog.getText(self, "Go to", "Go to page: ", QLineEdit.Normal) if text[1] != False: try: x = int(text[0]) if x <= 0 or x > self.symbol_tests.count(): error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) error.setText("Page must be between 1 and " + str(self.symbol_tests.count())) error.exec_() return self.symbol_tests.setCurrentIndex(x - 1) except ValueError: error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) error.setText("Can only enter an integer between 1 and " + str(self.symbol_tests.count())) error.exec_() """ @modifies self.question1, self.question2 @effects changes the default questions """ def change_questions(self): text = QInputDialog.getText(self, "Question 1 Input", "Question 1: ", QLineEdit.Normal, self.question1) if str(text[0]) != '': self.question1 = str(text[0]) text = QInputDialog.getText(self, "Question 2 Input", "Question 2: ", QLineEdit.Normal, self.question2) if str(text[0]) != '': self.question2 = str(text[0]) def delete_pages(self): text = QInputDialog.getText( self, "Delete pages", "Enter page numbers seperated by a comma:", QLineEdit.Normal) error = QMessageBox() error.setIcon(QMessageBox.Warning) error.setStandardButtons(QMessageBox.Ok) if text[1] != False: pages = text[0].split(",") del_widgets = [] for page in pages: try: x = int(page) except: error.setText("All page numbers must be integers") error.exec_() return if int(page) > self.symbol_tests.count() or int(page) < 1: error.setText("Page " + page + " does not exist") error.exec_() return del_widgets.append(self.symbol_tests.widget(int(page) - 1)) confirm = QMessageBox.question( self, 'Message', "Really delete pages: " + text[0] + "?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) for del_widget in del_widgets: del_idx = self.symbol_tests.indexOf(del_widget) if del_idx != self.symbol_tests.currentIndex(): self.symbol_tests.removeWidget(del_widget) else: #Removing the only test if self.symbol_tests.count() == 1: self.add_blank_test() self.symbol_tests.removeWidget(del_widget) self.symbol_tests.currentWidget().set_page(1) self.symbol_tests.currentWidget().set_numPages(1) return else: if del_idx == self.symbol_tests.count() - 1: self.symbol_tests.setCurrentIndex(del_idx - 1) self.symbol_tests.removeWidget(del_widget) else: self.symbol_tests.setCurrentIndex(del_idx + 1) self.symbol_tests.removeWidget(del_widget) count = 1 for i in range(0, self.symbol_tests.count()): cur_widget = self.symbol_tests.widget(i) cur_widget.set_page(count) cur_widget.set_numPages(self.symbol_tests.count()) count += 1
class TabStackedWidget(QWidget): ''' @note: just some of QTabWidget's methods were implemented ''' def __init__(self, parent=None): super(TabStackedWidget, self).__init__(parent) self._stack = None # QStackedWidget self._tabBar = None # ComboTabBar self._mainLayout = None # QVBoxLayout self._dirtyTabBar = False self._currentIndex = 0 self._previousIndex = 0 self._stack = QStackedWidget(self) self._mainLayout = QVBoxLayout() self._mainLayout.setSpacing(0) self._mainLayout.setContentsMargins(0, 0, 0, 0) self._mainLayout.addWidget(self._stack) self.setLayout(self._mainLayout) self._stack.widgetRemoved.connect(self._tabWasRemoved) def tabBar(self): ''' @return: ComboTabBar ''' return self._tabBar def setTabBar(self, tb): ''' @param: ComboTabBar ''' assert (tb) if tb.parentWidget() != self: tb.setParent(self) tb.show() del self._tabBar self._dirtyTabBar = True self._tabBar = tb self.setFocusProxy(self._tabBar) self._tabBar.currentChanged.connect(self._showTab) self._tabBar.tabMoved.connect( lambda from_, to_: TabStackedWidget._tabWasMoved(self, from_, to_)) self._tabBar.overFlowChanged.connect(self.setUpLayout) if self._tabBar.tabsCloseable(): self._tabBar.tabCloseRequested.connect(self.tabCloseRequested) self.setDocumentMode(self._tabBar.documentMode()) self._tabBar.installEventFilter(self) self.setUpLayout() def documentMode(self): return self._tabBar.documentMode() def setDocumentMode(self, enabled): self._tabBar.setDocumentModel(enabled) self._tabBar.setExpanding(not enabled) self._tabBar.setDrawBase(enabled) def addTab(self, widget, label, pinned=False): ''' @return: int ''' return self.insertTab(-1, widget, label, pinned) def insertTab(self, index, widget, label, pinned=False): ''' @param: widget QWidget @param: label QString ''' if not widget: return -1 if pinned: if index < 0: index = self._tabBar.pinnedTabsCount() else: index = min(index, self._tabBar.pinnedTabsCount()) index = self._stack.insertWidget(index, widget) self._tabBar.insertTabByIconText(index, QIcon(), label, True) else: if index < 0: index = self._tabBar.pinnedTabsCount() else: index = max(index, self._tabBar.pinnedTabsCount()) index = self._stack.insertWidget(index, widget) self._tabBar.insertTabByIconText(index, QIcon(), label, False) if self._previousIndex >= index: self._previousIndex += 1 if self._currentIndex >= index: self._currentIndex += 1 QTimer.singleShot(0, self.setUpLayout) return index def tabText(self, index): return self._tabBar.tabText(index) def setTabText(self, index, label): self._tabBar.setTabText(index, label) def tabToolTip(self, index): return self._tabBar.tabToolTip(index) def setTabToolTip(self, index, tip): self._tabBar.setTabToolTip(index, tip) def pinUnPinTab(self, index, title=''): widget = self._stack.widget(index) currentWidget = self._stack.currentWidget() if not widget or not currentWidget: return -1 makePinned = index >= self._tabBar.pinnedTabsCount() button = self._tabBar.tabButton(index, self._tabBar.iconButtonPosition()) # To show tooltip of tab which is pinned in the current session toolTip = self.tabToolTip(index) self._tabBar._blockCurrentChangedSignal = True self._tabBar.setTabButton(index, self._tabBar.iconButtonPosition(), None) self._stack.removeWidget(widget) if makePinned: insertIndex = 0 else: insertIndex = self._tabBar.pinnedTabsCount() newIndex = self.insertTab(insertIndex, widget, title, makePinned) self._tabBar.setTabButton(newIndex, self._tabBar.iconButtonPosition(), button) self._tabBar._blockCurrentChangedSignal = False self.setTabToolTip(newIndex, toolTip) # Restore current widget self.setCurrentWidget(currentWidget) self.pinStateChanged.emit(newIndex, makePinned) return newIndex def removeTab(self, index): widget = self._stack.widget(index) if widget: # Select another current tab before remove, so it won't be handled # by QTabBar if index == self.currentIndex() and self.count() > 1: self._selectTabOnRemove() self._stack.removeWidget(widget) def moveTab(self, from_, to_): self._tabBar.moveTab(from_, to_) def currentIndex(self): ''' @return: int ''' return self._tabBar.currentIndex() def currentWidget(self): ''' @return: QWidget ''' return self._stack.currentWidget() def widget(self, index): ''' @return: QWidget ''' return self._stack.widget(index) def indexOf(self, widget): ''' @param: widget QWidget @return: int ''' return self._stack.indexOf(widget) def count(self): return self._tabBar.count() # Q_SIGNALS currentChanged = pyqtSignal(int) # index tabCloseRequested = pyqtSignal(int) # index pinStateChanged = pyqtSignal(int, bool) # index, pinned # public Q_SLOTS def setCurrentIndex(self, index): self._tabBar.setCurrentIndex(index) def setCurrentWidget(self, widget): ''' @widget: widget QWidget ''' self._tabBar.setCurrentIndex(self.indexOf(widget)) def setUpLayout(self): if not self._tabBar.isVisible(): self._dirtyTabBar = True return self._tabBar.setElideMode(self._tabBar.elideMode()) self._dirtyTabBar = False # private Q_SLOTS def _showTab(self, index): if self._validIndex(index): self._stack.setCurrentIndex(index) self._previousIndex = self._currentIndex self._currentIndex = index # This is slot connected to ComboTabBar::currentChanged # We must send the signal event with invalid index (-1) self.currentChanged.emit(index) def _tabWasMoved(self, from_, to_): self._stack.blockSignals(True) widget = self._stack.widget(from_) self._stack.removeWidget(widget) self._stack.insertWidget(to_, widget) self._stack.blockSignals(False) def _tabWasRemoved(self, index): if self._previousIndex == index: self._previousIndex = -1 elif self._previousIndex > index: self._previousIndex -= 1 if self._currentIndex == index: self._currentIndex = -1 elif self._currentIndex > index: self._currentIndex -= 1 self._tabBar.removeTab(index) # protected: # override def eventFilter(self, obj, event): ''' @param: obj QObject @param: event QEvent @return: bool ''' if self._dirtyTabBar and obj == self._tabBar and event.type( ) == QEvent.Show: self.setUpLayout() return False # override def keyPressEvent(self, event): ''' @param: event QKeyEvent ''' evkey = event.key() evmodifiers = event.modifiers() if evkey == Qt.Key_Tab or evkey == Qt.Key_Backtab and \ self.count() > 1 and evmodifiers & Qt.ControlModifier: pageCount = self.count() page = self.currentIndex() if (evkey == Qt.Key_Backtab) or (evmodifiers & Qt.ShiftModifier): dx = -1 else: dx = 1 for idx in range(pageCount): page += dx if page < 0: page = self.count() - 1 elif page >= pageCount: page = 0 if self._tabBar.isTabEnabled(page): self.setCurrentIndex(page) break if not QApplication.focusWidget(): self._tabBar.setFocus() else: event.ignore() # private: def _validIndex(self, index): return index < self._stack.count() and index >= 0 def _selectTabOnRemove(self): assert (self.count() > 1) index = -1 behavior = self._tabBar.selectionBehaviorOnRemove() if behavior == QTabBar.SelectPreviousTab: if self._validIndex(self._previousIndex): index = self._previousIndex # fallthrough elif behavior == QTabBar.SelectLeftTab: index = self.currentIndex() - 1 if not self._validIndex(index): index = 1 elif behavior == QTabBar.SelectRightTab: index = self.currentIndex() + 1 if not self._validIndex(index): index = self.currentIndex() - 1 assert (self._validIndex(index)) self.setCurrentIndex(index)
class E5SideBar(QWidget): """ Class implementing a sidebar with a widget area, that is hidden or shown, if the current tab is clicked again. """ Version = 1 North = 0 East = 1 South = 2 West = 3 def __init__(self, orientation=None, delay=200, parent=None): """ Constructor @param orientation orientation of the sidebar widget (North, East, South, West) @param delay value for the expand/shrink delay in milliseconds (integer) @param parent parent widget (QWidget) """ super(E5SideBar, self).__init__(parent) self.__tabBar = QTabBar() self.__tabBar.setDrawBase(True) self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setUsesScrollButtons(True) self.__tabBar.setDrawBase(False) self.__stackedWidget = QStackedWidget(self) self.__stackedWidget.setContentsMargins(0, 0, 0, 0) self.__autoHideButton = QToolButton() self.__autoHideButton.setCheckable(True) self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOff.png")) self.__autoHideButton.setChecked(True) self.__autoHideButton.setToolTip( self.tr("Deselect to activate automatic collapsing")) self.barLayout = QBoxLayout(QBoxLayout.LeftToRight) self.barLayout.setContentsMargins(0, 0, 0, 0) self.layout = QBoxLayout(QBoxLayout.TopToBottom) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.barLayout.addWidget(self.__autoHideButton) self.barLayout.addWidget(self.__tabBar) self.layout.addLayout(self.barLayout) self.layout.addWidget(self.__stackedWidget) self.setLayout(self.layout) # initialize the delay timer self.__actionMethod = None self.__delayTimer = QTimer(self) self.__delayTimer.setSingleShot(True) self.__delayTimer.setInterval(delay) self.__delayTimer.timeout.connect(self.__delayedAction) self.__minimized = False self.__minSize = 0 self.__maxSize = 0 self.__bigSize = QSize() self.splitter = None self.splitterSizes = [] self.__hasFocus = False # flag storing if this widget or any child has the focus self.__autoHide = False self.__tabBar.installEventFilter(self) self.__orientation = E5SideBar.North if orientation is None: orientation = E5SideBar.North self.setOrientation(orientation) self.__tabBar.currentChanged[int].connect( self.__stackedWidget.setCurrentIndex) e5App().focusChanged[QWidget, QWidget].connect(self.__appFocusChanged) self.__autoHideButton.toggled[bool].connect(self.__autoHideToggled) def setSplitter(self, splitter): """ Public method to set the splitter managing the sidebar. @param splitter reference to the splitter (QSplitter) """ self.splitter = splitter self.splitter.splitterMoved.connect(self.__splitterMoved) self.splitter.setChildrenCollapsible(False) index = self.splitter.indexOf(self) self.splitter.setCollapsible(index, False) def __splitterMoved(self, pos, index): """ Private slot to react on splitter moves. @param pos new position of the splitter handle (integer) @param index index of the splitter handle (integer) """ if self.splitter: self.splitterSizes = self.splitter.sizes() def __delayedAction(self): """ Private slot to handle the firing of the delay timer. """ if self.__actionMethod is not None: self.__actionMethod() def setDelay(self, delay): """ Public method to set the delay value for the expand/shrink delay in milliseconds. @param delay value for the expand/shrink delay in milliseconds (integer) """ self.__delayTimer.setInterval(delay) def delay(self): """ Public method to get the delay value for the expand/shrink delay in milliseconds. @return value for the expand/shrink delay in milliseconds (integer) """ return self.__delayTimer.interval() def __cancelDelayTimer(self): """ Private method to cancel the current delay timer. """ self.__delayTimer.stop() self.__actionMethod = None def shrink(self): """ Public method to record a shrink request. """ self.__delayTimer.stop() self.__actionMethod = self.__shrinkIt self.__delayTimer.start() def __shrinkIt(self): """ Private method to shrink the sidebar. """ self.__minimized = True self.__bigSize = self.size() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumSizeHint().width() self.__maxSize = self.maximumWidth() if self.splitter: self.splitterSizes = self.splitter.sizes() self.__stackedWidget.hide() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.setFixedHeight(self.__tabBar.minimumSizeHint().height()) else: self.setFixedWidth(self.__tabBar.minimumSizeHint().width()) self.__actionMethod = None def expand(self): """ Public method to record a expand request. """ self.__delayTimer.stop() self.__actionMethod = self.__expandIt self.__delayTimer.start() def __expandIt(self): """ Private method to expand the sidebar. """ self.__minimized = False self.__stackedWidget.show() self.resize(self.__bigSize) if self.__orientation in [E5SideBar.North, E5SideBar.South]: minSize = max(self.__minSize, self.minimumSizeHint().height()) self.setMinimumHeight(minSize) self.setMaximumHeight(self.__maxSize) else: minSize = max(self.__minSize, self.minimumSizeHint().width()) self.setMinimumWidth(minSize) self.setMaximumWidth(self.__maxSize) if self.splitter: self.splitter.setSizes(self.splitterSizes) self.__actionMethod = None def isMinimized(self): """ Public method to check the minimized state. @return flag indicating the minimized state (boolean) """ return self.__minimized def isAutoHiding(self): """ Public method to check, if the auto hide function is active. @return flag indicating the state of auto hiding (boolean) """ return self.__autoHide def eventFilter(self, obj, evt): """ Public method to handle some events for the tabbar. @param obj reference to the object (QObject) @param evt reference to the event object (QEvent) @return flag indicating, if the event was handled (boolean) """ if obj == self.__tabBar: if evt.type() == QEvent.MouseButtonPress: pos = evt.pos() for i in range(self.__tabBar.count()): if self.__tabBar.tabRect(i).contains(pos): break if i == self.__tabBar.currentIndex(): if self.isMinimized(): self.expand() else: self.shrink() return True elif self.isMinimized(): self.expand() elif evt.type() == QEvent.Wheel: if qVersion() >= "5.0.0": delta = evt.angleDelta().y() else: delta = evt.delta() if delta > 0: self.prevTab() else: self.nextTab() return True return QWidget.eventFilter(self, obj, evt) def addTab(self, widget, iconOrLabel, label=None): """ Public method to add a tab to the sidebar. @param widget reference to the widget to add (QWidget) @param iconOrLabel reference to the icon or the label text of the tab (QIcon, string) @param label the labeltext of the tab (string) (only to be used, if the second parameter is a QIcon) """ if label: index = self.__tabBar.addTab(iconOrLabel, label) self.__tabBar.setTabToolTip(index, label) else: index = self.__tabBar.addTab(iconOrLabel) self.__tabBar.setTabToolTip(index, iconOrLabel) self.__stackedWidget.addWidget(widget) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def insertTab(self, index, widget, iconOrLabel, label=None): """ Public method to insert a tab into the sidebar. @param index the index to insert the tab at (integer) @param widget reference to the widget to insert (QWidget) @param iconOrLabel reference to the icon or the labeltext of the tab (QIcon, string) @param label the labeltext of the tab (string) (only to be used, if the second parameter is a QIcon) """ if label: index = self.__tabBar.insertTab(index, iconOrLabel, label) self.__tabBar.setTabToolTip(index, label) else: index = self.__tabBar.insertTab(index, iconOrLabel) self.__tabBar.setTabToolTip(index, iconOrLabel) self.__stackedWidget.insertWidget(index, widget) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def removeTab(self, index): """ Public method to remove a tab. @param index the index of the tab to remove (integer) """ self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index)) self.__tabBar.removeTab(index) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def clear(self): """ Public method to remove all tabs. """ while self.count() > 0: self.removeTab(0) def prevTab(self): """ Public slot used to show the previous tab. """ ind = self.currentIndex() - 1 if ind == -1: ind = self.count() - 1 self.setCurrentIndex(ind) self.currentWidget().setFocus() def nextTab(self): """ Public slot used to show the next tab. """ ind = self.currentIndex() + 1 if ind == self.count(): ind = 0 self.setCurrentIndex(ind) self.currentWidget().setFocus() def count(self): """ Public method to get the number of tabs. @return number of tabs in the sidebar (integer) """ return self.__tabBar.count() def currentIndex(self): """ Public method to get the index of the current tab. @return index of the current tab (integer) """ return self.__stackedWidget.currentIndex() def setCurrentIndex(self, index): """ Public slot to set the current index. @param index the index to set as the current index (integer) """ self.__tabBar.setCurrentIndex(index) self.__stackedWidget.setCurrentIndex(index) if self.isMinimized(): self.expand() def currentWidget(self): """ Public method to get a reference to the current widget. @return reference to the current widget (QWidget) """ return self.__stackedWidget.currentWidget() def setCurrentWidget(self, widget): """ Public slot to set the current widget. @param widget reference to the widget to become the current widget (QWidget) """ self.__stackedWidget.setCurrentWidget(widget) self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex()) if self.isMinimized(): self.expand() def indexOf(self, widget): """ Public method to get the index of the given widget. @param widget reference to the widget to get the index of (QWidget) @return index of the given widget (integer) """ return self.__stackedWidget.indexOf(widget) def isTabEnabled(self, index): """ Public method to check, if a tab is enabled. @param index index of the tab to check (integer) @return flag indicating the enabled state (boolean) """ return self.__tabBar.isTabEnabled(index) def setTabEnabled(self, index, enabled): """ Public method to set the enabled state of a tab. @param index index of the tab to set (integer) @param enabled enabled state to set (boolean) """ self.__tabBar.setTabEnabled(index, enabled) def orientation(self): """ Public method to get the orientation of the sidebar. @return orientation of the sidebar (North, East, South, West) """ return self.__orientation def setOrientation(self, orient): """ Public method to set the orientation of the sidebar. @param orient orientation of the sidebar (North, East, South, West) """ if orient == E5SideBar.North: self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.TopToBottom) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == E5SideBar.East: self.__tabBar.setShape(QTabBar.RoundedEast) self.__tabBar.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Expanding) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.RightToLeft) self.layout.setAlignment(self.barLayout, Qt.AlignTop) elif orient == E5SideBar.South: self.__tabBar.setShape(QTabBar.RoundedSouth) self.__tabBar.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.BottomToTop) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == E5SideBar.West: self.__tabBar.setShape(QTabBar.RoundedWest) self.__tabBar.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Expanding) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.LeftToRight) self.layout.setAlignment(self.barLayout, Qt.AlignTop) self.__orientation = orient def tabIcon(self, index): """ Public method to get the icon of a tab. @param index index of the tab (integer) @return icon of the tab (QIcon) """ return self.__tabBar.tabIcon(index) def setTabIcon(self, index, icon): """ Public method to set the icon of a tab. @param index index of the tab (integer) @param icon icon to be set (QIcon) """ self.__tabBar.setTabIcon(index, icon) def tabText(self, index): """ Public method to get the text of a tab. @param index index of the tab (integer) @return text of the tab (string) """ return self.__tabBar.tabText(index) def setTabText(self, index, text): """ Public method to set the text of a tab. @param index index of the tab (integer) @param text text to set (string) """ self.__tabBar.setTabText(index, text) def tabToolTip(self, index): """ Public method to get the tooltip text of a tab. @param index index of the tab (integer) @return tooltip text of the tab (string) """ return self.__tabBar.tabToolTip(index) def setTabToolTip(self, index, tip): """ Public method to set the tooltip text of a tab. @param index index of the tab (integer) @param tip tooltip text to set (string) """ self.__tabBar.setTabToolTip(index, tip) def tabWhatsThis(self, index): """ Public method to get the WhatsThis text of a tab. @param index index of the tab (integer) @return WhatsThis text of the tab (string) """ return self.__tabBar.tabWhatsThis(index) def setTabWhatsThis(self, index, text): """ Public method to set the WhatsThis text of a tab. @param index index of the tab (integer) @param text WhatsThis text to set (string) """ self.__tabBar.setTabWhatsThis(index, text) def widget(self, index): """ Public method to get a reference to the widget associated with a tab. @param index index of the tab (integer) @return reference to the widget (QWidget) """ return self.__stackedWidget.widget(index) def saveState(self): """ Public method to save the state of the sidebar. @return saved state as a byte array (QByteArray) """ if len(self.splitterSizes) == 0: if self.splitter: self.splitterSizes = self.splitter.sizes() self.__bigSize = self.size() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumSizeHint().width() self.__maxSize = self.maximumWidth() data = QByteArray() stream = QDataStream(data, QIODevice.WriteOnly) stream.setVersion(QDataStream.Qt_4_6) stream.writeUInt16(self.Version) stream.writeBool(self.__minimized) stream << self.__bigSize stream.writeUInt16(self.__minSize) stream.writeUInt16(self.__maxSize) stream.writeUInt16(len(self.splitterSizes)) for size in self.splitterSizes: stream.writeUInt16(size) stream.writeBool(self.__autoHide) return data def restoreState(self, state): """ Public method to restore the state of the sidebar. @param state byte array containing the saved state (QByteArray) @return flag indicating success (boolean) """ if state.isEmpty(): return False if self.__orientation in [E5SideBar.North, E5SideBar.South]: minSize = self.layout.minimumSize().height() maxSize = self.maximumHeight() else: minSize = self.layout.minimumSize().width() maxSize = self.maximumWidth() data = QByteArray(state) stream = QDataStream(data, QIODevice.ReadOnly) stream.setVersion(QDataStream.Qt_4_6) stream.readUInt16() # version minimized = stream.readBool() if minimized and not self.__minimized: self.shrink() stream >> self.__bigSize self.__minSize = max(stream.readUInt16(), minSize) self.__maxSize = max(stream.readUInt16(), maxSize) count = stream.readUInt16() self.splitterSizes = [] for i in range(count): self.splitterSizes.append(stream.readUInt16()) self.__autoHide = stream.readBool() self.__autoHideButton.setChecked(not self.__autoHide) if not minimized: self.expand() return True ####################################################################### ## methods below implement the autohide functionality ####################################################################### def __autoHideToggled(self, checked): """ Private slot to handle the toggling of the autohide button. @param checked flag indicating the checked state of the button (boolean) """ self.__autoHide = not checked if self.__autoHide: self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOn.png")) else: self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOff.png")) def __appFocusChanged(self, old, now): """ Private slot to handle a change of the focus. @param old reference to the widget, that lost focus (QWidget or None) @param now reference to the widget having the focus (QWidget or None) """ self.__hasFocus = self.isAncestorOf(now) if self.__autoHide and not self.__hasFocus and not self.isMinimized(): self.shrink() elif self.__autoHide and self.__hasFocus and self.isMinimized(): self.expand() def enterEvent(self, event): """ Protected method to handle the mouse entering this widget. @param event reference to the event (QEvent) """ if self.__autoHide and self.isMinimized(): self.expand() else: self.__cancelDelayTimer() def leaveEvent(self, event): """ Protected method to handle the mouse leaving this widget. @param event reference to the event (QEvent) """ if self.__autoHide and not self.__hasFocus and not self.isMinimized(): self.shrink() else: self.__cancelDelayTimer() def shutdown(self): """ Public method to shut down the object. This method does some preparations so the object can be deleted properly. It disconnects from the focusChanged signal in order to avoid trouble later on. """ e5App().focusChanged[QWidget, QWidget].disconnect( self.__appFocusChanged)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setStyleSheet(''' background-color: #b3e6ff; ''') self.setWindowFlags(Qt.FramelessWindowHint) self.menu = InitWidget() self.gameWindow = GameWindow('', '', gameMode=GameMode.PVP) self.currentWidget = DisplayedWidget.MENU self.mode = GameMode.PVP # self.menu.PvAISignal.connect(self.goToNames) # self.menu.PvPSignal.connect(self.goToNames) self.menu.PvAISignal.connect(self.goToPVEGame) self.menu.PvPSignal.connect(self.goToPVPGame) self.menu.showHSTSignal.connect(self.goToScoreTable) self.stack = QStackedWidget(self) self.stack.addWidget(self.menu) self.stack.addWidget(self.gameWindow) self.setCentralWidget(self.stack) self.setGeometry(0, 0, 800, 600) self.setWindowTitle('Морской бой') self.mLastMousePosition = None self.mMoving = None self.gameOverWidget = None self.playerNamesWidget = None self.AIChooseWidget = None self.scoreBoardWidget = None def goToNames(self, mode=GameMode.PVE): self.playerNamesWidget = PlayerNamesWidget() self.playerNamesWidget.prepareWidget(mode) if mode == GameMode.PVE: self.AIChooseWidget = AIChooseWidget() self.playerNamesWidget.startSignal.connect(self.choosePvEMode) self.AIChooseWidget.modeSignal.connect(self.goToGameWindow) else: self.playerNamesWidget.startSignal.connect(self.goToGameWindow1) self.playerNamesWidget.menuSignal.connect(self.goToMenu) self.stack.addWidget(self.playerNamesWidget) self.stack.setCurrentWidget(self.playerNamesWidget) @pyqtSlot() def goToMenu(self): self.currentWidget = DisplayedWidget.MENU self.display() @pyqtSlot() def goToPVPGame(self): self.mode = GameMode.PVP self.goToNames(GameMode.PVP) @pyqtSlot() def goToPVEGame(self): self.mode = GameMode.PVE self.goToNames(GameMode.PVE) @pyqtSlot() def choosePvEMode(self): self.stack.addWidget(self.AIChooseWidget) self.stack.setCurrentWidget(self.AIChooseWidget) self.AIChooseWidget.backSignal.connect(self.goToNames) @pyqtSlot(str, str) def goToGameWindow1(self, player_1, player_2): self.currentWidget = DisplayedWidget.GAME self.gameWindow = GameWindow(player_1, player_2, self.mode) self.gameWindow.gameOverSignal.connect(self.showGameOver) self.gameWindow.toMenuSignal.connect(self.goToMenu) self.stack.insertWidget(DisplayedWidget.GAME, self.gameWindow) self.display() @pyqtSlot(GameLevel) def goToGameWindow(self, mode): self.currentWidget = DisplayedWidget.GAME player_1 = self.playerNamesWidget.getPlayer1() self.gameWindow = GameWindow(player_1, "OpenAI", GameMode.PVE, mode) self.gameWindow.gameOverSignal.connect(self.showGameOver) self.gameWindow.toMenuSignal.connect(self.goToMenu) self.stack.insertWidget(DisplayedWidget.GAME, self.gameWindow) self.display() # def goToGameWindow_(self, gameMode): # self.currentWidget = DisplayedWidget.GAME # self.gameWindow = GameWindow(gameMode=gameMode) # self.gameWindow.gameOverSignal.connect(self.showGameOver) # self.gameWindow.toMenuSignal.connect(self.goToMenu) # self.stack.insertWidget(DisplayedWidget.GAME, self.gameWindow) # # self.display() @pyqtSlot(str) def showGameOver(self, player): self.gameOverWidget = GameOverWidget(player) self.gameOverWidget.ui.menuButton.clicked.connect(self.goToMenu) self.stack.addWidget(self.gameOverWidget) self.stack.setCurrentWidget(self.gameOverWidget) @pyqtSlot() def goToScoreTable(self): self.stack.removeWidget(self.scoreBoardWidget) self.scoreBoardWidget = ScoreBoardWidget() self.scoreBoardWidget.onExit.connect(self.goToMenu) self.stack.addWidget(self.scoreBoardWidget) self.stack.setCurrentWidget(self.scoreBoardWidget) def display(self): self.stack.setCurrentIndex(self.currentWidget) def quit(self): QCoreApplication.quit() def mousePressEvent(self, event: QtGui.QMouseEvent) -> None: if event.button() == Qt.MouseButton.LeftButton: self.mMoving = True self.mLastMousePosition = event.pos() def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: if self.mMoving: self.move(self.pos() + event.pos() - self.mLastMousePosition) def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None: if event.button() == Qt.MouseButton.LeftButton: self.mMoving = False
class PyMultiPageWidget(QWidget): currentIndexChanged = pyqtSignal(int) pageTitleChanged = pyqtSignal(str) def __init__(self, parent=None): super(PyMultiPageWidget, self).__init__(parent) self.comboBox = QComboBox() # MAGIC # It is important that the combo box has an object name beginning # with '__qt__passive_', otherwise, it is inactive in the form editor # of the designer and you can't change the current page via the # combo box. # MAGIC self.comboBox.setObjectName('__qt__passive_comboBox') self.stackWidget = QStackedWidget() self.comboBox.activated.connect(self.setCurrentIndex) self.layout = QVBoxLayout() self.layout.addWidget(self.comboBox) self.layout.addWidget(self.stackWidget) self.setLayout(self.layout) def sizeHint(self): return QSize(200, 150) def count(self): return self.stackWidget.count() def widget(self, index): return self.stackWidget.widget(index) @pyqtSlot(QWidget) def addPage(self, page): self.insertPage(self.count(), page) @pyqtSlot(int, QWidget) def insertPage(self, index, page): page.setParent(self.stackWidget) self.stackWidget.insertWidget(index, page) title = page.windowTitle() if title == "": title = "Page %d" % (self.comboBox.count() + 1) page.setWindowTitle(title) self.comboBox.insertItem(index, title) @pyqtSlot(int) def removePage(self, index): widget = self.stackWidget.widget(index) self.stackWidget.removeWidget(widget) self.comboBox.removeItem(index) def getPageTitle(self): return self.stackWidget.currentWidget().windowTitle() @pyqtSlot(str) def setPageTitle(self, newTitle): self.comboBox.setItemText(self.getCurrentIndex(), newTitle) self.stackWidget.currentWidget().setWindowTitle(newTitle) self.pageTitleChanged.emit(newTitle) def getCurrentIndex(self): return self.stackWidget.currentIndex() @pyqtSlot(int) def setCurrentIndex(self, index): if index != self.getCurrentIndex(): self.stackWidget.setCurrentIndex(index) self.comboBox.setCurrentIndex(index) self.currentIndexChanged.emit(index) pageTitle = pyqtProperty(str, fget=getPageTitle, fset=setPageTitle, stored=False) currentIndex = pyqtProperty(int, fget=getCurrentIndex, fset=setCurrentIndex)
class MainWindow(QMainWindow): def __init__(self, resolution: QRect, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowTitle("") self.screens_config = [] self.current_screen = 0 self.sub_screens = {} self.button = {} self.subscreen_stacked_widget = QStackedWidget() self.number_of_subs = 0 self.main_stack_widget = QStackedWidget() self.main_widget = QWidget() self.main_layout = QGridLayout() self.gui_element_builder = GuiElementsBuilder() self.gui_button_builder = GuiButtonBuilder() self.gui_subscreen_builder = GuiSubscreenBuilder() self.resolution = resolution self.alarm_observer = AlarmObserver(self) self.alarm_widget = Alarm(self.alarm_observer, "Alarm_Widget", "#550055", self) def set_current_subscreen(self): source_button = self.sender() for i in range(0, self.number_of_subs): # print(source_button.text(), self.subscreen_stacked_widget.widget(i).get_name()) if self.subscreen_stacked_widget.widget( i).get_name() == source_button.text(): self.subscreen_stacked_widget.setCurrentIndex(i) def toggle_main_widget(self, index: int): max_value = self.main_stack_widget.count() self.main_stack_widget.setCurrentIndex(index % max_value) def close_main_window(self): self.close() def update_from_subscreen(self, msg: dict) -> None: print(msg) self.alarm_widget.set_alarm_text(msg) self.toggle_main_widget(1) def init_with_config(self, config: dict): self.screens_config = config # Set Title title = str(config['main']['name']) self.setWindowTitle(title) # Set window flag flags = Qt.CustomizeWindowHint # Small Frame # flags = Qt.FramelessWindowHint # No Frame self.setWindowFlags(flags) # Set Resolution ###################################################### # via config window_width = config['main']["resolution"][0] window_height = config['main']["resolution"][1] # via given screen geometry # window_width = self.resolution.width() # window_height = self.resolution.height() # Set Resolution End ################################################## button_width = config['main']["button-size"][0] button_height = config['main']["button-size"][1] front_color = config['main']["front_color"] background_color = config['main']["background_color"] font = config['main']["font"] self.number_of_subs = len(config['sub']) self.gui_element_builder.set_font(font) self.setFixedSize(window_width, window_height) self.main_widget.setLayout(self.main_layout) self.main_widget.setStyleSheet("background-color:" + background_color) vbox_menu = QVBoxLayout() vbox_menu.setSizeConstraint(QLayout.SetFixedSize) vbox_menu.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.TOP_LEFT_SHORT, 100, 191, front_color)) button_list_widget = QListWidget() vbox_menu.addWidget(button_list_widget) vbox_menu.addWidget( self.gui_element_builder.get_svg_widget( Gui_Element.BOTTOM_LEFT_SHORT, 100, 191, front_color)) # Header ################################################################# self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 33, 712, front_color), 0, 1, 1, 1, Qt.AlignTop) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 33, 52, front_color), 0, 3, Qt.AlignTop) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 33, 33, front_color), 0, 4, Qt.AlignTop) # Header - END ########################################################### # Menu self.main_layout.addLayout(vbox_menu, 0, 0, 4, 1) # Central Window self.main_layout.addWidget(self.subscreen_stacked_widget, 1, 1, 2, 4) # Footer ################################################################# self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 33, 712, front_color), 3, 1, Qt.AlignBottom) # Add Exit Button exit_button = QPushButton("EXIT") exit_button.setFont(QFont(font, 20, QFont.Bold)) exit_button.setFixedSize(52, 33) exit_button.setStyleSheet("background:#ff0000; border:1px solid " + front_color + ";") exit_button.clicked.connect(lambda state: self.close()) self.main_layout.addWidget(exit_button, 3, 3, Qt.AlignBottom) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 33, 33, front_color, font), 3, 4, Qt.AlignBottom) # Footer - END ########################################################### # button_ListWidget.setVerticalScrolllayout(QAbstractItemView.ScrollMode.ScrollPerItem) button_list_widget.setStyleSheet("QListWidget{background:" + background_color + "; border: 0px solid " + front_color + ";}") # Erstellen der linken Button-Leiste ############## button_width = button_width * window_width / 100 button_height = button_height * window_height / 100 button_size = QSize(button_width, button_height) for i in range(0, self.number_of_subs): sub_button_list_item = QListWidgetItem(button_list_widget) placeholder_list_item = QListWidgetItem(button_list_widget) placeholder_list_item.setSizeHint(QSize(button_width, 4)) placeholder_list_item.setBackground(QColor(background_color)) flag = placeholder_list_item.flags() & Qt.ItemIsUserCheckable placeholder_list_item.setFlags(flag) # Widgets ################################################################################################## self.subscreen_stacked_widget.insertWidget( i, self.gui_subscreen_builder.init_with_config( self.screens_config['sub'][i], self.alarm_observer)) # Buttons ################################################################################################## self.gui_button_builder.set_color( self.screens_config['sub'][i]["Background"]) self.gui_button_builder.set_size(button_height, button_width) self.button[i] = self.gui_button_builder.create_button( self.screens_config["sub"][i]["name"], Gui_Element.BUTTON_TEXT) sub_button_list_item.setSizeHint(button_size) button_list_widget.addItem(placeholder_list_item) button_list_widget.addItem(sub_button_list_item) button_list_widget.setItemWidget(sub_button_list_item, self.button[i]) # signals ################################################################################################## self.button[i].clicked.connect( lambda widget=self.subscreen_stacked_widget.widget( i): self.set_current_subscreen()) # button_list_widget.setMaximumWidth(1000) button_list_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) button_list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) button_list_widget.setMaximumWidth( button_list_widget.sizeHintForColumn(0)) ############################################# self.subscreen_stacked_widget.setCurrentIndex(0) self.main_stack_widget.insertWidget(0, self.main_widget) self.main_stack_widget.insertWidget(1, self.alarm_widget) self.main_stack_widget.setCurrentIndex(0) self.setCentralWidget(self.main_stack_widget)
class PyMultiPageWidget(QWidget): currentIndexChanged = pyqtSignal(int) pageTitleChanged = pyqtSignal(str) def __init__(self, parent=None): super(PyMultiPageWidget, self).__init__(parent) self.comboBox = QComboBox() self.comboBox.setObjectName('__qt__passive_comboBox') self.stackWidget = QStackedWidget() self.comboBox.activated.connect(self.setCurrentIndex) self.layout = QVBoxLayout() self.layout.addWidget(self.comboBox) self.layout.addWidget(self.stackWidget) self.setLayout(self.layout) def sizeHint(self): return QSize(200, 150) def count(self): return self.stackWidget.count() def widget(self, index): return self.stackWidget.widget(index) @pyqtSlot(QWidget) def addPage(self, page): self.insertPage(self.count(), page) @pyqtSlot(int, QWidget) def insertPage(self, index, page): page.setParent(self.stackWidget) self.stackWidget.insertWidget(index, page) title = page.windowTitle() if title == "": title = "Page %d" % (self.comboBox.count() + 1) page.setWindowTitle(title) self.comboBox.insertItem(index, title) @pyqtSlot(int) def removePage(self, index): widget = self.stackWidget.widget(index) self.stackWidget.removeWidget(widget) self.comboBox.removeItem(index) def getPageTitle(self): cw = self.stackWidget.currentWidget() return cw.windowTitle() if cw is not None else '' @pyqtSlot(str) def setPageTitle(self, newTitle): cw = self.stackWidget.currentWidget() if cw is not None: self.comboBox.setItemText(self.getCurrentIndex(), newTitle) cw.setWindowTitle(newTitle) self.pageTitleChanged.emit(newTitle) def getCurrentIndex(self): return self.stackWidget.currentIndex() @pyqtSlot(int) def setCurrentIndex(self, index): if index != self.getCurrentIndex(): self.stackWidget.setCurrentIndex(index) self.comboBox.setCurrentIndex(index) self.currentIndexChanged.emit(index) pageTitle = pyqtProperty(str, fget=getPageTitle, fset=setPageTitle, stored=False) currentIndex = pyqtProperty(int, fget=getCurrentIndex, fset=setCurrentIndex)
class E5SideBar(QWidget): """ Class implementing a sidebar with a widget area, that is hidden or shown, if the current tab is clicked again. """ Version = 1 North = 0 East = 1 South = 2 West = 3 def __init__(self, orientation=None, delay=200, parent=None): """ Constructor @param orientation orientation of the sidebar widget (North, East, South, West) @param delay value for the expand/shrink delay in milliseconds (integer) @param parent parent widget (QWidget) """ super(E5SideBar, self).__init__(parent) self.__tabBar = QTabBar() self.__tabBar.setDrawBase(True) self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setUsesScrollButtons(True) self.__tabBar.setDrawBase(False) self.__stackedWidget = QStackedWidget(self) self.__stackedWidget.setContentsMargins(0, 0, 0, 0) self.__autoHideButton = QToolButton() self.__autoHideButton.setCheckable(True) self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOff.png")) self.__autoHideButton.setChecked(True) self.__autoHideButton.setToolTip( self.tr("Deselect to activate automatic collapsing")) self.barLayout = QBoxLayout(QBoxLayout.LeftToRight) self.barLayout.setContentsMargins(0, 0, 0, 0) self.layout = QBoxLayout(QBoxLayout.TopToBottom) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.barLayout.addWidget(self.__autoHideButton) self.barLayout.addWidget(self.__tabBar) self.layout.addLayout(self.barLayout) self.layout.addWidget(self.__stackedWidget) self.setLayout(self.layout) # initialize the delay timer self.__actionMethod = None self.__delayTimer = QTimer(self) self.__delayTimer.setSingleShot(True) self.__delayTimer.setInterval(delay) self.__delayTimer.timeout.connect(self.__delayedAction) self.__minimized = False self.__minSize = 0 self.__maxSize = 0 self.__bigSize = QSize() self.splitter = None self.splitterSizes = [] self.__hasFocus = False # flag storing if this widget or any child has the focus self.__autoHide = False self.__tabBar.installEventFilter(self) self.__orientation = E5SideBar.North if orientation is None: orientation = E5SideBar.North self.setOrientation(orientation) self.__tabBar.currentChanged[int].connect( self.__stackedWidget.setCurrentIndex) e5App().focusChanged.connect(self.__appFocusChanged) self.__autoHideButton.toggled[bool].connect(self.__autoHideToggled) def setSplitter(self, splitter): """ Public method to set the splitter managing the sidebar. @param splitter reference to the splitter (QSplitter) """ self.splitter = splitter self.splitter.splitterMoved.connect(self.__splitterMoved) self.splitter.setChildrenCollapsible(False) index = self.splitter.indexOf(self) self.splitter.setCollapsible(index, False) def __splitterMoved(self, pos, index): """ Private slot to react on splitter moves. @param pos new position of the splitter handle (integer) @param index index of the splitter handle (integer) """ if self.splitter: self.splitterSizes = self.splitter.sizes() def __delayedAction(self): """ Private slot to handle the firing of the delay timer. """ if self.__actionMethod is not None: self.__actionMethod() def setDelay(self, delay): """ Public method to set the delay value for the expand/shrink delay in milliseconds. @param delay value for the expand/shrink delay in milliseconds (integer) """ self.__delayTimer.setInterval(delay) def delay(self): """ Public method to get the delay value for the expand/shrink delay in milliseconds. @return value for the expand/shrink delay in milliseconds (integer) """ return self.__delayTimer.interval() def __cancelDelayTimer(self): """ Private method to cancel the current delay timer. """ self.__delayTimer.stop() self.__actionMethod = None def shrink(self): """ Public method to record a shrink request. """ self.__delayTimer.stop() self.__actionMethod = self.__shrinkIt self.__delayTimer.start() def __shrinkIt(self): """ Private method to shrink the sidebar. """ self.__minimized = True self.__bigSize = self.size() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumSizeHint().width() self.__maxSize = self.maximumWidth() if self.splitter: self.splitterSizes = self.splitter.sizes() self.__stackedWidget.hide() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.setFixedHeight(self.__tabBar.minimumSizeHint().height()) else: self.setFixedWidth(self.__tabBar.minimumSizeHint().width()) self.__actionMethod = None def expand(self): """ Public method to record a expand request. """ self.__delayTimer.stop() self.__actionMethod = self.__expandIt self.__delayTimer.start() def __expandIt(self): """ Private method to expand the sidebar. """ self.__minimized = False self.__stackedWidget.show() self.resize(self.__bigSize) if self.__orientation in [E5SideBar.North, E5SideBar.South]: minSize = max(self.__minSize, self.minimumSizeHint().height()) self.setMinimumHeight(minSize) self.setMaximumHeight(self.__maxSize) else: minSize = max(self.__minSize, self.minimumSizeHint().width()) self.setMinimumWidth(minSize) self.setMaximumWidth(self.__maxSize) if self.splitter: self.splitter.setSizes(self.splitterSizes) self.__actionMethod = None def isMinimized(self): """ Public method to check the minimized state. @return flag indicating the minimized state (boolean) """ return self.__minimized def isAutoHiding(self): """ Public method to check, if the auto hide function is active. @return flag indicating the state of auto hiding (boolean) """ return self.__autoHide def eventFilter(self, obj, evt): """ Public method to handle some events for the tabbar. @param obj reference to the object (QObject) @param evt reference to the event object (QEvent) @return flag indicating, if the event was handled (boolean) """ if obj == self.__tabBar: if evt.type() == QEvent.MouseButtonPress: pos = evt.pos() for i in range(self.__tabBar.count()): if self.__tabBar.tabRect(i).contains(pos): break if i == self.__tabBar.currentIndex(): if self.isMinimized(): self.expand() else: self.shrink() return True elif self.isMinimized(): self.expand() elif evt.type() == QEvent.Wheel: if qVersion() >= "5.0.0": delta = evt.angleDelta().y() else: delta = evt.delta() if delta > 0: self.prevTab() else: self.nextTab() return True return QWidget.eventFilter(self, obj, evt) def addTab(self, widget, iconOrLabel, label=None): """ Public method to add a tab to the sidebar. @param widget reference to the widget to add (QWidget) @param iconOrLabel reference to the icon or the label text of the tab (QIcon, string) @param label the labeltext of the tab (string) (only to be used, if the second parameter is a QIcon) """ if label: index = self.__tabBar.addTab(iconOrLabel, label) self.__tabBar.setTabToolTip(index, label) else: index = self.__tabBar.addTab(iconOrLabel) self.__tabBar.setTabToolTip(index, iconOrLabel) self.__stackedWidget.addWidget(widget) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def insertTab(self, index, widget, iconOrLabel, label=None): """ Public method to insert a tab into the sidebar. @param index the index to insert the tab at (integer) @param widget reference to the widget to insert (QWidget) @param iconOrLabel reference to the icon or the labeltext of the tab (QIcon, string) @param label the labeltext of the tab (string) (only to be used, if the second parameter is a QIcon) """ if label: index = self.__tabBar.insertTab(index, iconOrLabel, label) self.__tabBar.setTabToolTip(index, label) else: index = self.__tabBar.insertTab(index, iconOrLabel) self.__tabBar.setTabToolTip(index, iconOrLabel) self.__stackedWidget.insertWidget(index, widget) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def removeTab(self, index): """ Public method to remove a tab. @param index the index of the tab to remove (integer) """ self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index)) self.__tabBar.removeTab(index) if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() else: self.__minSize = self.minimumSizeHint().width() def clear(self): """ Public method to remove all tabs. """ while self.count() > 0: self.removeTab(0) def prevTab(self): """ Public slot used to show the previous tab. """ ind = self.currentIndex() - 1 if ind == -1: ind = self.count() - 1 self.setCurrentIndex(ind) self.currentWidget().setFocus() def nextTab(self): """ Public slot used to show the next tab. """ ind = self.currentIndex() + 1 if ind == self.count(): ind = 0 self.setCurrentIndex(ind) self.currentWidget().setFocus() def count(self): """ Public method to get the number of tabs. @return number of tabs in the sidebar (integer) """ return self.__tabBar.count() def currentIndex(self): """ Public method to get the index of the current tab. @return index of the current tab (integer) """ return self.__stackedWidget.currentIndex() def setCurrentIndex(self, index): """ Public slot to set the current index. @param index the index to set as the current index (integer) """ self.__tabBar.setCurrentIndex(index) self.__stackedWidget.setCurrentIndex(index) if self.isMinimized(): self.expand() def currentWidget(self): """ Public method to get a reference to the current widget. @return reference to the current widget (QWidget) """ return self.__stackedWidget.currentWidget() def setCurrentWidget(self, widget): """ Public slot to set the current widget. @param widget reference to the widget to become the current widget (QWidget) """ self.__stackedWidget.setCurrentWidget(widget) self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex()) if self.isMinimized(): self.expand() def indexOf(self, widget): """ Public method to get the index of the given widget. @param widget reference to the widget to get the index of (QWidget) @return index of the given widget (integer) """ return self.__stackedWidget.indexOf(widget) def isTabEnabled(self, index): """ Public method to check, if a tab is enabled. @param index index of the tab to check (integer) @return flag indicating the enabled state (boolean) """ return self.__tabBar.isTabEnabled(index) def setTabEnabled(self, index, enabled): """ Public method to set the enabled state of a tab. @param index index of the tab to set (integer) @param enabled enabled state to set (boolean) """ self.__tabBar.setTabEnabled(index, enabled) def orientation(self): """ Public method to get the orientation of the sidebar. @return orientation of the sidebar (North, East, South, West) """ return self.__orientation def setOrientation(self, orient): """ Public method to set the orientation of the sidebar. @param orient orientation of the sidebar (North, East, South, West) """ if orient == E5SideBar.North: self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.TopToBottom) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == E5SideBar.East: self.__tabBar.setShape(QTabBar.RoundedEast) self.__tabBar.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.RightToLeft) self.layout.setAlignment(self.barLayout, Qt.AlignTop) elif orient == E5SideBar.South: self.__tabBar.setShape(QTabBar.RoundedSouth) self.__tabBar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.BottomToTop) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == E5SideBar.West: self.__tabBar.setShape(QTabBar.RoundedWest) self.__tabBar.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.LeftToRight) self.layout.setAlignment(self.barLayout, Qt.AlignTop) self.__orientation = orient def tabIcon(self, index): """ Public method to get the icon of a tab. @param index index of the tab (integer) @return icon of the tab (QIcon) """ return self.__tabBar.tabIcon(index) def setTabIcon(self, index, icon): """ Public method to set the icon of a tab. @param index index of the tab (integer) @param icon icon to be set (QIcon) """ self.__tabBar.setTabIcon(index, icon) def tabText(self, index): """ Public method to get the text of a tab. @param index index of the tab (integer) @return text of the tab (string) """ return self.__tabBar.tabText(index) def setTabText(self, index, text): """ Public method to set the text of a tab. @param index index of the tab (integer) @param text text to set (string) """ self.__tabBar.setTabText(index, text) def tabToolTip(self, index): """ Public method to get the tooltip text of a tab. @param index index of the tab (integer) @return tooltip text of the tab (string) """ return self.__tabBar.tabToolTip(index) def setTabToolTip(self, index, tip): """ Public method to set the tooltip text of a tab. @param index index of the tab (integer) @param tip tooltip text to set (string) """ self.__tabBar.setTabToolTip(index, tip) def tabWhatsThis(self, index): """ Public method to get the WhatsThis text of a tab. @param index index of the tab (integer) @return WhatsThis text of the tab (string) """ return self.__tabBar.tabWhatsThis(index) def setTabWhatsThis(self, index, text): """ Public method to set the WhatsThis text of a tab. @param index index of the tab (integer) @param text WhatsThis text to set (string) """ self.__tabBar.setTabWhatsThis(index, text) def widget(self, index): """ Public method to get a reference to the widget associated with a tab. @param index index of the tab (integer) @return reference to the widget (QWidget) """ return self.__stackedWidget.widget(index) def saveState(self): """ Public method to save the state of the sidebar. @return saved state as a byte array (QByteArray) """ if len(self.splitterSizes) == 0: if self.splitter: self.splitterSizes = self.splitter.sizes() self.__bigSize = self.size() if self.__orientation in [E5SideBar.North, E5SideBar.South]: self.__minSize = self.minimumSizeHint().height() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumSizeHint().width() self.__maxSize = self.maximumWidth() data = QByteArray() stream = QDataStream(data, QIODevice.WriteOnly) stream.setVersion(QDataStream.Qt_4_6) stream.writeUInt16(self.Version) stream.writeBool(self.__minimized) stream << self.__bigSize stream.writeUInt16(self.__minSize) stream.writeUInt16(self.__maxSize) stream.writeUInt16(len(self.splitterSizes)) for size in self.splitterSizes: stream.writeUInt16(size) stream.writeBool(self.__autoHide) return data def restoreState(self, state): """ Public method to restore the state of the sidebar. @param state byte array containing the saved state (QByteArray) @return flag indicating success (boolean) """ if state.isEmpty(): return False if self.__orientation in [E5SideBar.North, E5SideBar.South]: minSize = self.layout.minimumSize().height() maxSize = self.maximumHeight() else: minSize = self.layout.minimumSize().width() maxSize = self.maximumWidth() data = QByteArray(state) stream = QDataStream(data, QIODevice.ReadOnly) stream.setVersion(QDataStream.Qt_4_6) stream.readUInt16() # version minimized = stream.readBool() if minimized and not self.__minimized: self.shrink() stream >> self.__bigSize self.__minSize = max(stream.readUInt16(), minSize) self.__maxSize = max(stream.readUInt16(), maxSize) count = stream.readUInt16() self.splitterSizes = [] for i in range(count): self.splitterSizes.append(stream.readUInt16()) self.__autoHide = stream.readBool() self.__autoHideButton.setChecked(not self.__autoHide) if not minimized: self.expand() return True ####################################################################### ## methods below implement the autohide functionality ####################################################################### def __autoHideToggled(self, checked): """ Private slot to handle the toggling of the autohide button. @param checked flag indicating the checked state of the button (boolean) """ self.__autoHide = not checked if self.__autoHide: self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOn.png")) else: self.__autoHideButton.setIcon( UI.PixmapCache.getIcon("autoHideOff.png")) def __appFocusChanged(self, old, now): """ Private slot to handle a change of the focus. @param old reference to the widget, that lost focus (QWidget or None) @param now reference to the widget having the focus (QWidget or None) """ self.__hasFocus = self.isAncestorOf(now) if self.__autoHide and not self.__hasFocus and not self.isMinimized(): self.shrink() elif self.__autoHide and self.__hasFocus and self.isMinimized(): self.expand() def enterEvent(self, event): """ Protected method to handle the mouse entering this widget. @param event reference to the event (QEvent) """ if self.__autoHide and self.isMinimized(): self.expand() else: self.__cancelDelayTimer() def leaveEvent(self, event): """ Protected method to handle the mouse leaving this widget. @param event reference to the event (QEvent) """ if self.__autoHide and not self.__hasFocus and not self.isMinimized(): self.shrink() else: self.__cancelDelayTimer() def shutdown(self): """ Public method to shut down the object. This method does some preparations so the object can be deleted properly. It disconnects from the focusChanged signal in order to avoid trouble later on. """ e5App().focusChanged.disconnect(self.__appFocusChanged)
class CentralWidget(QWidget): # This signals is used by notificator databaseSaved = pyqtSignal('QString') querySaved = pyqtSignal('QString') def __init__(self): QWidget.__init__(self) box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) box.setSpacing(0) self.stacked = QStackedWidget() box.addWidget(self.stacked) self.created = False self.__last_open_folder = None self.__recent_dbs = [] if PSetting.RECENT_DBS: self.__recent_dbs = PSetting.RECENT_DBS Pireal.load_service("central", self) @property def recent_databases(self): return self.__recent_dbs @recent_databases.setter def recent_databases(self, database_file): if database_file in PSetting.RECENT_DBS: PSetting.RECENT_DBS.remove(database_file) PSetting.RECENT_DBS.insert(0, database_file) self.__recent_dbs = PSetting.RECENT_DBS def create_database(self): """ Show a wizard widget to create a new database, only have one database open at time. """ if self.created: QMessageBox.information(self, self.tr("Information"), self.tr("You may only have one database" " open at time.")) DEBUG("Ya existe una base de datos abierta") return wizard = database_wizard.DatabaseWizard(self) wizard.wizardFinished.connect( self.__on_wizard_finished) # Hide menubar and toolbar pireal = Pireal.get_service("pireal") pireal.show_hide_menubar() pireal.show_hide_toolbar() # Add wizard widget to stacked self.add_widget(wizard) def __on_wizard_finished(self, data, wizard_widget): """ This slot execute when wizard to create a database is finished """ pireal = Pireal.get_service("pireal") if not data: # If it's canceled, remove wizard widget and return to Start Page self.remove_last_widget() else: # Create a new data base container db_container = database_container.DatabaseContainer() # Associate the file name with the PFile object pfile_object = pfile.File(data['filename']) # Associate PFile object with data base container # and add widget to stacked db_container.pfile = pfile_object self.add_widget(db_container) # Remove wizard self.stacked.removeWidget(wizard_widget) # Set window title pireal.change_title(file_manager.get_basename(data['filename'])) # Enable db actions pireal.set_enabled_db_actions(True) pireal.set_enabled_relation_actions(True) self.created = True DEBUG("Base de datos creada correctamente: '{}'".format( data['filename'])) # If data or not, show menubar and toolbar again pireal.show_hide_menubar() pireal.show_hide_toolbar() def open_database(self, filename=''): """ This function opens a database and set this on the UI """ # If not filename provide, then open dialog to select if self.created: QMessageBox.information(self, self.tr("Information"), self.tr("You may only have one database" " open at time.")) DEBUG("Ya existe una base de datos abierta") return if not filename: if self.__last_open_folder is None: directory = os.path.expanduser("~") else: directory = self.__last_open_folder filter_ = settings.SUPPORTED_FILES.split(';;')[0] filename, _ = QFileDialog.getOpenFileName(self, self.tr("Open Database"), directory, filter_) # If is canceled, return if not filename: return # Remember the folder self.__last_open_folder = file_manager.get_path(filename) DEBUG("Abriendo la base de datos: '{}'".format(filename)) # If filename provide try: # Read pdb file pfile_object = pfile.File(filename) db_data = pfile_object.read() # Create a dict to manipulate data more easy db_data = self.__sanitize_data(db_data) except Exception as reason: QMessageBox.information(self, self.tr("The file couldn't be open"), str(reason)) CRITICAL("Error al intentar abrir el archivo: {}".format(reason)) return # Create a database container widget db_container = database_container.DatabaseContainer() try: db_container.create_database(db_data) except Exception as reason: QMessageBox.information(self, self.tr("Error"), str(reason)) CRITICAL("Error al crear la base de datos: {}".format(reason)) return # Set the PFile object to the new database db_container.pfile = pfile_object # Add data base container to stacked self.add_widget(db_container) # Database name db_name = file_manager.get_basename(filename) # Update title with the new database name, and enable some actions pireal = Pireal.get_service("pireal") pireal.change_title(db_name) pireal.set_enabled_db_actions(True) pireal.set_enabled_relation_actions(True) # Add to recent databases self.recent_databases = filename self.created = True def open_query(self): filter_ = settings.SUPPORTED_FILES.split(';;')[1] filename, _ = QFileDialog.getOpenFileName(self, self.tr("Open Query"), os.path.expanduser("~"), filter_) if not filename: return # FIXME: mejorar éste y new_query self.new_query(filename) def save_query(self, editor=None): db = self.get_active_db() fname = db.save_query(editor) if fname: self.querySaved.emit(self.tr("Query saved: {}".format(fname))) def save_query_as(self): pass def __sanitize_data(self, data): """ This function converts the data into a dictionary for better handling then. The argument 'data' is the content of the database. """ # FIXME: controlar cuando al final de la línea hay una coma data_dict = {'tables': []} for line_count, line in enumerate(data.splitlines()): # Ignore blank lines if not line: continue if line.startswith('@'): # This line is a header tpoint = line.find(':') if tpoint == -1: raise Exception("Invalid syntax at line {}".format( line_count + 1)) table_name, line = line.split(':') table_name = table_name[1:].strip() table_dict = {} table_dict['name'] = table_name table_dict['header'] = line.split(',') table_dict['tuples'] = [] else: for l in csv.reader([line]): # Remove spaces l = list(map(str.strip, l)) # FIXME: this is necesary? if table_dict['name'] == table_name: table_dict['tuples'].append(l) if not table_dict['tuples']: data_dict['tables'].append(table_dict) return data_dict def remove_last_widget(self): """ Remove last widget from stacked """ widget = self.stacked.widget(self.stacked.count() - 1) self.stacked.removeWidget(widget) def close_database(self): """ Close the database and return to the main widget """ db = self.get_active_db() query_container = db.query_container if db.modified: msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle(self.tr("Save Changes?")) msgbox.setText(self.tr("The <b>{}</b> database has ben" " modified.<br>Do you want save " "your changes?".format( db.dbname()))) cancel_btn = msgbox.addButton(self.tr("Cancel"), QMessageBox.RejectRole) msgbox.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msgbox.addButton(self.tr("Yes"), QMessageBox.YesRole) msgbox.exec_() r = msgbox.clickedButton() if r == cancel_btn: return if r == yes_btn: self.save_database() # Check if editor is modified query_widget = query_container.currentWidget() if query_widget is not None: weditor = query_widget.get_editor() if weditor is not None: # TODO: duplicate code, see tab widget if weditor.modified: msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle(self.tr("File modified")) msgbox.setText(self.tr("The file <b>{}</b> has unsaved " "changes. You want to keep " "them?".format( weditor.name))) cancel_btn = msgbox.addButton(self.tr("Cancel"), QMessageBox.RejectRole) msgbox.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msgbox.addButton(self.tr("Yes"), QMessageBox.YesRole) msgbox.exec_() r = msgbox.clickedButton() if r == cancel_btn: return if r == yes_btn: self.save_query(weditor) self.stacked.removeWidget(db) pireal = Pireal.get_service("pireal") pireal.set_enabled_db_actions(False) pireal.set_enabled_relation_actions(False) pireal.set_enabled_query_actions(False) pireal.set_enabled_editor_actions(False) self.created = False DEBUG("Se cerró la base de datos: '{}'".format(db.dbname())) del db def new_query(self, filename=''): pireal = Pireal.get_service("pireal") db_container = self.get_active_db() db_container.new_query(filename) # Enable editor actions # FIXME: refactoring pireal.set_enabled_query_actions(True) zoom_in_action = Pireal.get_action("zoom_in") zoom_in_action.setEnabled(True) zoom_out_action = Pireal.get_action("zoom_out") zoom_out_action.setEnabled(True) paste_action = Pireal.get_action("paste_action") paste_action.setEnabled(True) comment_action = Pireal.get_action("comment") comment_action.setEnabled(True) uncomment_action = Pireal.get_action("uncomment") uncomment_action.setEnabled(True) def execute_queries(self): db_container = self.get_active_db() db_container.execute_queries() def execute_selection(self): db_container = self.get_active_db() db_container.execute_selection() def save_database(self): db = self.get_active_db() if not db.modified: return # Get relations dict relations = db.table_widget.relations # Generate content content = file_manager.generate_database(relations) db.pfile.save(content=content) filename = db.pfile.filename # Emit signal self.databaseSaved.emit( self.tr("Database saved: {}".format(filename))) db.modified = False def save_database_as(self): filter = settings.SUPPORTED_FILES.split(';;')[0] filename, _ = QFileDialog.getSaveFileName(self, self.tr("Save Database As"), settings.PIREAL_PROJECTS, filter) if not filename: return db = self.get_active_db() # Get relations relations = db.table_widget.relations # Content content = file_manager.generate_database(relations) db.pfile.save(content, filename) self.databaseSaved.emit( self.tr("Database saved: {}".format(db.pfile.filename))) db.modified = False def remove_relation(self): db = self.get_active_db() if db.delete_relation(): db.modified = True def create_new_relation(self): data = new_relation_dialog.create_relation() if data is not None: db = self.get_active_db() rela, rela_name = data # Add table db.table_widget.add_table(rela, rela_name) # Add item to lateral widget db.lateral_widget.add_item(rela_name, rela.count()) # Set modified db db.modified = True def edit_relation(self): db = self.get_active_db() lateral = db.lateral_widget selected_items = lateral.selectedItems() if selected_items: selected_relation = selected_items[0].text(0) relation_text = selected_relation.split()[0].strip() rela = db.table_widget.relations[relation_text] data = edit_relation_dialog.edit_relation(rela) if data is not None: # Update table db.table_widget.update_table(data) # Update relation db.table_widget.relations[relation_text] = data # Set modified db db.modified = True lateral.update_item(data.count()) def load_relation(self, filename=''): """ Load Relation file """ if not filename: if self.__last_open_folder is None: directory = os.path.expanduser("~") else: directory = self.__last_open_folder msg = self.tr("Open Relation File") filter_ = settings.SUPPORTED_FILES.split(';;')[-1] filenames = QFileDialog.getOpenFileNames(self, msg, directory, filter_)[0] if not filenames: return # Save folder self.__last_open_folder = file_manager.get_path(filenames[0]) db_container = self.get_active_db() if db_container.load_relation(filenames): db_container.modified = True def add_start_page(self): """ This function adds the Start Page to the stacked widget """ sp = start_page.StartPage() self.add_widget(sp) def show_settings(self): """ Show settings dialog on stacked """ preferences_dialog = preferences.Preferences(self) if isinstance(self.widget(1), preferences.Preferences): self.widget(1).close() else: self.stacked.insertWidget(1, preferences_dialog) self.stacked.setCurrentIndex(1) # Connect the closed signal preferences_dialog.settingsClosed.connect(self._settings_closed) def widget(self, index): """ Returns the widget at the given index """ return self.stacked.widget(index) def add_widget(self, widget): """ Appends and show the given widget to the Stacked """ index = self.stacked.addWidget(widget) self.stacked.setCurrentIndex(index) def _settings_closed(self): self.stacked.removeWidget(self.widget(1)) self.stacked.setCurrentWidget(self.stacked.currentWidget()) def get_active_db(self): """ Return an instance of DatabaseContainer widget if the stacked contains an DatabaseContainer in last index or None if it's not an instance of DatabaseContainer """ index = self.stacked.count() - 1 widget = self.widget(index) if isinstance(widget, database_container.DatabaseContainer): return widget return None def get_unsaved_queries(self): query_container = self.get_active_db().query_container return query_container.get_unsaved_queries() def undo_action(self): query_container = self.get_active_db().query_container query_container.undo() def redo_action(self): query_container = self.get_active_db().query_container query_container.redo() def cut_action(self): query_container = self.get_active_db().query_container query_container.cut() def copy_action(self): query_container = self.get_active_db().query_container query_container.copy() def paste_action(self): query_container = self.get_active_db().query_container query_container.paste() def zoom_in(self): query_container = self.get_active_db().query_container query_container.zoom_in() def zoom_out(self): query_container = self.get_active_db().query_container query_container.zoom_out() def comment(self): query_container = self.get_active_db().query_container query_container.comment() def uncomment(self): query_container = self.get_active_db().query_container query_container.uncomment()
class GuiSubscreenBuilder: def __init__(self): self.widget = QWidget() self.main_layout = QGridLayout() self.gui_menu_builder = GuiMenuBuilder() self.gui_element_builder = GuiElementsBuilder() self.foreground_color = "" self.central_widget = QStackedWidget() self.buttons = [] def init_with_config(self, config: dict, observer: Observer) -> QWidget: self.widget = Base(observer, config["name"], config["Background"]) self.foreground_color = config["Background"] if config["layout"] == 1: # Header self.main_layout.addWidget( self.gui_element_builder.get_svg_widget( Gui_Element.BUTTON, 20, 640, self.foreground_color), 0, 1, 1, 3, Qt.AlignTop) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget( Gui_Element.END_RIGHT, 20, 20, self.foreground_color), 0, 5, Qt.AlignTop) self.main_layout.addWidget(self.central_widget, 1, 1, 2, 4) # self.central_widget.setStyleSheet("background-color:" + "#ffffff") # Show size of Central_Widget # Footer self.main_layout.addWidget( self.gui_element_builder.get_svg_widget( Gui_Element.BUTTON, 13, 640, self.foreground_color), 4, 1, 1, 2, Qt.AlignBottom) self.main_layout.addWidget( self.gui_element_builder.get_svg_widget( Gui_Element.END_RIGHT, 13, 10, self.foreground_color), 4, 5, Qt.AlignLeft | Qt.AlignBottom) if "subapp" in config: self.main_layout.addLayout( self.gui_menu_builder.build_menu(config.get("subapp"), self.foreground_color), 0, 0, 5, 1) self.buttons = self.gui_menu_builder.get_button_list() for i in range(0, len(config.get("subapp"))): widget = self.create_subapp( config.get("subapp")[i], observer) button = self.buttons[i] self.central_widget.insertWidget(i, widget) button.clicked.connect( lambda state, wid=widget: self.central_widget. setCurrentWidget(wid)) self.widget.setLayout(self.main_layout) return self.widget else: return self.create_subapp(config, observer) @staticmethod def create_subapp(config: dict, observer: Observer) -> QWidget: name = config["name"] # ToDo besseren Weg zum Erstellen der Subapps suchen # ToDo Laden der Subscreens aus Verzeichniss je nach Nennung in Config if name == "Clock": return Clock(observer, name, config["Background"]) elif name == "Timer": return Timer(observer, name, config["Background"]) elif name == "Weather": return Weather(observer, name, config["Background"], "LCARSGTJ3") elif name == "Countup": return Countup(name, config["Background"]) elif name == "Movesub": return Movesub(name, config["Background"]) elif name == "Alarm": return Alarm(observer, name, config["Background"], None) elif name == "MyCustomEventTest": return MyCustomEventTest(name, config["Background"]) else: return Placeholder(name, config["Background"])
class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle('Code Size Visualizer') self.stacked_widget = QStackedWidget() #to show different pages self.stacked_widget.currentChanged.connect(self.set_button_state) widget = QtWidgets.QWidget() self.setCentralWidget(widget) vbox = QVBoxLayout() vbox.addWidget(self.stacked_widget) #add the to the main window self.toolbar = QToolBar("Edit", self) #on file upload chart button gets enables and upon pressing it goes to next page h = HomeScreen(self) #calling this first self.chartBtn = h.viewChartBtn self.lineEdit = h.lineEdit self.chartBtn.clicked.connect(self.next_page) h.pushButton.clicked.connect(self.file_open) self.insert_page(h.centralwidget) self.addToolBar(self.toolbar) #start with the toolbar hidden self.toolbar.toggleViewAction().setChecked(True) self.toolbar.toggleViewAction().trigger() # create main layout widget.setLayout(vbox) #FILE OPEN def file_open(self): name, _ = QtWidgets.QFileDialog.getOpenFileName(None, 'Open File', "", "*.map",options=QtWidgets.QFileDialog.DontUseNativeDialog) self.lineEdit.setText(name) chartData, navData = FileOpen.openFile(name) navigation = Navigation(chartData, navData , self) self.addToolBar(navigation.toolbar) self.insert_page(navigation.horizontalGroupBox) def set_button_state(self, index): n_pages = len(self.stacked_widget) self.chartBtn.setEnabled( index % n_pages < n_pages - 1) def insert_page(self, widget, index=-1): self.stacked_widget.insertWidget(index, widget) self.set_button_state(self.stacked_widget.currentIndex()) def next_page(self): new_index = self.stacked_widget.currentIndex()+1 if new_index < len(self.stacked_widget): self.stacked_widget.setCurrentIndex(new_index) self.toolbar.toggleViewAction().trigger()