def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = "frontend/icons/wow.png" icon_nn_path = "frontend/icons/nn_.png" icon_click_path = "frontend/icons/point.png" self.add_action( icon_path, text=self.tr("Set neural network (F6)"), callback=self.gui_dialog, parent=self.iface.mainWindow(), shortcut="F6", ) self.add_action( icon_nn_path, text=self.tr("Inference (F4)"), callback=self.infer_only, parent=self.iface.mainWindow(), shortcut="F4", ) self.add_action( icon_click_path, text=self.tr("Clicky click (F3)"), callback=self.clicky, parent=self.iface.mainWindow(), ) short = QShortcut("F3", self.iface.mainWindow()) short.setContext(Qt.ApplicationShortcut) short.activated.connect(partial(self._set_class_annot))
def _setupUi(self): self.resize(400, 300) self.gridLayout = QGridLayout(self) self.label = QLabel(tr("Choose a type for this tab:")) self.label.setAlignment(Qt.AlignCenter) self.gridLayout.addWidget(self.label, 0, 0, 1, 3) self.gridLayout.addItem(horizontalSpacer(), 1, 0, 1, 1) self.verticalLayout = QVBoxLayout() BUTTONS = [ ('networthButton', tr("1. Net Worth"), 'balance_sheet_16'), ('profitButton', tr("2. Profit && Loss"), 'income_statement_16'), ('transactionButton', tr("3. Transactions"), 'transaction_table_16'), ('gledgerButton', tr("4. General Ledger"), 'gledger_16'), ('scheduleButton', tr("5. Schedules"), 'schedules_16'), ('budgetButton', tr("6. Budgets"), 'budget_16'), ('docpropsButton', tr("7. Document Properties"), 'gledger_16'), ] for i, (name, label, icon) in enumerate(BUTTONS, start=1): button = QPushButton(label) if icon: button.setIcon(QIcon(QPixmap(':/{}'.format(icon)))) self.verticalLayout.addWidget(button) setattr(self, name, button) shortcut = QShortcut(self) shortcut.setKey(QKeySequence(str(i))) shortcut.setContext(Qt.WidgetShortcut) setattr(self, 'shortcut{}'.format(i), shortcut) self.gridLayout.addLayout(self.verticalLayout, 1, 1, 1, 1) self.gridLayout.addItem(horizontalSpacer(), 1, 2, 1, 1) self.gridLayout.addItem(verticalSpacer(), 2, 1, 1, 1)
def bind_all_standard_keys(standard_key, handler_cb, parent=None, context=Qt.WindowShortcut): """Workaround for Qt apparently only binding the first StandardKey when it's fed into QShortcut @type standard_key: C{QtGui.QKeySequence.StandardKey} @type handler_cb: C{function} @type parent: C{QObject} @type context: C{QtCore.Qt.ShortcutContext} @rtype: C{[QtWidgets.QShortcut]} """ results = [] if isinstance(standard_key, QKeySequence.StandardKey): hotkeys = QKeySequence.keyBindings(standard_key) else: hotkeys = [standard_key] for hotkey in hotkeys: shortcut = QShortcut(hotkey, parent) shortcut.setContext(context) shortcut.activated.connect(handler_cb) results.append(shortcut) return results
def __init__(self, items=None, parent=None, status=None): self.emits = ['patternchanged'] self.receives = [('patterns', self.setItems)] self.settingsdialog = SettingsWin QComboBox.__init__(self, parent) self._status = status status['patterns'] = self.items status['patterntext'] = lambda: str(self.currentText()) self.setEditable(True) if items: self.addItems(items) pchange = lambda text: self.patternchanged.emit(str(text)) self.editTextChanged.connect(pchange) shortcut = QShortcut(self) shortcut.setKey('F8') shortcut.setContext(Qt.ApplicationShortcut) def set_focus(): if self.hasFocus(): status['table'].setFocus() else: self.lineEdit().selectAll() self.setFocus() shortcut.activated.connect(set_focus)
def install_shortcuts(obj, actions, ide): short = resources.get_shortcut for action in actions: short_key = action.get("shortcut", None) action_data = action.get("action", None) connect = action.get("connect", None) if connect == "open_project_properties": print("\nregistrando ::open_project_properties; obj:", obj) shortcut = None item_ui = None func = None if connect: func = getattr(obj, connect, None) if short_key and not action_data: if isinstance(short_key, QKeySequence): shortcut = QShortcut(short_key, ide) else: shortcut = QShortcut(short(short_key), ide) shortcut.setContext(Qt.ApplicationShortcut) if isinstance(func, collections.Callable): shortcut.activated.connect(func) if action_data: is_menu = action_data.get('is_menu', False) if is_menu: item_ui = QMenu(action_data['text'], ide) else: item_ui = QAction(action_data['text'], ide) object_name = "%s.%s" % (obj.__class__.__name__, connect) item_ui.setObjectName(object_name) image_name = action_data.get('image', None) section = action_data.get('section', None) weight = action_data.get('weight', None) keysequence = action_data.get('keysequence', None) if image_name: if isinstance(image_name, int): icon = ide.style().standardIcon(image_name) item_ui.setIcon(icon) elif isinstance(image_name, str): icon = QIcon(":img/" + image_name) item_ui.setIcon(icon) if short_key and not is_menu: item_ui.setShortcut(short(short_key)) item_ui.setShortcutContext(Qt.ApplicationShortcut) elif keysequence and not is_menu: item_ui.setShortcut(short(keysequence)) item_ui.setShortcutContext(Qt.ApplicationShortcut) if isinstance(func, collections.Callable) and not is_menu: item_ui.triggered['bool'].connect(lambda s, f=func: f()) if section and section[0] is not None and weight: ide.register_menuitem(item_ui, section, weight) if image_name and not is_menu: ide.register_toolbar(item_ui, section, weight) if short_key and shortcut: ide.register_shortcut(short_key, shortcut, item_ui)
def __init__(self, parent=None): QWidget.__init__(self, parent) Ui_PlaylistsWidget.setupUi(self, self) self.view.doubleClicked.connect(self.playlistClicked) deletePlaylistShortcut = QShortcut(QKeySequence('Del'), self.view) deletePlaylistShortcut.setContext(Qt.WidgetShortcut) deletePlaylistShortcut.activated.connect(self.onDeletePlaylist)
class UI(QWidget): def __init__(self, *args): super().__init__(*args) self.factory = ObjectFactory() self.factory_shortcut = QShortcut(QKeySequence("Ctrl+n"), self) self.factory_shortcut.setContext(QtCore.Qt.ApplicationShortcut) self.factory_shortcut.activated.connect(self.on_factory) self.selector = ObjectSelector() self.selector_shortcut = QShortcut(QKeySequence("Ctrl+s"), self) self.selector_shortcut.setContext(QtCore.Qt.ApplicationShortcut) self.selector_shortcut.activated.connect(self.on_selector) flags = QtCore.Qt.WindowFlags(QtCore.Qt.WindowStaysOnBottomHint) self.setWindowFlags(flags) self.showFullScreen() return def contextMenuEvent(self, event): m = QMenu() new_action = m.addAction("New ...") find_action = m.addAction("Find ...") m.addSeparator() logout_action = m.addAction("Logout") quit_action = m.addAction("Shutdown") action = m.exec_(self.mapToGlobal(event.pos())) if action == new_action: self.on_factory() elif action == find_action: self.on_selector() elif action == quit_action: qApp.quit() def on_factory(self, *args): """Display a panel enabling creation of new type instances.""" print("Factory: " + str(args)) if self.factory.isVisible(): self.factory.hide() else: self.factory.show() return def on_selector(self, *args): """Display a panel enabling a search of existing objects.""" print("Selector: " + str(args)) self.selector.toggle_visibility() return
def __init__(self, controller: 'Controller') -> None: super().__init__() self.controller = controller self.is_unused = True self.set_unused_text() self.returnPressed.connect(self.on_return_pressed) self.history: List[str] = [] self.history_idx = 0 action = self.addAction(QIcon.fromTheme("window-close"), QLineEdit.TrailingPosition) action.triggered.connect(self._on_reset) action.setToolTip("Close the Search") shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_G), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._on_reset) shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._on_reset) shortcut = QShortcut(QKeySequence(Qt.Key_Up), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self.history_up) shortcut = QShortcut(QKeySequence(Qt.Key_Down), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self.history_down)
def initPlaylist(self): """Initialize song playlist.""" self.playlistTable = QTableWidget() self.playlistTable.setSelectionBehavior(QAbstractItemView.SelectRows) self.playlistTable.setSelectionMode( QAbstractItemView.ExtendedSelection) self.playlistTable.setSortingEnabled(True) self.playlistTable.setTabKeyNavigation(False) self.playlistTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.playlistTable.setAlternatingRowColors(True) self.playlistTable.setVerticalScrollMode( QAbstractItemView.ScrollPerPixel) self.playlistTable.setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.playlistTable.itemDoubleClicked.connect(self.doubleClicked) self.doubleClicked = False self.lastPlayed = -1 self.currentPlaying = -1 delete = QShortcut( QKeySequence.Delete, self.playlistTable, self.deleteSongs) delete.setContext(Qt.WidgetShortcut) self.playlistTable.setColumnCount(4) self.playlistTable.setHorizontalHeaderLabels( ['Artist', 'Title', 'Album', 'Duration']) # False - ascending order, True - descending self.descendingOrder = [False] * 4 self.playlistTable.horizontalHeader().sectionClicked.connect( self.toSort) self.windows = [] names = [] for index in range(self.playlist.mediaCount()): names.append(self.playlist.media(index).canonicalUrl().path()) self.addClicked(names) self.grid.addWidget(self.playlistTable, 2, 0, 1, 4) self.grid.setRowStretch(2, 1)
def __init__(self, parent): """Init table list.""" super().__init__() self.parent = parent self.items = dict() self.header().hide() self.setAnimated(True) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.openMenu) shortcut = QShortcut(QKeySequence("DEL"), self) shortcut.setAutoRepeat(False) shortcut.setContext(Qt.WidgetWithChildrenShortcut) shortcut.activated.connect(self.delClicked) shortcut = QShortcut(QKeySequence("Enter"), self) shortcut.setAutoRepeat(False) shortcut.setContext(Qt.WidgetWithChildrenShortcut) shortcut.activated.connect(self.enterClicked)
def __init__(self, main_window, shortcut): self.shortcut = shortcut self.main_window = main_window shortcut_ = QShortcut(self.shortcut, main_window) shortcut_.setContext(Qt.ApplicationShortcut) def ShowStyleSheetEditor(): style_sheet_inspector_class = GetStyleSheetInspectorClass() style_sheet_inspector = [ c for c in self.main_window.children() if isinstance(c, style_sheet_inspector_class) ] if style_sheet_inspector: style_sheet_inspector = style_sheet_inspector[0] else: style_sheet_inspector = style_sheet_inspector_class( self.main_window) style_sheet_inspector.setFixedSize(800, 600) style_sheet_inspector.show() shortcut_.activated.connect(ShowStyleSheetEditor)
def __init__(self, parent=None): QWidget.__init__(self, parent) Ui_LibraryWidget.setupUi(self, self) self.rescanButton.show() self.scanProgressBar.hide() self.libraryModel = LibraryModel() self.treeView.setModel(self.libraryModel) self.libraryModel.toggleRow.connect(self.onToggleRow) self.rescanButton.clicked.connect(self.rescanClicked) self.treeView.doubleClicked.connect(self.onTreeViewDoubleClicked) self.querySearchBox.textChanged.connect(self.onQueryChanged) self.clearSearchButton.clicked.connect(self.onQueryClear) # shortcuts releaseSearchboxShortcut = QShortcut(QKeySequence('Esc'), self.querySearchBox) releaseSearchboxShortcut.setContext(Qt.WidgetShortcut) releaseSearchboxShortcut.activated.connect(self.onReleaseSearchbox) scrollLibraryShortcut = QShortcut(QKeySequence(Qt.Key_Down), self.querySearchBox) scrollLibraryShortcut.setContext(Qt.WidgetShortcut) scrollLibraryShortcut.activated.connect(self.onScrollLibrary) activateTracksShortcut = QShortcut(QKeySequence(Qt.Key_Return), self.treeView) activateTracksShortcut.setContext(Qt.WidgetShortcut) activateTracksShortcut.activated.connect(self.onActivateTracks)
def init(self): self.setUtf8(True) lexer = QsciLexerJSON(self) self.setLexer(lexer) self.setAutoCompletionCaseSensitivity(False) # 忽略大小写 self.setAutoCompletionSource(self.AcsAll) self.setAutoCompletionThreshold(1) # 一个字符就弹出补全 self.setAutoIndent(True) # 自动缩进 self.setBackspaceUnindents(True) self.setBraceMatching(self.StrictBraceMatch) self.setIndentationGuides(True) self.setIndentationsUseTabs(False) self.setIndentationWidth(4) self.setTabIndents(True) self.setTabWidth(4) self.setWhitespaceSize(1) self.setWhitespaceVisibility(self.WsVisible) self.setWhitespaceForegroundColor(Qt.gray) self.setWrapIndentMode(self.WrapIndentFixed) self.setWrapMode(self.WrapWord) # 折叠 self.setFolding(self.BoxedTreeFoldStyle, 2) self.setFoldMarginColors(QColor("#676A6C"), QColor("#676A6D")) font = self.font() or QFont() font.setFamily("Consolas") font.setFixedPitch(True) font.setPointSize(13) self.setFont(font) self.setMarginsFont(font) self.fontmetrics = QFontMetrics(font) lexer.setFont(font) self.setMarginWidth(0, self.fontmetrics.width(str(self.lines())) + 6) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("gainsboro")) self.setMarginWidth(1, 0) self.setMarginWidth(2, 14) # 折叠区域 # 绑定自动补齐热键Alt+/ completeKey = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Slash), self) completeKey.setContext(Qt.WidgetShortcut) completeKey.activated.connect(self.autoCompleteFromAll)
def _setupInspector(self): """ F12키를 누르면 "개발자 도구"가 노출됨 """ # webinspector self.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True) self.webInspector = QWebInspector(self) self.webInspector.setPage(self.page()) # shortcut shortcut = QShortcut(self) shortcut.setContext(Qt.ApplicationShortcut) shortcut.setKey(Qt.Key_F12) shortcut.activated.connect(self._toggleInspector) # Devtools self.webInspector.setVisible(True) self.devTool = QDialog(self) self.devTool.setWindowTitle("Development Tool") self.devTool.resize(950, 400) layout = QGridLayout() layout.setContentsMargins(0,0,0,0) layout.addWidget(self.webInspector) self.devTool.setLayout(layout)
def __init__(self, parent): super().__init__(parent) self.mModel = CommandDataModel(self) self.setModel(self.mModel) self.setRootIsDecorated(False) # Setup resizing so the command column stretches self.setColumnWidth(0, 200) h = self.header() h.setStretchLastSection(False) h.setSectionResizeMode(CommandDataModel.NameColumn, QHeaderView.Interactive) h.setSectionResizeMode(CommandDataModel.CommandColumn, QHeaderView.Stretch) h.setSectionResizeMode(CommandDataModel.EnabledColumn, QHeaderView.ResizeToContents) # Allow deletion via keyboard d = QShortcut(QKeySequence.Delete, self) d.setContext(Qt.WidgetShortcut) d.activated.connect(self.removeSelectedCommands) self.mModel.rowsRemoved.connect(self.handleRowsRemoved)
def __init__(self, controller: 'Controller') -> None: super().__init__() self._controller = controller self.is_unused = True self._show_completion_selection = True self.returnPressed.connect(self.on_return_pressed) self.textEdited.connect(self.on_text_edited) self.bookmark_act = self.addAction(QIcon.fromTheme("user-bookmarks"), QLineEdit.TrailingPosition) self.bookmark_act.setCheckable(True) self.bookmark_act.triggered.connect(self._on_bookmark_triggered) self.bookmark_act.setToolTip("Toggle bookmark for this location") self._controller.sig_location_changed.connect( self._on_location_changed) self._controller.sig_location_changed_to_none.connect( lambda: self._on_location_changed(None)) self._popup = LocationLineEditPopup(self) shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_G), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._on_escape_press) shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._on_escape_press) shortcut = QShortcut(QKeySequence(Qt.Key_Up), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._popup.on_key_up) shortcut = QShortcut(QKeySequence(Qt.Key_Down), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._popup.on_key_down)
class SubwindowMisc(QWidget): """Show subwindow with miscellaneous settings.""" current_tab = -1 def createWindow(self, mainWindow, tab=''): """Create subwindow with miscellaneous settings.""" try: parent = None super().__init__(parent) # self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setWindowIcon( QIcon(scctool.settings.getResFile('settings.png'))) self.setWindowModality(Qt.ApplicationModal) self.mainWindow = mainWindow self.passEvent = False self.controller = mainWindow.controller self.__dataChanged = False self.createButtonGroup() self.createTabs(tab) mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs) mainLayout.addLayout(self.buttonGroup) self.setLayout(mainLayout) self.resize( QSize(int(mainWindow.size().width() * 0.9), self.sizeHint().height())) relativeChange = QPoint(int(mainWindow.size().width() / 2), int(mainWindow.size().height() / 3))\ - QPoint(int(self.size().width() / 2), int(self.size().height() / 3)) self.move(mainWindow.pos() + relativeChange) self.setWindowTitle(_("Miscellaneous Settings")) except Exception: module_logger.exception("message") def createTabs(self, tab=''): """Create tabs.""" self.tabs = QTabWidget() self.createMapsBox() self.createFavBox() self.createAliasBox() self.createOcrBox() self.createAlphaBox() self.createSC2ClientAPIBox() self.createAligulacTab() self.createCounterTab() # Add tabs self.tabs.addTab(self.mapsBox, _("Map Manager")) self.tabs.addTab(self.favBox, _("Favorites")) self.tabs.addTab(self.aliasBox, _("Alias")) self.tabs.addTab(self.ocrBox, _("OCR")) self.tabs.addTab(self.alphaBox, _("AlphaTL && Ingame Score")) self.tabs.addTab(self.clientapiBox, _("SC2 Client API")) self.tabs.addTab(self.aligulacTab, _("Aligulac")) self.tabs.addTab(self.counterTab, _("Countdown && Ticker")) table = dict() table['mapmanager'] = 0 table['favorites'] = 1 table['alias'] = 2 table['ocr'] = 3 table['alphatl'] = 4 table['sc2clientapi'] = 5 table['aligulac'] = 6 table['counter'] = 7 self.tabs.setCurrentIndex(table.get(tab, SubwindowMisc.current_tab)) self.tabs.currentChanged.connect(self.tabChanged) @classmethod def tabChanged(cls, idx): """Save the current tab index.""" SubwindowMisc.current_tab = idx def changed(self): """Handle changes.""" self.__dataChanged = True def createAlphaBox(self): """Create Alpha QWidget.""" self.alphaBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("AlphaTL")) layout = QHBoxLayout() self.cb_trans_banner = QCheckBox( " " + _("Download transparent Banner of the Match")) self.cb_trans_banner.setChecked( scctool.settings.config.parser.getboolean( "SCT", "transparent_match_banner")) self.cb_trans_banner.stateChanged.connect(self.changed) layout.addWidget(self.cb_trans_banner) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Set Ingame Score Task")) layout = QVBoxLayout() self.cb_ctrlx = QCheckBox(" " + _('Automatically press Ctrl+X to apply the' ' correct player order ingame')) self.cb_ctrlx.setToolTip( _("This will ensure that the player of the first team is always" " on the left/top in the ingame Observer UI.")) self.cb_ctrlx.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlX")) self.cb_ctrlx.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlx) self.cb_ctrln = QCheckBox(" " + _('Automatically press Ctrl+N before' ' OCR to display player names')) self.cb_ctrln.setToolTip( _("This is recommended for Standard and Gawliq Observer UI.")) self.cb_ctrln.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlN")) self.cb_ctrln.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrln) self.cb_ctrlshifts = QCheckBox( " " + _('Automatically press Ctrl+Shift+S to display' ' the ingame score')) self.cb_ctrlshifts.setToolTip( _("Ctrl+Shift+S is needed for the WCS-Gameheart Oberserver" " Overlay, but disables the sound for other overlays.")) self.cb_ctrlshifts.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlShiftS")) self.cb_ctrlshifts.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlshifts) self.cb_ctrlshiftc = QCheckBox( " " + _('Automatically press Ctrl+Shift+C to toogle the clan tag')) self.cb_ctrlshiftc.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlShiftC")) self.cb_ctrlshiftc.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlshiftc) container = QHBoxLayout() self.cb_ctrlshiftr = QComboBox() self.cb_ctrlshiftr.addItem("0") self.cb_ctrlshiftr.addItem("1") self.cb_ctrlshiftr.addItem("2") try: self.cb_ctrlshiftr.setCurrentIndex( scctool.settings.config.parser.getint("SCT", "CtrlShiftR")) except Exception: self.cb_ctrlshiftr.setCurrentIndex(0) self.cb_ctrlshiftr.setMaximumWidth(40) self.cb_ctrlshiftr.currentIndexChanged.connect(self.changed) container.addWidget( QLabel( _('Automatically press Ctrl+Shift+R to toogle the race icon ')) ) container.addWidget(self.cb_ctrlshiftr) container.addWidget(QLabel(_(' time(s)'))) layout.addLayout(container) self.cb_blacklist = QCheckBox(" " + _('Activate Blacklist for' ' Ingame Score')) self.cb_blacklist.setChecked( scctool.settings.config.parser.getboolean("SCT", "blacklist_on")) self.cb_blacklist.stateChanged.connect(self.changed) layout.addWidget(self.cb_blacklist) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Blacklist for Ingame Score")) layout = QVBoxLayout() blacklistDesc = _("Enter your SC2 client usernames to deactivate" " automatically setting the ingame score and" " toogling the production tab when you are playing" " yourself. Replays are exempt.") label = QLabel(blacklistDesc) label.setAlignment(Qt.AlignJustify) label.setWordWrap(True) layout.addWidget(label) self.list_blacklist = ListTable(4, scctool.settings.config.getBlacklist()) self.list_blacklist.dataModified.connect(self.changed) self.list_blacklist.setFixedHeight(50) layout.addWidget(self.list_blacklist) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.alphaBox.setLayout(mainLayout) def createFavBox(self): """Create favorites box.""" self.favBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("Players")) layout = QHBoxLayout() self.list_favPlayers = ListTable( 4, scctool.settings.config.getMyPlayers()) self.list_favPlayers.dataModified.connect(self.changed) self.list_favPlayers.setFixedHeight(150) layout.addWidget(self.list_favPlayers) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Teams")) layout = QVBoxLayout() self.list_favTeams = ListTable(3, scctool.settings.config.getMyTeams()) self.list_favTeams.dataModified.connect(self.changed) self.list_favTeams.setFixedHeight(100) layout.addWidget(self.list_favTeams) self.cb_swapTeams = QCheckBox( _('Swap my favorite team always to the left')) self.cb_swapTeams.setChecked( scctool.settings.config.parser.getboolean("SCT", "swap_myteam")) self.cb_swapTeams.stateChanged.connect(self.changed) layout.addWidget(self.cb_swapTeams) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.favBox.setLayout(mainLayout) def createAliasBox(self): """Create favorites box.""" self.aliasBox = QWidget() mainLayout = QGridLayout() aliasDesc = _( 'Player, team, and league aliases are replaced by the actual name when' + ' encountered by the match grabber. Additionally, SC2 player' + ' names listed as aliases are replaced in the intros' + ' and used to identify players by the automatic' + ' background tasks "Auto Score Update" and "Set Ingame Score".') label = QLabel(aliasDesc) label.setAlignment(Qt.AlignJustify) label.setWordWrap(True) mainLayout.addWidget(label, 1, 0, 1, 3) box = QGroupBox(_("Player Aliases")) layout = QVBoxLayout() self.list_aliasPlayers = AliasTreeView(self) self.list_aliasPlayers.aliasRemoved.connect( self.controller.aliasManager.removePlayerAlias) layout.addWidget(self.list_aliasPlayers) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasPlayers, _('Player Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 0) box = QGroupBox(_("Team Aliases")) layout = QVBoxLayout() self.list_aliasTeams = AliasTreeView(self) self.list_aliasTeams.aliasRemoved.connect( self.controller.aliasManager.removeTeamAlias) layout.addWidget(self.list_aliasTeams) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasTeams, _('Team Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 1) box = QGroupBox(_("League Aliases")) layout = QVBoxLayout() self.list_aliasLeagues = AliasTreeView(self) self.list_aliasLeagues.aliasRemoved.connect( self.controller.aliasManager.removeLeagueAlias) layout.addWidget(self.list_aliasLeagues) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasLeagues, _('League Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 2) alias_list = self.controller.aliasManager.playerAliasList() for player, aliases in alias_list.items(): self.list_aliasPlayers.insertAliasList(player, aliases) alias_list = self.controller.aliasManager.teamAliasList() for league, aliases in alias_list.items(): self.list_aliasTeams.insertAliasList(league, aliases) alias_list = self.controller.aliasManager.leagueAliasList() for league, aliases in alias_list.items(): self.list_aliasLeagues.insertAliasList(league, aliases) self.aliasBox.setLayout(mainLayout) def addAlias(self, widget, scope, name=""): """Add an alias.""" name, ok = QInputDialog.getText(self, scope, scope + ':', text=name) if not ok: return name = name.strip() alias, ok = QInputDialog.getText(self, _('Alias'), _('Alias of {}').format(name) + ':', text="") alias = alias.strip() if not ok: return try: if widget == self.list_aliasPlayers: self.controller.aliasManager.addPlayerAlias(name, alias) elif widget == self.list_aliasTeams: self.controller.aliasManager.addTeamAlias(name, alias) elif widget == self.list_aliasLeagues: self.controller.aliasManager.addLeagueAlias(name, alias) widget.insertAlias(name, alias, True) except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) def createSC2ClientAPIBox(self): """Create form for SC2 Client API config.""" self.clientapiBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("SC2 Client API Address")) layout = QGridLayout() self.cb_usesc2listener = QCheckBox( " " + _("Listen to SC2 Client API running" " on a different PC in the network.")) self.cb_usesc2listener.setChecked( scctool.settings.config.parser.getboolean( "SCT", "sc2_network_listener_enabled")) self.cb_usesc2listener.stateChanged.connect(self.changed) self.listener_address = MonitoredLineEdit() self.listener_address.setAlignment(Qt.AlignCenter) self.listener_address.setText( scctool.settings.config.parser.get("SCT", "sc2_network_listener_address")) self.listener_address.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.listener_address.setPlaceholderText("[Your SC2 PC IP]:6119") self.listener_address.setToolTip( _('IP address and port of machine running SC2.')) ip_port = ( r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)" + r"{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$") self.listener_address.setValidator(QRegExpValidator(QRegExp(ip_port))) self.test_listener = QPushButton(" " + _("Test SC2 Client API Connection") + " ") self.test_listener.clicked.connect(self.testClientAPI) text = _("Activate this option if you are using a two computer " "setup with StarCraft Casting Tool running on a different" " PC than your SC2 client. Open the Battle.net launcher " "on the latter PC, click 'Options', 'Game Settings', and " "under SC2, check 'Additional Command Line Arguments', and " "enter '-clientapi 6119'. Finally set as network" " address below: '[Your SC2 PC IP]:6119'.") label = QLabel(text) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 3) layout.addWidget(self.cb_usesc2listener, 0, 0, 1, 3) layout.addWidget(QLabel(_("Network Address") + ": "), 3, 0) layout.addWidget(self.listener_address, 3, 1) layout.addWidget(self.test_listener, 3, 2) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.clientapiBox.setLayout(mainLayout) def testClientAPI(self): """Test for connection to sc2 client api.""" QApplication.setOverrideCursor(Qt.WaitCursor) address = self.listener_address.text().strip() url = "http://{}/ui".format(address) try: r = requests.get(url, timeout=10) r.raise_for_status() successfull = True except Exception: successfull = False module_logger.error("message") finally: QApplication.restoreOverrideCursor() title = _("Connection Test") if successfull: QMessageBox.information( self, title, _('Connection to SC2 client API established!')) else: QMessageBox.warning( self, title, _('Unable to connect to SC2 client API.' ' Please make sure that SC2 is currently' ' running on that machine.')) def createOcrBox(self): """Create forms for OCR.""" self.ocrBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox( _("Optical Character Recognition for" " Automatic Setting of Ingame Score")) layout = QGridLayout() self.cb_useocr = QCheckBox(" " + _("Activate Optical Character Recognition")) self.cb_useocr.setChecked( scctool.settings.config.parser.getboolean("SCT", "use_ocr")) self.cb_useocr.stateChanged.connect(self.changed) self.tesseract = MonitoredLineEdit() self.tesseract.setText( scctool.settings.config.parser.get("SCT", "tesseract")) self.tesseract.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.tesseract.setPlaceholderText( "C:\\Program Files (x86)\\Tesseract-OCR\\tesseract") self.tesseract.setReadOnly(True) self.tesseract.setToolTip(_('Tesseract-OCR Executable')) self.browse = QPushButton(_("Browse...")) self.browse.clicked.connect(self.selectTesseract) text = _( "Sometimes the order of players given by the SC2-Client-API" " differs from the order in the Observer-UI resulting in a" " swapped match score. To correct this via Optical Character" " Recognition you have to download {} and install and select the" " exectuable below, if it is not detected automatically.") url = 'https://github.com/UB-Mannheim/tesseract' + \ '/wiki#tesseract-at-ub-mannheim' href = "<a href='{}'>" + "Tesseract-OCR" + "</a>" href = href.format(url) label = QLabel(text.format(href)) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 2) layout.addWidget(self.cb_useocr, 0, 0, 1, 2) layout.addWidget(QLabel(_("Tesseract-OCR Executable") + ":"), 2, 0) layout.addWidget(self.tesseract, 3, 0) layout.addWidget(self.browse, 3, 1) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.ocrBox.setLayout(mainLayout) if (not scctool.settings.windows): self.cb_useocr.setEnabled(False) self.cb_useocr.setAttribute(Qt.WA_AlwaysShowToolTips) self.cb_useocr.setToolTip( _("This feature is only available in Windows.")) self.tesseract.setEnabled(False) self.tesseract.setAttribute(Qt.WA_AlwaysShowToolTips) self.tesseract.setToolTip( _("This feature is only available in Windows.")) self.browse.setEnabled(False) self.browse.setAttribute(Qt.WA_AlwaysShowToolTips) self.browse.setToolTip( _("This feature is only available in Windows.")) def selectTesseract(self): """Create forms for tesseract.""" old_exe = self.tesseract.text() default = scctool.settings.config.findTesserAct(old_exe) exe, ok = QFileDialog.getOpenFileName( self, _("Select Tesseract-OCR Executable"), default, _("Tesseract-OCR Executable") + " (tesseract.exe);; " + _("Executable") + " (*.exe);; " + _("All files") + " (*)") if (ok and exe != old_exe): self.tesseract.setText(exe) self.changed() def createAligulacTab(self): """Create the aligulac tab.""" self.aligulacTab = QWidget() layout = QGridLayout() self.aligulacTreeview = AligulacTreeView( self, self.controller.aligulacManager) layout.addWidget(self.aligulacTreeview, 0, 0, 3, 1) self.pb_addAligulacID = QPushButton(_("Add Aligluac ID")) self.pb_addAligulacID.clicked.connect( lambda x, self=self: self.addAligulacID()) layout.addWidget(self.pb_addAligulacID, 1, 1) self.pb_removeAligulacID = QPushButton(_("Remove Aligulac ID")) self.pb_removeAligulacID.clicked.connect(self.removeAligulacID) layout.addWidget(self.pb_removeAligulacID, 2, 1) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), 0, 1) self.aligulacTab.setLayout(layout) def addAligulacID(self, name='', aligulac_id=1): """Add an aligulac ID.""" text, ok = QInputDialog.getText(self, _('Player Name'), _('Player Name') + ':', text=name) text = text.strip() if not ok or not text: return aligulac_id, ok = QInputDialog.getInt(self, _('Aligulac ID'), _('Aligulac ID') + ':', value=aligulac_id, min=1) if not ok: return self.aligulacTreeview.insertItem(text, aligulac_id) def removeAligulacID(self): """Remove an selected aligulac ID.""" self.aligulacTreeview.removeSelected() def createCounterTab(self): """Create the aligulac tab.""" self.counterTab = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("Countdown")) layout = QFormLayout() self.le_countdown_replacement = QLineEdit() self.le_countdown_replacement.setText( scctool.settings.config.parser.get("Countdown", "replacement")) self.le_countdown_replacement.textChanged.connect(self.changed) layout.addRow(QLabel(_('Replacement Text')), self.le_countdown_replacement) self.cb_counter_matchgrabber_update = QCheckBox('') self.cb_counter_matchgrabber_update.setChecked( scctool.settings.config.parser.getboolean("Countdown", "matchgrabber_update")) self.cb_counter_matchgrabber_update.stateChanged.connect(self.changed) layout.addRow(QLabel(_('Update Static Countdown via MatchGrabber')), self.cb_counter_matchgrabber_update) self.counter_pretext = QPlainTextEdit() self.counter_pretext.setPlainText( scctool.settings.config.parser.get("Countdown", "pre_txt")) self.counter_pretext.textChanged.connect(self.changed) self.counter_posttext = QPlainTextEdit() self.counter_posttext.setPlainText( scctool.settings.config.parser.get("Countdown", "post_txt")) self.counter_posttext.textChanged.connect(self.changed) layout.addRow(QLabel(_('Pre-Text (in countdown.txt)')), self.counter_pretext) layout.addRow(QLabel(_('Post-Text (in countdown.txt)')), self.counter_posttext) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Ticker")) layout = QFormLayout() box.setLayout(layout) self.ticker_pretext = QLineEdit() self.ticker_pretext.setText( scctool.settings.config.parser.get("Ticker", "prefix")) self.ticker_pretext.textChanged.connect(self.changed) layout.addRow(QLabel(_('Prefix text (in ticker.txt)')), self.ticker_pretext) mainLayout.addWidget(box) self.counterTab.setLayout(mainLayout) def createMapsBox(self): """Create box for map manager.""" self.mapsize = 300 self.mapsBox = QWidget() layout = QGridLayout() self.maplist = QListWidget() self.maplist.setSortingEnabled(True) for sc2map in scctool.settings.maps: self.maplist.addItem(QListWidgetItem(sc2map)) self.maplist.setCurrentItem(self.maplist.item(0)) self.maplist.currentItemChanged.connect(self.changePreview) # self.maplist.setFixedHeight(self.mapsize) self.maplist.setMinimumWidth(150) layout.addWidget(self.maplist, 0, 1, 2, 1) self.mapPreview = QLabel() self.mapPreview.setFixedWidth(self.mapsize) self.mapPreview.setFixedHeight(self.mapsize) self.mapPreview.setAlignment(Qt.AlignCenter) layout.addWidget(self.mapPreview, 0, 0) self.mapInfo = QLabel() self.mapInfo.setIndent(10) layout.addWidget(self.mapInfo, 1, 0) self.pb_addMapLiquipedia = QPushButton(_("Add from Liquipedia")) self.pb_addMapLiquipedia.clicked.connect(self.addFromLquipedia) self.pb_addMap = QPushButton(_("Add from File")) self.pb_addMap.clicked.connect(self.addMap) self.pb_renameMap = QPushButton(_("Rename")) self.pb_renameMap.clicked.connect(self.renameMap) self.pb_changeMap = QPushButton(_("Change Image")) self.pb_changeMap.clicked.connect(self.changeMap) self.pb_removeMap = QPushButton(_("Remove")) self.pb_removeMap.clicked.connect(self.deleteMap) self.sc_removeMap = QShortcut(QKeySequence("Del"), self.maplist) self.sc_removeMap.setAutoRepeat(False) self.sc_removeMap.setContext(Qt.WidgetWithChildrenShortcut) self.sc_removeMap.activated.connect(self.deleteMap) self.cb_newMapsPrompt = QCheckBox( _('Prompt to download new ladders maps.')) self.cb_newMapsPrompt.setChecked( scctool.settings.config.parser.getboolean("SCT", "new_maps_prompt")) self.cb_newMapsPrompt.stateChanged.connect(self.changed) self.pb_downloadLadderMaps = QPushButton(_("Download Ladder Maps")) self.pb_downloadLadderMaps.clicked.connect(self.downloadLadderMaps) box = QWidget() container = QHBoxLayout() container.addWidget(self.pb_addMapLiquipedia, 0) container.addWidget(self.pb_addMap, 0) container.addWidget(QLabel(), 1) container.addWidget(self.pb_downloadLadderMaps, 0) container.addWidget(QLabel(), 1) container.addWidget(self.pb_renameMap, 0) container.addWidget(self.pb_changeMap, 0) container.addWidget(self.pb_removeMap, 0) box.setLayout(container) layout.addWidget(box, 2, 0, 1, 2) layout.addWidget(self.cb_newMapsPrompt, 3, 0, 1, 1) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 3, 2, 1, 2) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 4, 0, 1, 2) self.changePreview() self.mapsBox.setLayout(layout) def renameMap(self): """Rename maps.""" item = self.maplist.currentItem() mapname = item.text() text, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=mapname) if not ok: return text = text.strip() if (text == mapname): return if text.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format(text)) return if (text in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map is already in list! Overwrite?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: return self.controller.addMap(self.controller.getMapImg(mapname, True), text) self.controller.deleteMap(mapname) item.setText(text) def changeMap(self): """Change a map.""" current_map = self.maplist.currentItem().text() fileName, ok = QFileDialog.getOpenFileName( self, _("Select Map Image (> 500x500px recommended)"), "", _("Supported Images") + " (*.png *.jpg *.jpeg)") if ok: base = os.path.basename(fileName) name, __ = os.path.splitext(base) name = name.replace("_", " ") self.controller.deleteMap(current_map) self.controller.addMap(fileName, current_map) self.changePreview() def addMap(self): """Add a map.""" fileName, ok = QFileDialog.getOpenFileName( self, _("Select Map Image (> 500x500px recommended)"), "", _("Supported Images") + " (*.png *.jpg *.jpeg)") if ok: base = os.path.basename(fileName) name, __ = os.path.splitext(base) name = name.replace("_", " ") map_name, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=name) map_name = map_name.strip() if ok: if map_name.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format(map_name)) return if (map_name in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map is already in list! Overwrite?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: return else: self.controller.deleteMap(map_name) self.controller.addMap(fileName, map_name) items = self.maplist.findItems(map_name, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(map_name) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() def downloadLadderMaps(self): players_per_team, ok = QInputDialog.getItem( self, _('Select the type of ladder maps to download'), _('Please select a map type') + ':', ['1vs1', '2vs2', '3vs3', '4vs4'], editable=False) players_per_team = int(players_per_team[0]) found_a_map = False for sc2map in LiquipediaGrabber().get_ladder_mappool(players_per_team): if not sc2map in scctool.settings.maps: found_a_map = True self.controller.autoDownloadMap(sc2map, self) scctool.settings.maps.append(sc2map) items = self.maplist.findItems(sc2map, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(sc2map) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() if not found_a_map: QMessageBox.information( self, _("No missing map"), _('All of the current ladder maps are already present.')) def addFromLquipedia(self): """Add a map from Liquipedia.""" grabber = LiquipediaGrabber() search_str = '' while True: search_str, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=search_str) search_str.strip() try: if ok and search_str: if search_str.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format( search_str)) continue try: QApplication.setOverrideCursor(Qt.WaitCursor) sc2map = grabber.get_map(search_str) except MapNotFound: QMessageBox.critical( self, _("Map not found"), _('"{}" was not found on Liquipedia.').format( search_str)) continue finally: QApplication.restoreOverrideCursor() map_name = sc2map.get_name() if (map_name in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map {} is already in list! Overwrite?".format( map_name)), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: break else: self.controller.deleteMap(map_name) try: QApplication.setOverrideCursor(Qt.WaitCursor) images = grabber.get_images(sc2map.get_map_images()) image = "" for size in sorted(images): if not image or size <= 2500 * 2500: image = images[size] url = grabber._base_url + image downloader = MapDownloader(self, map_name, url) downloader.download() if map_name not in scctool.settings.maps: scctool.settings.maps.append(map_name) items = self.maplist.findItems(map_name, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(map_name) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() except Exception: raise finally: QApplication.restoreOverrideCursor() except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) break def deleteMap(self): """Delete a map.""" item = self.maplist.currentItem() mapname = item.text() buttonReply = QMessageBox.question( self, _('Delete map?'), _("Delete '{}' permanently?").format(mapname), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.controller.deleteMap(mapname) self.maplist.takeItem(self.maplist.currentRow()) def changePreview(self): """Change the map preview.""" if self.maplist.count() < 1: return mapname = self.maplist.currentItem().text() if (mapname == "TBD"): self.pb_renameMap.setEnabled(False) self.pb_removeMap.setEnabled(False) self.sc_removeMap.setEnabled(False) else: self.pb_removeMap.setEnabled(True) self.pb_renameMap.setEnabled(True) self.sc_removeMap.setEnabled(True) file = self.controller.getMapImg(mapname, True) pixmap = QPixmap(file) height = pixmap.height() width = pixmap.width() ext = os.path.splitext(file)[1].replace(".", "").upper() size = humanize.naturalsize(os.path.getsize(file)) pixmap = QPixmap(file).scaled(self.mapsize, self.mapsize, Qt.KeepAspectRatio) self.mapPreview.setPixmap(pixmap) text = f"{width}x{height}px, {size}, {ext}" self.mapInfo.setText(text) def createButtonGroup(self): """Create buttons.""" try: layout = QHBoxLayout() layout.addWidget(QLabel("")) buttonCancel = QPushButton(_('Cancel')) buttonCancel.clicked.connect(self.closeWindow) layout.addWidget(buttonCancel) buttonSave = QPushButton(_('&Save && Close')) buttonSave.setToolTip(_("Shortcut: {}").format("Ctrl+S")) self.shortcut = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcut.setAutoRepeat(False) self.shortcut.activated.connect(self.saveCloseWindow) buttonSave.clicked.connect(self.saveCloseWindow) layout.addWidget(buttonSave) self.buttonGroup = layout except Exception: module_logger.exception("message") def saveData(self): """Save the data.""" if (self.__dataChanged): scctool.settings.config.parser.set( "SCT", "myteams", ", ".join(self.list_favTeams.getData())) scctool.settings.config.parser.set( "SCT", "commonplayers", ", ".join(self.list_favPlayers.getData())) scctool.settings.config.parser.set("SCT", "tesseract", self.tesseract.text().strip()) scctool.settings.config.parser.set("SCT", "use_ocr", str(self.cb_useocr.isChecked())) scctool.settings.config.parser.set( "SCT", "new_maps_prompt", str(self.cb_newMapsPrompt.isChecked())) scctool.settings.config.parser.set( "SCT", "transparent_match_banner", str(self.cb_trans_banner.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftS", str(self.cb_ctrlshifts.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftC", str(self.cb_ctrlshiftc.isChecked())) scctool.settings.config.parser.set( "SCT", "swap_myteam", str(self.cb_swapTeams.isChecked())) scctool.settings.config.parser.set("SCT", "CtrlN", str(self.cb_ctrln.isChecked())) scctool.settings.config.parser.set("SCT", "CtrlX", str(self.cb_ctrlx.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftR", str(self.cb_ctrlshiftr.currentText())) scctool.settings.config.parser.set( "SCT", "blacklist_on", str(self.cb_blacklist.isChecked())) scctool.settings.config.parser.set( "SCT", "blacklist", ", ".join(self.list_blacklist.getData())) scctool.settings.config.parser.set( "SCT", "sc2_network_listener_address", self.listener_address.text().strip()) scctool.settings.config.parser.set( "SCT", "sc2_network_listener_enabled", str(self.cb_usesc2listener.isChecked())) scctool.settings.config.parser.set( "Countdown", "matchgrabber_update", str(self.cb_counter_matchgrabber_update.isChecked())) scctool.settings.config.parser.set( "Countdown", "replacement", self.le_countdown_replacement.text()) scctool.settings.config.parser.set( "Countdown", "pre_txt", self.counter_pretext.toPlainText()) scctool.settings.config.parser.set( "Countdown", "post_txt", self.counter_posttext.toPlainText()) scctool.settings.config.parser.set( "Ticker", "prefix", self.ticker_pretext.text().strip()) self.controller.matchControl.tickerChanged.emit() self.controller.refreshButtonStatus() # self.controller.setCBS() self.__dataChanged = False def saveCloseWindow(self): """Save and close window.""" self.saveData() self.passEvent = True self.close() def closeWindow(self): """Close window.""" self.passEvent = True self.close() def closeEvent(self, event): """Handle close event.""" try: self.mainWindow.updateAllMapCompleters() if (not self.__dataChanged): event.accept() return if (not self.passEvent): if (self.isMinimized()): self.showNormal() buttonReply = QMessageBox.question( self, _('Save data?'), _("Save data?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.saveData() event.accept() except Exception: module_logger.exception("message")
class BetterEditor: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value("locale/userLocale")[0:2] locale_path = os.path.join(self.plugin_dir, "i18n", "BetterEditor_{}.qm".format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Init settings self.settings = QSettings() self.settings.beginGroup("plugins/bettereditor") # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate("BetterEditor", message) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" # Create settings dialog self.settings_dialog = SettingsDialog(self.settings, self.iface.mainWindow()) self.settings_dialog.settingsChanged.connect(self.on_settings_changed) # Show Python console to trigger its creation self.python_console = self.iface.mainWindow().findChild(PythonConsole) if not self.python_console: self.iface.actionShowPythonDialog().trigger() self.python_console = self.iface.mainWindow().findChild( PythonConsole) self.python_console.hide() self.iface.actionShowPythonDialog().setChecked(False) self.about_action = QAction( QIcon(":/plugins/bettereditor/icons/about.svg"), self.tr("About"), parent=self.iface.mainWindow(), ) self.about_action.triggered.connect(self.show_about) self.settings_action = QAction( QIcon(":/images/themes/default/console/iconSettingsConsole.svg"), self.tr("Settings"), parent=self.iface.mainWindow(), ) self.settings_action.triggered.connect(self.show_settings) self.plugin_menu = self.iface.pluginMenu().addMenu( QIcon(":/plugins/bettereditor/icons/icon.svg"), "Better Editor") self.plugin_menu.addAction(self.about_action) self.plugin_menu.addAction(self.settings_action) self.toolbar = self.python_console.findChild(QToolBar) self.tab_widget = self.python_console.findChild(EditorTabWidget) # Connect current self.tab_widget.currentChanged.connect(self.customize_current_editor) # Tweak zoom shortcuts to prevent them from interfering # when typing '|' and '}' with an AZERTY (French) keyboard layout action_zoom_in = self.iface.mainWindow().findChild( QAction, "mActionZoomIn") action_zoom_out = self.iface.mainWindow().findChild( QAction, "mActionZoomOut") action_zoom_in.setShortcut("") action_zoom_out.setShortcut("") self.iface.initializationCompleted.connect( self.on_initialization_completed) for shortcut_name in ( "ZoomInToCanvas", "ZoomInToCanvas2", "ZoomIn2", "ZoomOutOfCanvas", ): shortcut = self.iface.mainWindow().findChild( QShortcut, shortcut_name) if shortcut: shortcut.setParent(self.iface.mapCanvas()) shortcut.setContext(Qt.WidgetWithChildrenShortcut) self.zoom_out_shortcut = QShortcut("Ctrl+Alt+-", self.iface.mapCanvas()) self.zoom_out_shortcut.setObjectName("MyZoomOut") self.zoom_out_shortcut.setContext(Qt.WidgetWithChildrenShortcut) self.zoom_out_shortcut.activated.connect(action_zoom_out.trigger) # Customize buttons tooltips save_button = self.python_console.widget().saveFileButton saveas_button = self.python_console.widget().saveAsFileButton run_button = self.python_console.widget().runScriptEditorButton save_button.setToolTip(f"<b>{save_button.text()}</b> (Ctrl+S)") saveas_button.setToolTip( f"<b>{saveas_button.text()}</b> (Ctrl+Shift+S)") run_button.setToolTip(f"<b>{run_button.text()}</b> (Ctrl+R)") # Create our own toggle comment action separator = self.toolbar.addSeparator() separator = separator.setObjectName("separator") self.toggle_comment_action = self.toolbar.addAction( QIcon( ":/images/themes/default/console/iconCommentEditorConsole.svg" ), self.tr("Toggle Comment"), ) self.toggle_comment_action.setObjectName("toggleComment") self.toggle_comment_action.triggered.connect(self.toggle_comment) self.toggle_comment_action.setShortcut("Ctrl+:") self.toggle_comment_action.setToolTip( f"<b>{self.toggle_comment_action.text()}</b> ({self.toggle_comment_action.shortcut().toString()})" ) # Check that submodules are installed self.black = None self.jedi = None self.check_dependencies() # Add format action self.format_action = self.toolbar.addAction( QIcon(r":/plugins/bettereditor/icons/wizard.svg"), self.tr("Format file")) self.format_action.setObjectName("format") self.format_action.setShortcut("Ctrl+Alt+F") self.format_action.triggered.connect(self.format_file) self.format_action.setToolTip( f"<b>{self.format_action.text()}</b> ({self.format_action.shortcut().toString()})" ) if not self.black: self.format_action.setEnabled(False) self.project = None if self.jedi: self.project = self.jedi.Project("", sys_path=sys.path, load_unsafe_extensions=True, smart_sys_path=False) patch(Editor, MonkeyEditor) patch(EditorTab, MonkeyEditorTab) patch(ScriptEdit, MonkeyScriptEditor) patch(ScriptEditorDialog, MonkeyScriptEditorDialog) ScriptEdit.project = self.project ScriptEdit.settings = self.settings self.oldAutoCloseBracketEditor = QSettings().value( "pythonConsole/autoCloseBracketEditor", False, bool) QSettings().setValue("pythonConsole/autoCloseBracketEditor", False) # Add insert icon from ressource action self.insert_resource_action = self.toolbar.addAction( QIcon(":/images/themes/default/propertyicons/diagram.svg"), self.tr("Insert resource path"), ) self.insert_resource_action.setObjectName("insertResource") self.insert_resource_action.triggered.connect(self.insert_resource) self.insert_resource_action.setToolTip( f"<b>{self.insert_resource_action.text()}</b>") # Add next / previous tab shortcuts self.next_tab_shortcut = QShortcut("Ctrl+PgDown", self.python_console) self.next_tab_shortcut.setObjectName("NextTab") self.next_tab_shortcut.activated.connect(self.go_to_next_tab) self.previous_tab_shortcut = QShortcut("Ctrl+PgUp", self.python_console) self.previous_tab_shortcut.setObjectName("PreviousTab") self.previous_tab_shortcut.activated.connect(self.go_to_previous_tab) self.on_settings_changed() if not self.black or not self.jedi: if not check_pip(): QMessageBox.warning( self.iface.mainWindow(), self.tr("Error"), self. tr("Pip is not installed. Try to get it, then restart QGIS, or manually install <b>black</b> and <b>jedi</b>" ), ) else: if not self.black: QMessageBox.warning( self.iface.mainWindow(), self.tr("Error"), self. tr("Unable to load <b>black</b>. Formatting will be disabled. You could try to manually install <b>black</b> with pip" ), ) if not self.jedi: # If check_module return true, an obsolete version was loaded, ad user was already informed if not check_module("jedi"): QMessageBox.warning( self.iface.mainWindow(), self.tr("Error"), self. tr("Unable to load <b>jedi</b>. Multi syntax error check will be disabled. You could try to manually install <b>jedi</b> with pip" ), ) def check_dependencies(self): install("packaging") self.black, _ = import_or_install("black") self.jedi, jedi_version = import_or_install("jedi") # JEDI 0.17 is required if not check_minimum_version(jedi_version, "0.17"): res = QMessageBox.question( self.iface.mainWindow(), self.tr("Information"), self. tr("<b>jedi</b> version is {0} and BetterEditor needs {1}. Do you want to upgrade <b>jedi</b>?<br><b>Warning:</b> it could cause old code relying on the obsolete <b>jedi</b> to stop working correctly." ).format(jedi_version, "0.17"), QMessageBox.Yes | QMessageBox.No, ) if res == QMessageBox.Yes: install("jedi", True) QMessageBox.information( self.iface.mainWindow(), self.tr("Information"), self. tr("Jedi was upgraded. You need to restart QGIS to fully use BetterEditor" ), ) self.jedi = None def on_initialization_completed(self): """ Called after QGIS has completed its initialization """ # Shortcuts are created after plugins for shortcut_name in ( "ZoomInToCanvas", "ZoomInToCanvas2", "ZoomIn2", "ZoomOutOfCanvas", ): shortcut = self.iface.mainWindow().findChild( QShortcut, shortcut_name) if shortcut: shortcut.setParent(self.iface.mapCanvas()) shortcut.setContext(Qt.WidgetWithChildrenShortcut) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" # Delete Settings dialog self.settings_dialog.deleteLater() # Remove buttons tooltips save_button = self.python_console.widget().saveFileButton saveas_button = self.python_console.widget().saveAsFileButton run_button = self.python_console.widget().runScriptEditorButton save_button.setToolTip(save_button.text()) saveas_button.setToolTip(saveas_button.text()) run_button.setToolTip(run_button.text()) # Show comment actions self.set_old_comments_action_visible(True) # Remove custom actions for action_name in ("separator", "toggleComment", "format", "insertResource"): action = self.toolbar.findChild(QAction, action_name) if action: action.deleteLater() # Remove Next tab / previous tab shortcuts for shortcut in (self.next_tab_shortcut, self.previous_tab_shortcut): shortcut.activated.disconnect() shortcut.setEnabled(False) shortcut.deleteLater() # Reenable zoom shortcuts & actions for shortcut_name in ( "ZoomInToCanvas", "ZoomInToCanvas2", "ZoomIn2", "ZoomOutOfCanvas", ): shortcut = self.iface.mainWindow().findChild( QShortcut, shortcut_name) if shortcut: shortcut.setParent(self.iface.mainWindow()) shortcut.setContext(Qt.ApplicationShortcut) self.iface.mainWindow().findChild( QAction, "mActionZoomIn").setShortcut("Ctrl+Alt++") self.iface.mainWindow().findChild( QAction, "mActionZoomOut").setShortcut("Ctrl+Alt+-") self.zoom_out_shortcut.activated.disconnect() self.zoom_out_shortcut.setEnabled(False) self.zoom_out_shortcut.deleteLater() self.tab_widget.currentChanged.disconnect( self.customize_current_editor) for editor in self.python_console.findChildren(Editor): clear_all_indicators(editor) self.restore_editor(editor) # Revert MonkeyPatch unpatch(Editor) unpatch(EditorTab) unpatch(ScriptEdit) unpatch(ScriptEditorDialog) del ScriptEdit.project del ScriptEdit.settings # Remove menu from plugins menu self.iface.pluginMenu().removeAction(self.plugin_menu.menuAction()) # Reactivate old autoCloseBracketEditor QSettings().setValue("pythonConsole/autoCloseBracketEditor", self.oldAutoCloseBracketEditor) def current_editor(self) -> Editor: if not self.tab_widget.currentWidget(): return None return self.tab_widget.currentWidget().findChild(Editor) def toggle_comment(self): self.current_editor().toggle_comment() def format_file(self): self.current_editor().format_file() def insert_resource(self): self.current_editor().insert_resource() def go_to_next_tab(self): self.tab_widget.setCurrentIndex( (self.tab_widget.currentIndex() + 1) % self.tab_widget.count()) def go_to_previous_tab(self): self.tab_widget.setCurrentIndex( (self.tab_widget.currentIndex() - 1) % self.tab_widget.count()) def show_about(self): # Used to display plugin icon in the about message box bogus = QWidget(self.iface.mainWindow()) bogus.setWindowIcon(QIcon(":/plugins/bettereditor/icons/icon.svg")) cfg = configparser.ConfigParser() cfg.read(os.path.join(os.path.dirname(__file__), "metadata.txt")) version = cfg.get("general", "version") QMessageBox.about( bogus, self.tr("About Better Editor"), "<b>Version</b> {0}<br><br>" "<b>{1}</b> : <a href=https://github.com/YoannQDQ/qgis-better-editor>GitHub</a><br>" "<b>{2}</b> : <a href=https://github.com/YoannQDQ/qgis-better-editor/issues>GitHub</a><br>" "<b>{3}</b> : <a href=https://github.com/YoannQDQ/qgis-better-editor#better-editor-qgis-plugin>GitHub</a>" .format( version, self.tr("Source code"), self.tr("Report issues"), self.tr("Documentation"), ), ) bogus.deleteLater() def set_old_comments_action_visible(self, value): self.toolbar.actions()[13].setVisible(value) self.toolbar.actions()[14].setVisible(value) self.toolbar.actions()[15].setVisible(value) def show_settings(self): self.settings_dialog.show() self.settings_dialog.raise_() def on_settings_changed(self): # Hide / Show old comment actions self.set_old_comments_action_visible( not self.settings.value("hide_old_comment_actions", True, bool)) for editor in self.python_console.findChildren(Editor): self.customize_editor(editor) def customize_current_editor(self): return self.customize_editor() def customize_editor(self, editor: Editor = None): if editor is None: editor = self.current_editor() if editor is None: return editor.project = self.project # Disable shortcuts for shortcut in editor.findChildren(QShortcut): shortcut.setEnabled(False) editor.set_completer(QCompleter(editor)) editor.completer.setModel(CompletionModel([], editor)) editor.callTips = CallTips(editor) editor.callTipsTimer = QTimer(editor) editor.callTipsTimer.setSingleShot(True) editor.callTipsTimer.setInterval(500) editor.callTipsTimer.timeout.connect(editor.update_calltips) editor.setCallTipsStyle(QsciScintilla.CallTipsNone) editor.setAutoCompletionSource(QsciScintilla.AcsNone) editor.setFolding( self.settings.value("folding_style", QsciScintilla.BoxedTreeFoldStyle, int)) # Add a small margin after the indicator (if folding is not Plain or None) if editor.folding() > 1: editor.setMarginWidth(3, "0") else: editor.setMarginWidth(3, "") if self.settings.value("ruler_visible", True, bool): editor.setEdgeMode(QsciScintilla.EdgeLine) editor.setEdgeColumn( self.settings.value("max_line_length", 88, int)) editor.setEdgeColor( self.settings.value("ruler_color", QColor("#00aaff"), QColor)) else: editor.setEdgeMode(QsciScintilla.EdgeNone) # Change syntax error marker define_indicators(editor) editor.cursorPositionChanged.connect(editor.on_position_changed) def restore_editor(self, editor: Editor): editor.cursorPositionChanged.disconnect(editor.on_position_changed) editor.setFolding(QsciScintilla.PlainFoldStyle) editor.setEdgeMode(QsciScintilla.EdgeLine) editor.setEdgeColumn(80) editor.setMarginWidth(3, "") editor.setEdgeColor(QSettings().value("pythonConsole/edgeColorEditor", QColor("#efefef"), QColor)) # Disable shortcuts for shortcut in editor.findChildren(QShortcut): shortcut.setEnabled(True) editor.markerDefine( QgsApplication.getThemePixmap( "console/iconSyntaxErrorConsole.svg"), editor.MARKER_NUM, ) editor.setAnnotationDisplay(QsciScintilla.AnnotationBoxed) editor.setCallTipsStyle(QsciScintilla.CallTipsNoContext) editor.setAutoCompletionSource(QsciScintilla.AcsAll) editor.callTips.deleteLater() del editor.callTips editor.callTipsTimer.deleteLater() del editor.callTipsTimer editor.completer.deleteLater() del editor.completer del editor.project
def make_shortcut(self): shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_L), self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(self.controller.show_location_toolbar) def show_filter(): self.file_filter.setFocus(Qt.ShortcutFocusReason) self.filter_toolbar.show() shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_K), self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(show_filter) shortcut = QShortcut(QKeySequence(Qt.Key_F3), self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(self.controller.show_search) shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(self.controller.show_search) shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(self.controller.close_window) shortcut = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Up), self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(self.controller.parent_directory) shortcut = QShortcut(Qt.Key_Home, self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(lambda: self.file_view.ensureVisible(0, 0, 1, 1)) shortcut = QShortcut(Qt.Key_End, self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect( lambda: self.file_view.ensureVisible( 0, self.file_view._layout.get_bounding_rect().height(), 1, 1)) shortcut = QShortcut(Qt.Key_PageUp, self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(lambda: self.file_view.scroll_by(0, -self.file_view.viewport().height())) shortcut = QShortcut(Qt.Key_PageDown, self) shortcut.setContext(Qt.WindowShortcut) shortcut.activated.connect(lambda: self.file_view.scroll_by(0, self.file_view.viewport().height()))
class My_MainWindow(Ui_MainWindow): def __init__(self): super().__init__() self.tree_model = None self.running_threads = set() self.downloaded_class = set() self.best_schedules = [] self.solve_schedule_thread = None self.req_breaks = [] def setupUi(self, MainWindow): super().setupUi(MainWindow) self.tree_model = ClassTreeModel() self.treeView.setModel(self.tree_model) self.treeView.setColumnWidth(0, 180) self.treeView.setColumnWidth(1, 80) self.treeView.setColumnWidth(2, 80) self.treeView.setColumnWidth(6, 80) # signals to add courses self.addClassButton.clicked.connect(self.retrieve_class_on_click) self.classNameLineEdit.returnPressed.connect( self.retrieve_class_on_click) # set up schedule ploting area self.plot_canvas = FigureCanvas(Figure(figsize=(12, 6))) self.plot_canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.scheduleTabHorizontalLayout.addWidget(self.plot_canvas) self.plot_ax = self.plot_canvas.figure.subplots() self.show_time_table() # signals to update schedules calculations self.updatPushButton.clicked.connect(self.calculate_schedules) # signals to handle schedule list selection self.scheduleScoreTreeWidget.itemSelectionChanged.connect( self.handle_score_list_selection) # signals to handle policy page actions self.earlyPenaltyLineEdit.textEdited.connect( self.handle_early_penalty_line_edit_change) self.latePenaltyLineEdit.textEdited.connect( self.handle_late_penalty_line_edit_change) self.intervalPenaltyLineEdit.textChanged.connect( self.handle_interval_penalty_line_edit_change) self.requiredBreaksLineEdit.textChanged.connect( self.handle_breaks_line_edit_change) self.addBreakPushButton.clicked.connect(self.add_required_breaks) self.delete_break_short_cut = QShortcut( QKeySequence(QKeySequence.Delete), self.breakTreeWidget) self.delete_break_short_cut.setContext(Qt.WidgetShortcut) self.delete_break_short_cut.activated.connect( self.delete_selected_break) self.delete_course_short_cut = QShortcut( QKeySequence(QKeySequence.Delete), self.treeView) self.delete_course_short_cut.setContext(Qt.WidgetShortcut) self.delete_course_short_cut.activated.connect( self.delete_selected_course) def retrieve_class_on_click(self): term = self.termLineEdit.text() class_name = self.classNameLineEdit.text().upper() url = 'https://classes.usc.edu/term-' + term + '/course/' + class_name + '/' if class_name in self.downloaded_class: QMessageBox(QMessageBox.Warning, "Already Exists", class_name + " already exists.", QMessageBox.Close).exec() return self.downloaded_class.add(class_name) thread = LoadClassThread(url, class_name) self.running_threads.add(thread) thread.results_ready.connect(self.add_class) msg = "Downloading" for running_thread in self.running_threads: msg += " " + running_thread.name msg += " ..." self.statusBar.showMessage(msg) thread.start() def add_class(self, thread): self.running_threads.remove(thread) if self.running_threads: msg = "Downloading" for running_thread in self.running_threads: msg += " " + running_thread.name msg += " ..." self.statusBar.showMessage(msg) else: self.statusBar.clearMessage() if thread.root is None: QMessageBox( QMessageBox.Warning, "Download Failed", "Invalid term / course name or bad Internet connection.\n" + thread.url, QMessageBox.Close).exec() self.downloaded_class.remove(thread.name) return self.tree_model.add_top_level_child(thread.root) def show_time_table(self, sections=None): if sections is None: sections = [] self.plot_ax.clear() for section in sections: for day in section.days_list: bar_bottom = section.start_end[0] bar_height = section.start_end[1] - section.start_end[0] self.plot_ax.bar(day, bar_height, width=0.92, bottom=bar_bottom, linewidth=0, fc='#3CA730') description = (section.name + " " + section.section_id + " " + section.section_type[:4]) self.plot_ax.text(day, bar_bottom + bar_height / 2, description, horizontalalignment='center', verticalalignment='center', fontfamily='Nirmala UI', color='white', fontsize='medium') self.plot_ax.set_axisbelow(True) self.plot_ax.minorticks_on() self.plot_ax.set_xticks([0, 1, 2, 3, 4]) self.plot_ax.set_xticks([0.5, 1.5, 2.5, 3.5], minor=True) self.plot_ax.set_yticks(range(5 * 60, 24 * 60, 60)) self.plot_ax.set_yticklabels( [str(time) + ":00" for time in range(5, 24)], fontfamily='Nirmala UI') self.plot_ax.set_yticks(range(5 * 60 + 30, 24 * 60, 60), minor=True) self.plot_ax.set_xlim(-0.5, 4.5) self.plot_ax.set_ylim(23 * 60, 5 * 60) self.plot_ax.xaxis.tick_top() self.plot_ax.set_xticklabels(["Mon", "Tue", "Wed", "Thu", "Fri"], fontfamily='Nirmala UI', fontsize='x-large') # ax.grid(which = 'major', visible = False) self.plot_ax.grid(which='minor', axis='x', linewidth=0.5, alpha=0.8) self.plot_ax.grid(which='major', axis='y', linewidth=0.5, alpha=0.8) self.plot_ax.grid(which='minor', axis='y', linewidth=0.5, alpha=0.3) self.plot_ax.tick_params(which='both', top=False, left=False, right=False, bottom=False) self.plot_ax.spines['bottom'].set_color("#bababa") self.plot_ax.spines['top'].set_color("#bababa") self.plot_ax.spines['left'].set_color("#bababa") self.plot_ax.spines['right'].set_color("#bababa") self.plot_canvas.draw() def calculate_schedules(self): if (self.solve_schedule_thread): return list_of_componets = [] self.tree_model.lock(True) for course in self.tree_model.root.data: if not course.is_included(): continue for component in course.data: if not component.is_included(): continue list_of_sections = [ section.data for section in component.data if section.data.include ] list_of_componets.append(list_of_sections) if not list_of_componets: self.tree_model.lock(False) QMessageBox(QMessageBox.Warning, "No Course Selected", "Cannot make schedules since no course is selected.", QMessageBox.Close).exec() return if self.earlyHorizontalSlider.isEnabled(): time = qtime2minutes(self.earlyTimeEdit.time()) penalty = self.earlyHorizontalSlider.value() / 1000 early_curve = [(0, penalty * time), (time, 0)] else: early_curve = parse_ELI_penalty(self.earlyPenaltyLineEdit.text()) if early_curve is None: QMessageBox(QMessageBox.Warning, "Invalid Early Penalty", self.earlyPenaltyLineEdit.text() + " isn't valid.", QMessageBox.Close).exec() self.tree_model.lock(False) return if self.lateHorizontalSlider.isEnabled(): time = qtime2minutes(self.lateTimeEdit.time()) penalty = self.lateHorizontalSlider.value() / 1000 late_curve = [(time, 0), (1440, penalty * (1440 - time))] else: late_curve = parse_ELI_penalty(self.latePenaltyLineEdit.text()) if late_curve is None: QMessageBox(QMessageBox.Warning, "Invalid Late Penalty", self.latePenaltyLineEdit.text() + " isn't valid.", QMessageBox.Close).exec() self.tree_model.lock(False) return if self.intervalHorizontalSlider.isEnabled(): time = qtime2minutes(self.intervalTimeEdit.time()) penalty = self.intervalHorizontalSlider.value() / 1000 interval_curve = [(time, 0), (1440, penalty * (1440 - time))] else: interval_curve = parse_ELI_penalty( self.intervalPenaltyLineEdit.text()) if interval_curve is None: QMessageBox( QMessageBox.Warning, "Invalid Interval Penalty", self.intervalPenaltyLineEdit.text() + " isn't valid.", QMessageBox.Close).exec() self.tree_model.lock(False) return if self.breakTreeWidget.isEnabled(): req_breaks = self.req_breaks else: req_breaks = parse_req_breaks(self.requiredBreaksLineEdit.text()) if req_breaks is None: QMessageBox( QMessageBox.Warning, "Invalid Required Breaks", self.requiredBreaksLineEdit.text() + " isn't valid.", QMessageBox.Close).exec() self.tree_model.lock(False) return self.solve_schedule_thread = CalcScheduleThread( list_of_componets, early_curve, late_curve, interval_curve, req_breaks) self.solve_schedule_thread.results_ready.connect( self.handle_schedule_calc_results) self.solve_schedule_thread.update_count.connect( self.handle_schedule_calc_update) self.scheduleScoreTreeWidget.clear() self.scheduleDetailsTreeWidget.clear() self.solve_schedule_thread.start() def handle_schedule_calc_results(self, thread): self.tree_model.lock(False) if thread.best: self.best_schedules = [] while thread.best: self.best_schedules.append(heapq.heappop(thread.best)) self.best_schedules.reverse() num_score_pair_list = [] for i in range(len(self.best_schedules)): fields = [] fields.append(str(i + 1)) fields.append(str("{:.2f}".format(-self.best_schedules[i][0]))) fields.append(str("{:.2f}".format(self.best_schedules[i][2]))) fields.append(str("{:.2f}".format(self.best_schedules[i][3]))) fields.append(str("{:.2f}".format(self.best_schedules[i][4]))) fields.append(str("{:.2f}".format(self.best_schedules[i][5]))) num_score_pair_list.append(QTreeWidgetItem(None, fields)) self.scheduleScoreTreeWidget.insertTopLevelItems( 0, num_score_pair_list) self.solve_schedule_thread = None def handle_schedule_calc_update(self, count): self.statusBar.showMessage( "Solving for best schedules... {} valid schedules found.".format( count), 1000) def handle_score_list_selection(self): selected = self.scheduleScoreTreeWidget.selectedItems() if selected: index = self.scheduleScoreTreeWidget.indexOfTopLevelItem( selected[0]) if index >= 0 and index < len(self.best_schedules): self.show_schedule_details(self.best_schedules[index][1]) self.show_time_table(self.best_schedules[index][1]) def show_schedule_details(self, schedule): section_item_list = [] for section in schedule: fields = [] fields.append(section.name) fields.append(section.section_type) fields.append(section.section_id) fields.append(section.time) fields.append(section.days) fields.append(section.registered) fields.append("X" if section.closed else "") fields.append(section.instructor) fields.append(section.location) section_item_list.append(QTreeWidgetItem(None, fields)) self.scheduleDetailsTreeWidget.clear() self.scheduleDetailsTreeWidget.insertTopLevelItems( 0, section_item_list) def handle_early_penalty_line_edit_change(self, text): if text: self.earlyHorizontalSlider.setEnabled(False) self.earlyTimeEdit.setEnabled(False) if parse_ELI_penalty(text): self.earlyPenaltyLineEdit.setStyleSheet( "background-color: #b6fac2") else: self.earlyPenaltyLineEdit.setStyleSheet( "background-color: #fab6b6") else: self.earlyHorizontalSlider.setEnabled(True) self.earlyTimeEdit.setEnabled(True) self.earlyPenaltyLineEdit.setStyleSheet("") def handle_late_penalty_line_edit_change(self, text): if text: self.lateHorizontalSlider.setEnabled(False) self.lateTimeEdit.setEnabled(False) if parse_ELI_penalty(text): self.latePenaltyLineEdit.setStyleSheet( "background-color: #b6fac2") else: self.latePenaltyLineEdit.setStyleSheet( "background-color: #fab6b6") else: self.lateHorizontalSlider.setEnabled(True) self.lateTimeEdit.setEnabled(True) self.latePenaltyLineEdit.setStyleSheet("") def handle_interval_penalty_line_edit_change(self, text): if text: self.intervalHorizontalSlider.setEnabled(False) self.intervalTimeEdit.setEnabled(False) if parse_ELI_penalty(text): self.intervalPenaltyLineEdit.setStyleSheet( "background-color: #b6fac2") else: self.intervalPenaltyLineEdit.setStyleSheet( "background-color: #fab6b6") else: self.intervalHorizontalSlider.setEnabled(True) self.intervalTimeEdit.setEnabled(True) self.intervalPenaltyLineEdit.setStyleSheet("") def handle_breaks_line_edit_change(self, text): if text: self.addBreakPushButton.setEnabled(False) self.breakHorizontalSlider.setEnabled(False) self.breakStartTimeEdit.setEnabled(False) self.breakEndTimeEdit.setEnabled(False) self.breakLenTimeEdit.setEnabled(False) self.breakTreeWidget.setEnabled(False) if parse_req_breaks(text): self.requiredBreaksLineEdit.setStyleSheet( "background-color: #b6fac2") else: self.requiredBreaksLineEdit.setStyleSheet( "background-color: #fab6b6") else: self.addBreakPushButton.setEnabled(True) self.breakHorizontalSlider.setEnabled(True) self.breakStartTimeEdit.setEnabled(True) self.breakEndTimeEdit.setEnabled(True) self.breakLenTimeEdit.setEnabled(True) self.breakTreeWidget.setEnabled(True) self.requiredBreaksLineEdit.setStyleSheet("") def add_required_breaks(self): start = qtime2minutes(self.breakStartTimeEdit.time()) end = qtime2minutes(self.breakEndTimeEdit.time()) penalty = self.breakHorizontalSlider.value() / 5 length = qtime2minutes(self.breakLenTimeEdit.time()) if start > end: start, end = end, start self.req_breaks.append(req_break((start, end), length, penalty)) self.breakTreeWidget.clear() break_item_list = [] for some_break in self.req_breaks: fields = [] fields.append(minutes2str(some_break.start_end[0])) fields.append(minutes2str(some_break.start_end[1])) fields.append(minutes2str(some_break.length)) fields.append(str(some_break.penalty)) break_item_list.append(QTreeWidgetItem(None, fields)) self.breakTreeWidget.insertTopLevelItems(0, break_item_list) def delete_selected_break(self): selected = self.breakTreeWidget.selectedItems() if not selected: return index = self.breakTreeWidget.indexOfTopLevelItem(selected[0]) if index < len(self.req_breaks): self.req_breaks.pop(index) self.breakTreeWidget.clear() break_item_list = [] for some_break in self.req_breaks: fields = [] fields.append(minutes2str(some_break.start_end[0])) fields.append(minutes2str(some_break.start_end[1])) fields.append(minutes2str(some_break.length)) fields.append(str(some_break.penalty)) break_item_list.append(QTreeWidgetItem(None, fields)) self.breakTreeWidget.insertTopLevelItems(0, break_item_list) def delete_selected_course(self): selected = self.treeView.selectedIndexes() if selected and self.tree_model.parent(selected[0]) == QModelIndex(): name = self.tree_model.delete_top_level_child(selected[0].row()) if name in self.downloaded_class: self.downloaded_class.remove(name)
class Lookup(QWidget): MODEL_CLASS = None def __init__(self, parent, model): QWidget.__init__(self, parent, Qt.Window) self.model = model self.model.view = self self._setupUi() self.searchEdit.searchChanged.connect(self.searchChanged) self.searchEdit.returnPressed.connect(self.returnPressed) self.namesList.currentRowChanged.connect(self.currentRowChanged) self.namesList.itemDoubleClicked.connect(self.itemDoubleClicked) self._shortcutUp.activated.connect(self.upPressed) self._shortcutDown.activated.connect(self.downPressed) def _setupUi(self): self.setWindowTitle(tr("Lookup")) self.resize(314, 331) self.verticalLayout = QVBoxLayout(self) self.searchEdit = SearchEdit(self) self.verticalLayout.addWidget(self.searchEdit) self.namesList = QListWidget(self) self.namesList.setEditTriggers(QAbstractItemView.NoEditTriggers) self.namesList.setSelectionBehavior(QAbstractItemView.SelectRows) self.namesList.setUniformItemSizes(True) self.namesList.setSelectionRectVisible(True) self.verticalLayout.addWidget(self.namesList) self.searchEdit.immediate = True self._shortcutUp = QShortcut(self.searchEdit) self._shortcutUp.setKey(QKeySequence(Qt.Key_Up)) self._shortcutUp.setContext(Qt.WidgetShortcut) self._shortcutDown = QShortcut(self.searchEdit) self._shortcutDown.setKey(QKeySequence(Qt.Key_Down)) self._shortcutDown.setContext(Qt.WidgetShortcut) def _restoreSelection(self): self.namesList.setCurrentRow(self.model.selected_index) #--- Event Handlers def returnPressed(self): self.model.go() def searchChanged(self): self.model.search_query = str(self.searchEdit.text()) def currentRowChanged(self, row): if row >= 0: self.model.selected_index = row def itemDoubleClicked(self, item): self.model.go() def upPressed(self): if self.namesList.currentRow() > 0: self.namesList.setCurrentRow(self.namesList.currentRow()-1) def downPressed(self): if self.namesList.currentRow() < self.namesList.count()-1: self.namesList.setCurrentRow(self.namesList.currentRow()+1) #--- model --> view def refresh(self): self.namesList.clear() self.namesList.addItems(self.model.names) self._restoreSelection() self.searchEdit.setText(self.model.search_query) def show(self): QWidget.show(self) self.searchEdit.setFocus() # see csv_options self.raise_() def hide(self): QWidget.hide(self)
def install_shortcuts(obj, actions, ide): short = resources.get_shortcut for action in actions: short_key = action.get("shortcut", None) action_data = action.get("action", None) connect = action.get("connect", None) shortcut = None item_ui = None func = None if connect is not None: func = getattr(obj, connect, None) if short_key and not action_data: if isinstance(short_key, QKeySequence): shortcut = QShortcut(short_key, ide) else: if short(short_key) is None: logger.warning("Not shorcut for %s" % short_key) continue shortcut = QShortcut(short(short_key), ide) shortcut.setContext(Qt.ApplicationShortcut) if isinstance(func, collections.Callable): shortcut.activated.connect(func) if action_data: is_menu = action_data.get('is_menu', False) if is_menu: item_ui = QMenu(action_data['text'], ide) else: item_ui = QAction(action_data['text'], ide) object_name = "%s.%s" % (obj.__class__.__name__, connect) item_ui.setObjectName(object_name) # FIXME: Configurable item_ui.setIconVisibleInMenu(False) image_name = action_data.get('image', None) section = action_data.get('section', None) weight = action_data.get('weight', None) keysequence = action_data.get('keysequence', None) if image_name: if isinstance(image_name, int): icon = ide.style().standardIcon(image_name) item_ui.setIcon(icon) elif isinstance(image_name, str): if image_name.startswith("/home"): icon = QIcon(image_name) else: icon = QIcon(":img/" + image_name) item_ui.setIcon(icon) if short_key and not is_menu: if short(short_key) is None: logger.warning("Not shortcut for %s" % short_key) continue item_ui.setShortcut(short(short_key)) # Add tooltip with append shortcut item_ui.setToolTip( tooltip_with_shortcut(item_ui.text(), short(short_key))) item_ui.setShortcutContext(Qt.ApplicationShortcut) elif keysequence and not is_menu: item_ui.setShortcut(short(keysequence)) item_ui.setShortcutContext(Qt.ApplicationShortcut) if isinstance(func, collections.Callable) and not is_menu: item_ui.triggered.connect(lambda _, func=func: func()) if section and section[0] is not None and weight: ide.register_menuitem(item_ui, section, weight) if image_name and not is_menu: ide.register_toolbar(item_ui, section, weight) if short_key and shortcut: ide.register_shortcut(short_key, shortcut, item_ui)
class SearchWidget(QFrame): """Widget, appeared, when Ctrl+F pressed. Has different forms for different search modes """ Normal = 'normal' Good = 'good' Bad = 'bad' Incorrect = 'incorrect' visibilityChanged = pyqtSignal(bool) """ visibilityChanged(visible) **Signal** emitted, when widget has been shown or hidden """ # pylint: disable=W0105 searchInDirectoryStartPressed = pyqtSignal(type(re.compile('')), list, str) """ searchInDirectoryStartPressed(regEx, mask, path) **Signal** emitted, when 'search in directory' button had been pressed """ # pylint: disable=W0105 searchInDirectoryStopPressed = pyqtSignal() """ searchInDirectoryStopPressed() **Signal** emitted, when 'stop search in directory' button had been pressed """ # pylint: disable=W0105 replaceCheckedStartPressed = pyqtSignal(str) """ replaceCheckedStartPressed(replText) **Signal** emitted, when 'replace checked' button had been pressed """ # pylint: disable=W0105 replaceCheckedStopPressed = pyqtSignal() """ replaceCheckedStartPressed() **Signal** emitted, when 'stop replacing checked' button had been pressed """ # pylint: disable=W0105 searchRegExpChanged = pyqtSignal(type(re.compile(''))) """ searchRegExpValidStateChanged(regEx) **Signal** emitted, when search regexp has been changed. If reg exp is invalid - regEx object contains empty pattern """ # pylint: disable=W0105 searchNext = pyqtSignal() """ searchNext() **Signal** emitted, when 'Search Next' had been pressed """ # pylint: disable=W0105 searchPrevious = pyqtSignal() """ searchPrevious() **Signal** emitted, when 'Search Previous' had been pressed """ # pylint: disable=W0105 replaceFileOne = pyqtSignal(str) """ replaceFileOne(replText) **Signal** emitted, when 'Replace' had been pressed """ # pylint: disable=W0105 replaceFileAll = pyqtSignal(str) """ replaceFileAll(replText) **Signal** emitted, when 'Replace All' had been pressed """ # pylint: disable=W0105 def __init__(self, plugin): QFrame.__init__(self, core.workspace()) self._mode = None self.plugin = plugin uic.loadUi(os.path.join(os.path.dirname(__file__), 'SearchWidget.ui'), self) self.cbSearch.setCompleter(None) self.cbReplace.setCompleter(None) self.cbMask.setCompleter(None) self.fsModel = QDirModel(self.cbPath.lineEdit()) self.fsModel.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) self.cbPath.lineEdit().setCompleter(QCompleter(self.fsModel, self.cbPath.lineEdit())) self._pathBackspaceShortcut = QShortcut(QKeySequence("Ctrl+Backspace"), self.cbPath, self._onPathBackspace) self._pathBackspaceShortcut.setContext(Qt.WidgetWithChildrenShortcut) # TODO QDirModel is deprecated but QCompleter does not yet handle # QFileSystemodel - please update when possible.""" self.cbSearch.setCompleter(None) self.pbSearchStop.setVisible(False) self.pbReplaceCheckedStop.setVisible(False) self._progress = QProgressBar(self) self._progress.setAlignment(Qt.AlignCenter) self._progress.setToolTip(self.tr("Search in progress...")) self._progress.setMaximumSize(QSize(80, 16)) core.mainWindow().statusBar().insertPermanentWidget(1, self._progress) self._progress.setVisible(False) # cd up action self.tbCdUp = QToolButton(self.cbPath.lineEdit()) self.tbCdUp.setIcon(QIcon(":/enkiicons/go-up.png")) self.tbCdUp.setCursor(Qt.ArrowCursor) self.tbCdUp.installEventFilter(self) # for drawing button self.cbSearch.installEventFilter(self) # for catching Tab and Shift+Tab self.cbReplace.installEventFilter(self) # for catching Tab and Shift+Tab self.cbPath.installEventFilter(self) # for catching Tab and Shift+Tab self.cbMask.installEventFilter(self) # for catching Tab and Shift+Tab self._closeShortcut = QShortcut(QKeySequence("Esc"), self) self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut) self._closeShortcut.activated.connect(self.hide) # connections self.cbSearch.lineEdit().textChanged.connect(self._onSearchRegExpChanged) self.cbSearch.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbReplace.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbPath.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbMask.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbRegularExpression.stateChanged.connect(self._onSearchRegExpChanged) self.cbCaseSensitive.stateChanged.connect(self._onSearchRegExpChanged) self.cbWholeWord.stateChanged.connect(self._onSearchRegExpChanged) self.tbCdUp.clicked.connect(self._onCdUpPressed) self.pbNext.pressed.connect(self.searchNext) self.pbPrevious.pressed.connect(self.searchPrevious) self.pbSearchStop.pressed.connect(self.searchInDirectoryStopPressed) self.pbReplaceCheckedStop.pressed.connect(self.replaceCheckedStopPressed) core.mainWindow().hideAllWindows.connect(self.hide) core.workspace().escPressed.connect(self.hide) core.workspace().currentDocumentChanged.connect( lambda old, new: self.setVisible(self.isVisible() and new is not None)) def show(self): """Reimplemented function. Sends signal """ super(SearchWidget, self).show() self.visibilityChanged.emit(self.isVisible()) def hide(self): """Reimplemented function. Sends signal, returns focus to workspace """ super(SearchWidget, self).hide() core.workspace().focusCurrentDocument() self.visibilityChanged.emit(self.isVisible()) def setVisible(self, visible): """Reimplemented function. Sends signal """ super(SearchWidget, self).setVisible(visible) self.visibilityChanged.emit(self.isVisible()) def _regExEscape(self, text): """Improved version of re.escape() Doesn't escape space, comma, underscore. Escapes \n and \t """ text = re.escape(text) # re.escape escapes space, comma, underscore, but, it is not necessary and makes text not readable for symbol in (' ,_=\'"/:@#%&'): text = text.replace('\\' + symbol, symbol) text = text.replace('\\\n', '\\n') text = text.replace('\\\t', '\\t') return text def _makeEscapeSeqsVisible(self, text): """Replace invisible \n and \t with escape sequences """ text = text.replace('\\', '\\\\') text = text.replace('\t', '\\t') text = text.replace('\n', '\\n') return text def setMode(self, mode): """Change search mode. i.e. from "Search file" to "Replace directory" """ if self._mode == mode and self.isVisible(): if core.workspace().currentDocument() is not None and \ not core.workspace().currentDocument().hasFocus(): self.cbSearch.lineEdit().selectAll() self.cbSearch.setFocus() self._mode = mode # Set Search and Replace text document = core.workspace().currentDocument() if document is not None and \ document.hasFocus() and \ document.qutepart.selectedText: searchText = document.qutepart.selectedText self.cbReplace.setEditText(self._makeEscapeSeqsVisible(searchText)) if self.cbRegularExpression.checkState() == Qt.Checked: searchText = self._regExEscape(searchText) self.cbSearch.setEditText(searchText) if not self.cbReplace.lineEdit().text() and \ self.cbSearch.lineEdit().text() and \ not self.cbRegularExpression.checkState() == Qt.Checked: replaceText = self.cbSearch.lineEdit().text().replace('\\', '\\\\') self.cbReplace.setEditText(replaceText) # Move focus to Search edit self.cbSearch.setFocus() self.cbSearch.lineEdit().selectAll() # Set search path if mode & MODE_FLAG_DIRECTORY and \ not (self.isVisible() and self.cbPath.isVisible()): try: searchPath = os.path.abspath(str(os.path.curdir)) except OSError: # current directory might have been deleted pass else: self.cbPath.setEditText(searchPath) # Set widgets visibility flag according to state widgets = (self.wSearch, self.pbPrevious, self.pbNext, self.pbSearch, self.wReplace, self.wPath, self.pbReplace, self.pbReplaceAll, self.pbReplaceChecked, self.wOptions, self.wMask) # wSear pbPrev pbNext pbSear wRepl wPath pbRep pbRAll pbRCHK wOpti wMask visible = \ {MODE_SEARCH: (1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,), MODE_REPLACE: (1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,), MODE_SEARCH_DIRECTORY: (1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1,), MODE_REPLACE_DIRECTORY: (1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,), MODE_SEARCH_OPENED_FILES: (1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,), MODE_REPLACE_OPENED_FILES: (1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1,)} for i, widget in enumerate(widgets): widget.setVisible(visible[mode][i]) # Search next button text if mode == MODE_REPLACE: self.pbNext.setText('Next') else: self.pbNext.setText('Next↵') # Finaly show all with valid size self.show() # show before updating widgets and labels self._updateLabels() self._updateWidgets() def eventFilter(self, object_, event): """ Event filter for mode switch tool button Draws icons in the search and path lineEdits """ if event.type() == QEvent.Paint and object_ is self.tbCdUp: # draw CdUp button in search path QLineEdit toolButton = object_ lineEdit = self.cbPath.lineEdit() lineEdit.setContentsMargins(lineEdit.height(), 0, 0, 0) height = lineEdit.height() availableRect = QRect(0, 0, height, height) if toolButton.rect() != availableRect: toolButton.setGeometry(availableRect) painter = QPainter(toolButton) toolButton.icon().paint(painter, availableRect) return True elif event.type() == QEvent.KeyPress: # Tab and Shift+Tab in QLineEdits if event.key() == Qt.Key_Tab: self._moveFocus(1) return True elif event.key() == Qt.Key_Backtab: self._moveFocus(-1) return True return QFrame.eventFilter(self, object_, event) def _onReturnPressed(self): """Return or Enter pressed on widget. Search next or Replace next """ if self.pbReplace.isVisible(): self.pbReplace.click() elif self.pbNext.isVisible(): self.pbNext.click() elif self.pbSearch.isVisible(): self.pbSearch.click() elif self.pbSearchStop.isVisible(): self.pbSearchStop.click() def _onPathBackspace(self): """Ctrl+Backspace pressed on path. Remove 1 path level. Default behavior would be to remove one word on Linux or all on Windows """ path = self.cbPath.currentText() if path.endswith('/') or \ path.endswith('\\'): path = path[:-1] head, tail = os.path.split(path) if head and \ head != path: if not head.endswith(os.sep): head += os.sep self.cbPath.lineEdit().setText(head) def _moveFocus(self, step): """Move focus forward or backward according to step. Standard Qt Keyboard focus algorithm doesn't allow circular navigation """ allFocusableWidgets = (self.cbSearch, self.cbReplace, self.cbPath, self.cbMask) visibleWidgets = [widget for widget in allFocusableWidgets if widget.isVisible()] try: focusedIndex = visibleWidgets.index(QApplication.focusWidget()) except ValueError: print('Invalid focused widget in Search Widget', file=sys.stderr) return nextFocusedIndex = (focusedIndex + step) % len(visibleWidgets) visibleWidgets[nextFocusedIndex].setFocus() visibleWidgets[nextFocusedIndex].lineEdit().selectAll() def _updateLabels(self): """Update 'Search' 'Replace' 'Path' labels geometry """ width = 0 if self.lSearch.isVisible(): width = max(width, self.lSearch.minimumSizeHint().width()) if self.lReplace.isVisible(): width = max(width, self.lReplace.minimumSizeHint().width()) if self.lPath.isVisible(): width = max(width, self.lPath.minimumSizeHint().width()) self.lSearch.setMinimumWidth(width) self.lReplace.setMinimumWidth(width) self.lPath.setMinimumWidth(width) def _updateWidgets(self): """Update geometry of widgets with buttons """ width = 0 if self.wSearchRight.isVisible(): width = max(width, self.wSearchRight.minimumSizeHint().width()) if self.wReplaceRight.isVisible(): width = max(width, self.wReplaceRight.minimumSizeHint().width()) if self.wPathRight.isVisible(): width = max(width, self.wPathRight.minimumSizeHint().width()) self.wSearchRight.setMinimumWidth(width) self.wReplaceRight.setMinimumWidth(width) self.wPathRight.setMinimumWidth(width) def updateComboBoxes(self): """Update comboboxes with last used texts """ searchText = self.cbSearch.currentText() replaceText = self.cbReplace.currentText() maskText = self.cbMask.currentText() # search if searchText: index = self.cbSearch.findText(searchText) if index == -1: self.cbSearch.addItem(searchText) # replace if replaceText: index = self.cbReplace.findText(replaceText) if index == -1: self.cbReplace.addItem(replaceText) # mask if maskText: index = self.cbMask.findText(maskText) if index == -1: self.cbMask.addItem(maskText) def _searchPatternTextAndFlags(self): """Get search pattern and flags """ pattern = self.cbSearch.currentText() pattern = pattern.replace('\u2029', '\n') # replace unicode paragraph separator with habitual \n if not self.cbRegularExpression.checkState() == Qt.Checked: pattern = re.escape(pattern) if self.cbWholeWord.checkState() == Qt.Checked: pattern = r'\b' + pattern + r'\b' flags = 0 if not self.cbCaseSensitive.checkState() == Qt.Checked: flags = re.IGNORECASE return pattern, flags def getRegExp(self): """Read search parameters from controls and present it as a regular expression """ pattern, flags = self._searchPatternTextAndFlags() return re.compile(pattern, flags) def isSearchRegExpValid(self): """Try to compile search pattern to check if it is valid Returns bool result and text error """ pattern, flags = self._searchPatternTextAndFlags() try: re.compile(pattern, flags) except re.error as ex: return False, str(ex) return True, None def _getSearchMask(self): """Get search mask as list of patterns """ mask = [s.strip() for s in self.cbMask.currentText().split(' ')] # remove empty mask = [_f for _f in mask if _f] return mask def setState(self, state): """Change line edit color according to search result """ widget = self.cbSearch.lineEdit() color = {SearchWidget.Normal: QApplication.instance().palette().color(QPalette.Base), SearchWidget.Good: QColor(Qt.green), SearchWidget.Bad: QColor(Qt.red), SearchWidget.Incorrect: QColor(Qt.darkYellow)} stateColor = color[state] if state != SearchWidget.Normal: stateColor.setAlpha(100) pal = widget.palette() pal.setColor(widget.backgroundRole(), stateColor) widget.setPalette(pal) def setSearchInProgress(self, inProgress): """Search thread started or stopped """ self.pbSearchStop.setVisible(inProgress) self.pbSearch.setVisible(not inProgress) self._updateWidgets() self._progress.setVisible(inProgress) def onSearchProgressChanged(self, value, total): """Signal from the thread, progress changed """ self._progress.setValue(value) self._progress.setMaximum(total) def setReplaceInProgress(self, inProgress): """Replace thread started or stopped """ self.pbReplaceCheckedStop.setVisible(inProgress) self.pbReplaceChecked.setVisible(not inProgress) self._updateWidgets() def setSearchInFileActionsEnabled(self, enabled): """Set enabled state for Next, Prev, Replace, ReplaceAll """ for button in (self.pbNext, self.pbPrevious, self.pbReplace, self.pbReplaceAll): button.setEnabled(enabled) def _onSearchRegExpChanged(self): """User edited search text or checked/unchecked checkboxes """ valid, error = self.isSearchRegExpValid() if valid: self.setState(self.Normal) core.mainWindow().statusBar().clearMessage() self.pbSearch.setEnabled(len(self.getRegExp().pattern) > 0) else: core.mainWindow().statusBar().showMessage(error, 3000) self.setState(self.Incorrect) self.pbSearch.setEnabled(False) self.searchRegExpChanged.emit(re.compile('')) return self.searchRegExpChanged.emit(self.getRegExp()) def _onCdUpPressed(self): """User pressed "Up" button, need to remove one level from search path """ text = self.cbPath.currentText() if not os.path.exists(text): return editText = os.path.normpath(os.path.join(text, os.path.pardir)) self.cbPath.setEditText(editText) def on_pbSearch_pressed(self): """Handler of click on "Search" button (for search in directory) """ self.setState(SearchWidget.Normal) self.searchInDirectoryStartPressed.emit(self.getRegExp(), self._getSearchMask(), self.cbPath.currentText()) def on_pbReplace_pressed(self): """Handler of click on "Replace" (in file) button """ self.replaceFileOne.emit(self.cbReplace.currentText()) def on_pbReplaceAll_pressed(self): """Handler of click on "Replace all" (in file) button """ self.replaceFileAll.emit(self.cbReplace.currentText()) def on_pbReplaceChecked_pressed(self): """Handler of click on "Replace checked" (in directory) button """ self.replaceCheckedStartPressed.emit(self.cbReplace.currentText()) def on_pbBrowse_pressed(self): """Handler of click on "Browse" button. Explores FS for search directory path """ path = QFileDialog.getExistingDirectory(self, self.tr("Search path"), self.cbPath.currentText()) if path: self.cbPath.setEditText(path)
class WINENCERCLED(QWidget): def __init__(self,conf=None,name='VISU'): super().__init__() self.name=name p = pathlib.Path(__file__) if conf==None: self.conf=QtCore.QSettings(str(p.parent / 'confVisu.ini'), QtCore.QSettings.IniFormat) else : self.conf=conf sepa=os.sep self.icon=str(p.parent) + sepa+'icons' +sepa self.isWinOpen=False self.setWindowTitle('Encercled') self.setWindowIcon(QIcon(self.icon+'LOA.png')) self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) self.left=100 self.top=30 self.width=800 self.height=800 self.setGeometry(self.left,self.top,self.width,self.height) self.dimx=1200 self.dimy=900 self.bloqq=1 self.xec=int(self.conf.value(self.name+"/xec")) self.yec=int(self.conf.value(self.name+"/yec")) self.r1x=int(self.conf.value(self.name+"/r1x")) self.r1y=int(self.conf.value(self.name+"/r1y")) self.r2=int(self.conf.value(self.name+"/r2x")) self.r2=int(self.conf.value(self.name+"/r2y")) self.kE=0 # variable pour la courbe E fct du nb shoot self.Xec=[] self.Yec=[] self.fwhmX=100 self.fwhmY=100 self.setWindowIcon(QIcon('./icons/LOA.png')) self.E = [] #self.E=np.array([2,3,5]) self.Xec=[] self.Yec=[] # Create x and y indices x = np.arange(0,self.dimx) y = np.arange(0,self.dimy) y,x = np.meshgrid(y, x) self.data=(40*np.random.rand(self.dimx,self.dimy)).round() self.setup() self.ActionButton() self.Display(self.data) def setup(self): TogOff=self.icon+'Toggle_Off.png' TogOn=self.icon+'Toggle_On.png' TogOff=pathlib.Path(TogOff) TogOff=pathlib.PurePosixPath(TogOff) TogOn=pathlib.Path(TogOn) TogOn=pathlib.PurePosixPath(TogOn) self.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(%s);}""QCheckBox::indicator:checked { image: url(%s);}""QCheckBox{font :10pt;}" % (TogOff,TogOn) ) vbox1=QVBoxLayout() hbox=QHBoxLayout() self.checkBoxAuto=QCheckBox('Auto',self) self.checkBoxAuto.setChecked(True) hbox.addWidget(self.checkBoxAuto) self.resetButton=QPushButton('Reset',self) hbox.addWidget(self.resetButton) vbox1.addLayout(hbox) hbox0=QHBoxLayout() self.energieRes=QLabel('?') self.energieRes.setMaximumHeight(30) self.energieRes.setMaximumWidth(120) self.lEnergie=QLabel('s(E1)/s(E2) :') self.lEnergie.setStyleSheet("color:blue;font:14pt") self.lEnergie.setMaximumWidth(80) hbox0.addWidget(self.lEnergie) hbox0.addWidget(self.energieRes) #vbox1.addStretch(1) vbox1.addLayout(hbox0) LabelR1x=QLabel("fwhm X/0.85") LabelR1x.setStyleSheet("color:red;font:14pt") self.r1xBox=QSpinBox() #self.r1Box.setMaximumWidth(60) self.r1xBox.setMaximum(2000) LabelR1y=QLabel('fwhm Y/0.85') LabelR1y.setStyleSheet("color:green;font:14pt") self.r1yBox=QSpinBox() self.r1yBox.setMaximum(2000) #self.r2Box.setMaximumWidth(60) LabelR2=QLabel('R2') LabelR2.setStyleSheet("color:yellow;font:14pt") self.r2Box=QSpinBox() self.r2Box.setMaximum(2000) LabelE1=QLabel("E1 Sum ") LabelE1.setStyleSheet("color:red;font:14pt") self.LabelE1Sum=QLabel("? ") self.LabelE1Sum.setStyleSheet("color:red;font:14pt") LabelE1M=QLabel("E1 mean ") LabelE1M.setStyleSheet("color:red;font:14pt") self.LabelE1Mean=QLabel("? ") self.LabelE1Mean.setStyleSheet("color:red;font:14pt") LabelE2=QLabel("E2 Sum ") LabelE2.setStyleSheet("color:yellow;font:14pt") self.LabelE2Sum=QLabel("? ") self.LabelE2Sum.setStyleSheet("color:yellow;font:14pt") LabelE2M=QLabel("E2 mean ") LabelE2M.setStyleSheet("color:yellow ;font:14pt") self.LabelE2Mean=QLabel("? ") self.LabelE2Mean.setStyleSheet("color:yellow;font:14pt") grid_layout1 = QGridLayout() grid_layout1.addWidget(LabelR1x, 0, 0) grid_layout1.addWidget(self.r1xBox, 0, 1) grid_layout1.addWidget(LabelR1y, 1, 0) grid_layout1.addWidget(self.r1yBox, 1,1) grid_layout1.addWidget(LabelR2, 2, 0) grid_layout1.addWidget(self.r2Box, 2,1) grid_layout1.addWidget(LabelE1,3,0) grid_layout1.addWidget(self.LabelE1Sum,3,1) grid_layout1.addWidget(LabelE1M,4,0) grid_layout1.addWidget(self.LabelE1Mean,4,1) grid_layout1.addWidget(LabelE2,5,0) grid_layout1.addWidget(self.LabelE2Sum,5,1) grid_layout1.addWidget(LabelE2M,6,0) grid_layout1.addWidget(self.LabelE2Mean,6,1) vbox1.addLayout(grid_layout1) vbox1.addStretch(1) self.winImage = pg.GraphicsLayoutWidget() self.winImage.setContentsMargins(0,0,0,0) self.winImage.setAspectLocked(True) self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) #self.winImage.ci.setContentsMargins(0,0,0,0) vbox2=QVBoxLayout() hbox2=QHBoxLayout() hbox2.addWidget(self.winImage) vbox2.addLayout(hbox2) vbox2.setContentsMargins(0,0,0,0) self.p1=self.winImage.addPlot() self.imh=pg.ImageItem() self.p1.addItem(self.imh) self.p1.setMouseEnabled(x=False,y=False) self.p1.setContentsMargins(0,0,0,0) self.p1.setAspectLocked(True,ratio=1) self.p1.showAxis('right',show=False) self.p1.showAxis('top',show=False) self.p1.showAxis('left',show=False) self.p1.showAxis('bottom',show=False) self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='w') self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='w') self.p1.addItem(self.vLine) self.p1.addItem(self.hLine) self.vLine.setPos(self.xec) self.hLine.setPos(self.yec) self.roi1=pg.CircleROI([self.xec,self.yec],[2*self.r1x,2*self.r1y],pen='r',movable=False) self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)]) self.p1.addItem(self.roi1) self.roi2=pg.CircleROI([self.xec,self.yec],[2*self.r2,2*self.r2],pen='y',movable=False) self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)]) self.p1.addItem(self.roi2) #histogramme self.hist = pg.HistogramLUTItem() self.hist.setImageItem(self.imh) self.hist.autoHistogramRange() self.hist.gradient.loadPreset('flame') self.curve2=pg.PlotCurveItem() self.curve3=pg.PlotCurveItem() # text pour afficher fwhm sur p1 self.textX = pg.TextItem(angle=-90) self.textY = pg.TextItem() self.p1.addItem(self.curve2) self.p1.addItem(self.curve3) self.p1.addItem(self.textX) self.p1.addItem(self.textY) hLayout1=QHBoxLayout() hLayout1.addLayout(vbox2) hLayout1.addLayout(vbox1) hLayout1.setContentsMargins(1,1,1,1) # hLayout1.setSpacing(1) # hLayout1.setStretch(10,1) vMainLayout=QVBoxLayout() vMainLayout.addLayout(hLayout1) self.winCurve=QVBoxLayout() self.win2=pg.PlotWidget() self.p2=self.win2.plot(pen='b',symbol='t',symboleSize=2,clear=True,symbolPen='b',symbolBrush='b',name="rapport") self.win2.setContentsMargins(0,0,0,0) self.win2.setLabel('left','E1/E2',units='%') self.hLineMeanE = pg.InfiniteLine(angle=0, movable=False,pen=pg.mkPen('b', width=3, style=QtCore.Qt.DashLine) ) self.win2.addItem(self.hLineMeanE, ignoreBounds=True) self.win2.addItem(self.hLineMeanE, ignoreBounds=True) self.winCurve.addWidget(self.win2) self.win3=pg.PlotWidget() self.p3=self.win3.plot(pen='r',symbol='t',symboleSize=2,clear=True,symbolPen='r',symbolBrush='r',name="x") self.win3.setContentsMargins(0,0,0,0) self.win3.setLabel('left','X')#,units='pixel') self.hLineMeanX = pg.InfiniteLine(angle=0, movable=False,pen=pg.mkPen('r', width=3, style=QtCore.Qt.DashLine)) self.win3.addItem(self.hLineMeanX, ignoreBounds=True) self.winCurve.addWidget(self.win3) self.win4=pg.PlotWidget() self.p4=self.win4.plot(pen='g',symbol='t',symboleSize=2,clear=True,symbolPen='g',symbolBrush='g',name="y") self.win4.setLabel('left','Y')#,units='pixel') self.win4.setLabel('bottom',"Shoot number") self.hLineMeanY = pg.InfiniteLine(angle=0, movable=False,pen=pg.mkPen('g', width=3, style=QtCore.Qt.DashLine)) self.win4.addItem(self.hLineMeanY, ignoreBounds=True) self.winCurve.addWidget(self.win4) labelMean=QLabel('<E1/E2> ') labelMean.setStyleSheet("color:blue;font:14pt") #labelMean.setMaximumWidth(120) self.meanAff=QLabel('?') #self.meanAff.setMaximumWidth(60) labelPV=QLabel('std E1/E2') labelPV.setStyleSheet("color:blue;font:14pt") self.PVAff=QLabel('?') labelMeanX=QLabel('<X>') self.meanXAff=QLabel() labelMeanX.setStyleSheet("color:red;font:14pt") labelMeanY=QLabel('<Y>') labelMeanY.setStyleSheet("color:green;font:14pt") self.meanYAff=QLabel() labelStdX=QLabel('std X') labelStdX.setStyleSheet("color:red;font:14pt") self.stdXAff=QLabel() labelStdY=QLabel('std Y') labelStdY.setStyleSheet("color:green;font:14pt") self.stdYAff=QLabel() grid_layout2 = QGridLayout() grid_layout2.addWidget(labelMean, 0, 0) grid_layout2.addWidget(self.meanAff, 0, 1) grid_layout2.addWidget(labelPV, 1, 0) grid_layout2.addWidget(self.PVAff, 1,1) grid_layout2.addWidget(labelMeanX, 2, 0) grid_layout2.addWidget(self.meanXAff, 2, 1) grid_layout2.addWidget(labelStdX, 3, 0) grid_layout2.addWidget(self.stdXAff, 3,1) grid_layout2.addWidget(labelMeanY, 4, 0) grid_layout2.addWidget(self.meanYAff, 4, 1) grid_layout2.addWidget(labelStdY, 5, 0) grid_layout2.addWidget(self.stdYAff, 5,1) hLayout2=QHBoxLayout() hLayout2.addLayout(self.winCurve) hLayout2.addLayout(grid_layout2) vMainLayout.addLayout(hLayout2) hMainLayout=QHBoxLayout() hMainLayout.addLayout(vMainLayout) self.setLayout(hMainLayout) self.setContentsMargins(1,1,1,1) def ActionButton(self): # Blocage de la souris self.roi1.sigRegionChangeFinished.connect(self.energSouris) # signal si changement à la souris de la taille des cercles self.roi2.sigRegionChangeFinished.connect(self.energSouris) # self.r1xBox.editingFinished.connect(self.Rayon) #w.r1Box.returnPressed.connect(Rayon)# rayon change a la main self.r1yBox.editingFinished.connect(self.Rayon) self.r2Box.editingFinished.connect(self.Rayon) self.shortcutb=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self) self.shortcutb.activated.connect(self.bloquer) self.shortcutd=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self) self.shortcutd.activated.connect(self.debloquer) self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self) self.shortcutPu.activated.connect(self.paletteup) self.shortcutPu.setContext(Qt.ShortcutContext(3)) #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus. self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self) self.shortcutPd.activated.connect(self.palettedown) self.shortcutPd.setContext(Qt.ShortcutContext(3)) self.checkBoxAuto.stateChanged.connect(lambda:self.Display(self.data)) # mvt de la souris self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) self.p1.scene().sigMouseClicked.connect(self.mouseClick) self.vb=self.p1.vb self.checkBoxAuto.stateChanged.connect(self.AutoE) self.resetButton.clicked.connect(self.Reset) def mouseClick(self): # bloque ou debloque la souris si click su le graph if self.bloqq==1: self.debloquer() else : self.bloquer() def bloquer(self): # bloque la croix self.bloqq=1 self.conf.setValue(self.name+"/xec",int(self.xec)) # save cross postion in ini file self.conf.setValue(self.name+"/yec",int(self.yec)) self.CalculE() def debloquer(self): # deblaoque la croix : elle bouge avec la souris self.bloqq=0 # mvt de la souris def mouseMoved(self,evt): ## pour que la cross suive le mvt de la souris if self.checkBoxAuto.isChecked()==False: if self.bloqq==0: # souris non bloquer pos = evt[0] ## using signal proxy turns original arguments into a tuple if self.p1.sceneBoundingRect().contains(pos): mousePoint = self.vb.mapSceneToView(pos) self.xec =int (mousePoint.x()) self.yec= int(mousePoint.y()) if ((self.xec>0 and self.xec<self.data.shape[0]) and (self.yec>0 and self.yec<self.data.shape[1]) ): self.vLine.setPos(self.xec) self.hLine.setPos(self.yec) # la croix ne bouge que dans le graph self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)]) self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)]) def AutoE(self): if self.checkBoxAuto.isChecked()==False: self.energSouris() self.roi1.setSize([2*self.r1x,2*self.r1y]) self.roi2.setSize([2*self.r2,2*self.r2]) def energSouris(self): # changement des rayons à la souris if self.checkBoxAuto.isChecked()==False: s1=self.roi1.size() s2=self.roi2.size() self.r1xBox.setValue((int(s1[0]/2))) self.r1yBox.setValue((int(s1[1]/2))) self.r2Box.setValue((int(s2[0]/2))) self.r1x=int(s1[0]/2) self.r1y=int(s1[1]/2) self.r2=int(s2[0]/2) if self.bloqq==1: self.CalculE() def Rayon(self): """changement rayon dans les box """ if self.checkBoxAuto.isChecked()==False: if self.r1xBox.hasFocus() : self.r1x=(float(self.r1xBox.text())) self.roi1.setSize([2*self.r1x,2*self.r1y]) if self.r1yBox.hasFocus() : self.r1y=(float(self.r1yBox.text())) self.roi1.setSize([2*self.r1x,2*self.r1y]) if self.r2Box.hasFocus(): self.r2=(float(self.r2Box.text())) self.roi2.setSize([2*self.r2,2*self.r2]) self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)]) self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)]) if self.bloqq==1: self.CalculE() def CalculE(self): if self.fwhmX==None or self.fwhmY==None: self.fwhmX=100 self.fwhmY=100 if self.checkBoxAuto.isChecked()==True: self.r1x=self.fwhmX/0.849 self.r1y=self.fwhmY/0.849 self.r1xBox.setValue(int(self.r1x)) self.r1yBox.setValue(int(self.r1y)) nbG=2 # ré= 2 fois r1 pour le grand cercle self.roi2.setSize([2*nbG*self.r1x,2*nbG*self.r1y]) self.roi2.setPos([self.xec-nbG*self.r1x,self.yec-nbG*self.r1y]) self.r2Box.setValue(int(2*nbG*self.r1x)) self.roi1.setSize([2*self.r1x,2*self.r1y]) self.roi1.setPos([self.xec-self.r1x,self.yec-self.r1y]) else: self.r1x=self.r1x self.r1y=self.r1y E1=self.roi1.getArrayRegion(self.data,self.imh).sum() E2=self.roi2.getArrayRegion(self.data,self.imh).sum() self.rap=100*E1/E2 self.energieRes.setText('%.2f %%' % self.rap) self.E=np.append(self.E,self.rap) #self.E.append(self.rap) Emean=np.mean(self.E) self.meanAff.setText('%.2f' % Emean) EPV=np.std(self.E) self.PVAff.setText('%.2f' % EPV) self.hLineMeanE.setPos(Emean) self.textX.setText('fwhm='+str(self.fwhmY)) self.textY.setText('fwhm='+str(self.fwhmX),color='w') self.LabelE1Sum.setText('%.2f' %E1) self.LabelE1Mean.setText('%.2f' % (self.roi1.getArrayRegion(self.data,self.imh).mean())) self.LabelE2Sum.setText('%.2f' %E2) self.LabelE2Mean.setText('%.2f' % (self.roi2.getArrayRegion(self.data,self.imh).mean())) def Display(self,data): self.data=data self.dimx=self.data.shape[0] self.dimy=self.data.shape[1] self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) self.p1.setAspectLocked(True,ratio=1) self.imh.setImage(data.astype(float),autoLevels=True,autoDownsample=True) self.CalculCentroid() self.Coupe() self.CalculE() self.Xec.append(self.xec) self.Yec.append(self.yec) Xmean=np.mean(self.Xec) self.meanXAff.setText('%.2f' % Xmean) XPV=np.std(self.Xec) self.stdXAff.setText('%.2f' % XPV) self.hLineMeanX.setPos(Xmean) Ymean=np.mean(self.Yec) self.meanYAff.setText('%.2f' % Ymean) YPV=np.std(self.Yec) self.stdYAff.setText('%.2f' % YPV) self.hLineMeanY.setPos(Ymean) self.plotGraph() def plotGraph(self): self.p2.setData(self.E)#,pen='b',symbol='t',symboleSize=2,clear=True,symbolPen='b',symbolBrush='b',name="rapport") #self.p2.addItem(self.hLineMeanE, ignoreBounds=True) self.p3.setData(self.Xec)#,pen='r',symbol='t',symboleSize=2,clear=True,symbolPen='r',symbolBrush='r',name="x") #self.p3.addItem(self.hLineMeanX, ignoreBounds=True) self.p4.setData(self.Yec)#,pen='g',symbol='t',symboleSize=2,clear=True,symbolPen='g',symbolBrush='g',name="y") #self.p4.addItem(self.hLineMeanY, ignoreBounds=True) def CalculCentroid(self): if self.checkBoxAuto.isChecked()==True: dataF=gaussian_filter(self.data,5) (self.xec,self.yec)=pylab.unravel_index(dataF.argmax(),self.data.shape) #prend le max self.vLine.setPos(self.xec) self.hLine.setPos(self.yec) self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)]) self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)]) def fwhm(self,x, y, order=3): """ Determine full-with-half-maximum of a peaked set of points, x and y. Assumes that there is only one peak present in the datasset. The function uses a spline interpolation of order k. """ y=gaussian_filter(y,5) # filtre pour reduire le bruit half_max = np.amax(y)/2 try: s = splrep(x, y - half_max,k=order) # Find the B-spline representation of 1-D curve. roots = sproot(s) # Given the knots (>=8) and coefficients of a cubic B-spline return the roots of the spline. except: roots=0 if len(roots) > 2: pass #print( "The dataset appears to have multiple peaks, and ","thus the FWHM can't be determined.") elif len(roots) < 2: pass # print( "No proper peaks were found in the data set; likely ","the dataset is flat (e.g. all zeros).") else: return np.around(abs(roots[1] - roots[0]),decimals=2) def Coupe(self): xxx=np.arange(0,int(self.dimx),1)# yyy=np.arange(0,int(self.dimy),1)# coupeX=self.data[int(self.xec),:] coupeXMax=np.max(coupeX) if coupeXMax==0: # evite la div par zero coupeXMax=1 coupeXnorm=(self.data.shape[0]/10)*(coupeX/coupeXMax) # normalise les coupes pour pas prendre tout l ecran self.curve2.setData(30+coupeXnorm,yyy,clear=True) coupeY=self.data[:,int(self.yec)] coupeYMax=np.max(coupeY) if coupeYMax==0: coupeYMax=1 coupeYnorm=(self.data.shape[1]/10)*(coupeY/coupeYMax) self.curve3.setData(xxx,20+coupeYnorm,clear=True) ### affichage de fwhm sur les coupes X et Y que si le max est >20 counts xCXmax=np.amax(coupeXnorm) # max if xCXmax>20: self.fwhmY=self.fwhm(yyy, coupeXnorm, order=3) yCXmax=yyy[coupeXnorm.argmax()] self.textX.setPos(xCXmax-3,yCXmax+3) yCYmax=np.amax(coupeYnorm) # max if yCYmax>20: self.fwhmX=self.fwhm(xxx, coupeYnorm, order=3) xCYmax=xxx[coupeYnorm.argmax()] self.textY.setPos(xCYmax-3,yCYmax-3) def paletteup(self): levels=self.imh.getLevels() if levels[0]==None: xmax =self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax+(xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def palettedown(self): levels=self.imh.getLevels() if levels[0]==None: xmax=self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax- (xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def Reset(self): self.E = [] self.Xec=[] self.Yec=[] def closeEvent(self, event): """ when closing the window """ self.isWinOpen=False self.E=[] self.Xec=[] self.Yec=[] time.sleep(0.1) event.accept()
class Lookup(QWidget): MODEL_CLASS = None def __init__(self, parent, model): QWidget.__init__(self, parent, Qt.Window) self.model = model self.model.view = self self._setupUi() self.searchEdit.searchChanged.connect(self.searchChanged) self.searchEdit.returnPressed.connect(self.returnPressed) self.namesList.currentRowChanged.connect(self.currentRowChanged) self.namesList.itemDoubleClicked.connect(self.itemDoubleClicked) self._shortcutUp.activated.connect(self.upPressed) self._shortcutDown.activated.connect(self.downPressed) def _setupUi(self): self.setWindowTitle(tr("Lookup")) self.resize(314, 331) self.verticalLayout = QVBoxLayout(self) self.searchEdit = SearchEdit(self) self.verticalLayout.addWidget(self.searchEdit) self.namesList = QListWidget(self) self.namesList.setEditTriggers(QAbstractItemView.NoEditTriggers) self.namesList.setSelectionBehavior(QAbstractItemView.SelectRows) self.namesList.setUniformItemSizes(True) self.namesList.setSelectionRectVisible(True) self.verticalLayout.addWidget(self.namesList) self.searchEdit.immediate = True self._shortcutUp = QShortcut(self.searchEdit) self._shortcutUp.setKey(QKeySequence(Qt.Key_Up)) self._shortcutUp.setContext(Qt.WidgetShortcut) self._shortcutDown = QShortcut(self.searchEdit) self._shortcutDown.setKey(QKeySequence(Qt.Key_Down)) self._shortcutDown.setContext(Qt.WidgetShortcut) def _restoreSelection(self): self.namesList.setCurrentRow(self.model.selected_index) # --- Event Handlers def returnPressed(self): self.model.go() def searchChanged(self): self.model.search_query = str(self.searchEdit.text()) def currentRowChanged(self, row): if row >= 0: self.model.selected_index = row def itemDoubleClicked(self, item): self.model.go() def upPressed(self): if self.namesList.currentRow() > 0: self.namesList.setCurrentRow(self.namesList.currentRow() - 1) def downPressed(self): if self.namesList.currentRow() < self.namesList.count() - 1: self.namesList.setCurrentRow(self.namesList.currentRow() + 1) # --- model --> view def refresh(self): self.namesList.clear() self.namesList.addItems(self.model.names) self._restoreSelection() self.searchEdit.setText(self.model.search_query) def show(self): QWidget.show(self) self.searchEdit.setFocus() # see csv_options self.raise_() def hide(self): QWidget.hide(self)
class PlaylistView(QTableView): def __init__(self, listplayer, status_bar: QStatusBar, play_ctrls, parent=None): super().__init__(parent=parent) self.player = listplayer self.status_bar = status_bar self.play_ctrls = play_ctrls self.setSelectionBehavior(self.SelectRows) self.setDragDropMode(self.InternalMove) self.setDragDropOverwriteMode(False) self.setEditTriggers(QTableView.NoEditTriggers) self.setAlternatingRowColors(True) self.setDropIndicatorShown(True) self.setHorizontalHeader(PlaylistViewHeader(parent=self)) self.setContextMenuPolicy(Qt.CustomContextMenu) # Create shortcuts self.rem_selected_items_shortcut = QShortcut(self) self.rem_selected_items_shortcut.setKey(QKeySequence.Delete) self.rem_selected_items_shortcut.setContext(Qt.WidgetWithChildrenShortcut) self.rem_selected_items_shortcut.activated.connect(self.remove_selected_items) self.play_selected_item_shortcut = QShortcut(self) self.play_selected_item_shortcut.setKey(Qt.Key_Return) self.play_selected_item_shortcut.setContext(Qt.WidgetWithChildrenShortcut) self.play_selected_item_shortcut.activated.connect(self.play_selected_item) self.setModel(PlaylistModel()) # Setup signals self.customContextMenuRequested.connect(self.show_context_menu) self.doubleClicked.connect(self.on_doubleClicked) self.selectionModel().selectionChanged.connect(self.on_selectionChanged) def showEvent(self, e): if self.model().rowCount(): if not self.selectionModel().hasSelection(): self.setCurrentIndex(self.model().item(0).index()) self.setFocus() @pyqtSlot() def play_selected_item(self): self.player.load_media(index=self.currentIndex()) self.player.mp.play() def mousePressEvent(self, e): """Clear both row and current index selections when clicking away from items.""" clicked_index = self.indexAt(e.pos()) if clicked_index.isValid(): item = self.model().item(clicked_index.row()) status_tip = item.data(role=Qt.DisplayRole) self.status_bar.showMessage(status_tip) else: self.selectionModel().clear() return super().mousePressEvent(e) def on_selectionChanged(self, selected, deselected): if not selected: self.selectionModel().clear() @pyqtSlot(QModelIndex) def on_doubleClicked(self, index): self.player.load_media(index=index) self.player.mp.play() def dropEvent(self, e): dragged_index = self.currentIndex() dropped_index = self.indexAt(e.pos()) log.debug( f"dragged_index={dragged_index.row(), dragged_index.column()} dropped_index={dropped_index.row(), dropped_index.column()} action={e.dropAction()} source={e.source()}" ) if dropped_index.row() == -1: return None model = self.model() item = model.takeRow(dragged_index.row()) model.insertRow(dropped_index.row(), item) self.setCurrentIndex(dropped_index) e.ignore() @pyqtSlot(int) def on_model_rowCountChanged(self, count): """Enable/disable GUI elements when media is added or removed""" if count: self.play_ctrls.setEnabled(True) else: self.play_ctrls.setEnabled(False) def setModel(self, model): # Disconnect previous model if self.model(): self.model().rowCountChanged.disconnect() # Connect this model model.rowCountChanged.connect(self.on_model_rowCountChanged) model.rowCountChanged.connect(self.player.on_playlist_rowCountChanged) super().setModel(model) def selected_items(self): items = [] for i in self.selectionModel().selectedRows(): items.append(self.model().itemFromIndex(i)) return items def show_context_menu(self, pos: QPoint): selected_items = self.selected_items() if len(selected_items) <= 1: rem_selected_text = f"Remove '{selected_items[0].data(Qt.DisplayRole)}'" else: rem_selected_text = f"Remove {len(selected_items)} items" menu = QMenu(self) menu.addAction( icons.get("file_remove"), rem_selected_text, self.remove_selected_items, self.rem_selected_items_shortcut.key(), ) menu.exec_(self.mapToGlobal(pos)) @pyqtSlot() def remove_selected_items(self): indexes = self.selectionModel().selectedRows() items = [self.model().itemFromIndex(i) for i in indexes] self.remove_items(items) def remove_items(self, items): # Create a status message if len(items) == 1: status_msg = f"Removed '{items[0].data(Qt.DisplayRole)}'" else: status_msg = f"Removed {len(items)} items" # Unload from player self.player.unload_media(items=items) # Remove from model start_row = self.model().indexFromItem(items[0]).row() num_rows = len(items) self.model().removeRows(start_row, num_rows) # Push status message self.status_bar.showMessage(status_msg)
def __init__(self, pwMap, settings, dbFilename): """ @param pwMap: a PasswordMap instance with encrypted passwords @param dbFilename: file name for saving pwMap """ super(MainWindow, self).__init__() self.setupUi(self) self.logger = settings.logger self.settings = settings self.pwMap = pwMap self.selectedGroup = None self.modified = False # modified flag for "Save?" question on exit self.dbFilename = dbFilename self.groupsModel = QStandardItemModel(parent=self) self.groupsModel.setHorizontalHeaderLabels([u"Password group"]) self.groupsFilter = QSortFilterProxyModel(parent=self) self.groupsFilter.setSourceModel(self.groupsModel) self.groupsTree.setModel(self.groupsFilter) self.groupsTree.setContextMenuPolicy(Qt.CustomContextMenu) self.groupsTree.customContextMenuRequested.connect(self.showGroupsContextMenu) # Dont use e following line, it would cause loadPasswordsBySelection # to be called twice on mouse-click. # self.groupsTree.clicked.connect(self.loadPasswordsBySelection) self.groupsTree.selectionModel().selectionChanged.connect(self.loadPasswordsBySelection) self.groupsTree.setSortingEnabled(True) self.passwordTable.setContextMenuPolicy(Qt.CustomContextMenu) self.passwordTable.customContextMenuRequested.connect(self.showPasswdContextMenu) self.passwordTable.setSelectionBehavior(QAbstractItemView.SelectRows) self.passwordTable.setSelectionMode(QAbstractItemView.SingleSelection) shortcut = QShortcut(QKeySequence(u"Ctrl+C"), self.passwordTable, self.copyPasswordFromSelection) shortcut.setContext(Qt.WidgetShortcut) self.actionQuit.triggered.connect(self.close) self.actionQuit.setShortcut(QKeySequence(u"Ctrl+Q")) self.actionExport.triggered.connect(self.exportCsv) self.actionImport.triggered.connect(self.importCsv) self.actionBackup.triggered.connect(self.saveBackup) self.actionAbout.triggered.connect(self.printAbout) self.actionSave.triggered.connect(self.saveDatabase) self.actionSave.setShortcut(QKeySequence(u"Ctrl+S")) # headerKey = QTableWidgetItem(u"Key") # headerValue = QTableWidgetItem(u"Password/Value") # headerComments = QTableWidgetItem(u"Comments") # self.passwordTable.setColumnCount(self.NO_OF_PASSWDTABLE_COLUMNS) # self.passwordTable.setHorizontalHeaderItem(self.KEY_IDX, headerKey) # self.passwordTable.setHorizontalHeaderItem(self.PASSWORD_IDX, headerValue) # self.passwordTable.setHorizontalHeaderItem(self.COMMENTS_IDX, headerComments) # # self.passwordTable.resizeRowsToContents() # self.passwordTable.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) # self.passwordTable.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) # self.passwordTable.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents) self.searchEdit.textChanged.connect(self.filterGroups) if pwMap is not None: self.setPwMap(pwMap) self.clipboard = QApplication.clipboard() self.timer = QTimer(parent=self) self.timer.timeout.connect(self.clearClipboard)
class ListTable(QTableWidget): """Define a custom table list.""" dataModified = pyqtSignal() def __init__(self, noColumns=1, data=[]): """Init table list.""" super().__init__() data = self.__processData(data) self.__noColumns = noColumns self.setCornerButtonEnabled(False) self.horizontalHeader().hide() self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.verticalHeader().hide() self.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.setData(data) self.shortcut = QShortcut(QKeySequence("DEL"), self) self.shortcut.setAutoRepeat(False) self.shortcut.setContext(Qt.WidgetWithChildrenShortcut) self.shortcut.activated.connect(self.delClicked) def __handleDataChanged(self, item): self.setData(self.getData(), item) self.dataModified.emit() def __processData(self, data): seen = set() uniq = [x for x in data if x not in seen and not seen.add(x)] uniq.sort() return uniq def delClicked(self): item = self.currentItem() if item and item.isSelected() and item.text().strip(): item.setText("") def setData(self, data, item=""): """Set the data.""" try: self.itemChanged.disconnect() except Exception: pass if item: item = item.text() self.setColumnCount(self.__noColumns) self.setRowCount(int(len(data) / self.__noColumns) + 1) for idx, entry in enumerate(data): row, column = divmod(idx, self.__noColumns) self.setItem(row, column, QTableWidgetItem(entry)) if entry == item: self.setCurrentCell(row, column) row = int(len(data) / self.__noColumns) for col in range(len(data) % self.__noColumns, self.__noColumns): self.setItem(row, col, QTableWidgetItem("")) row = int(len(data) / self.__noColumns) + 1 for col in range(self.__noColumns): self.setItem(row, col, QTableWidgetItem("")) self.itemChanged.connect(self.__handleDataChanged) def getData(self): """Get the data.""" data = [] for row in range(self.rowCount()): for col in range(self.columnCount()): try: element = self.item(row, col).text().strip() if (element == ""): continue data.append(element) except Exception: pass return self.__processData(data)
def spaceBarPressed(): global myIt, activeLayerId aLayer = iface.activeLayer() if not aLayer or not aLayer.type() == 0: print("Please first select a vector layer in the ToC.") return if activeLayerId != aLayer.id(): activeLayerId = aLayer.id() myIt = None if not myIt: myIt = aLayer.getFeatures() feat = next(myIt, None) if feat: aLayer.removeSelection() aLayer.select(feat.id()) iface.actionZoomToSelected().trigger() print("Selected feature:", str(feat.id())) else: print ("We reached the last feature of this layer already.\n" + \ "If you want to restart press the Escape key.") shortcutEscape = QShortcut(QKeySequence(Qt.Key_Escape), iface.mapCanvas()) shortcutEscape.setContext(Qt.ApplicationShortcut) shortcutEscape.activated.connect(escapePressed) shortcutSpaceBar = QShortcut(QKeySequence(Qt.Key_Space), iface.mapCanvas()) shortcutSpaceBar.setContext(Qt.ApplicationShortcut) shortcutSpaceBar.activated.connect(spaceBarPressed)
class CAMERABASLERACQ(QWidget) : def __init__(self,name=None,visuGauche=False): super(CAMERABASLERACQ, self).__init__() self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # dark style self.visuGauche=visuGauche if name==None: self.nbcam='camTest' else: self.nbcam=name self.confCCD = QtCore.QSettings('confBasler.ini', QtCore.QSettings.IniFormat) self.camType=self.confCCD.value(self.nbcam+"/camType") if self.camType != 'basler': print('error camera type') self.id=self.confCCD.value(self.nbcam+"/camId") self.camName=self.confCCD.value(self.nbcam+"/name") camConnected=None for i in pylon.TlFactory.GetInstance().EnumerateDevices(): if i.GetSerialNumber()==self.id: camConnected=i try : if camConnected is not None: self.cam0= pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateDevice(camConnected)) self.isConnected=True print(self.camName,'connected @',i.GetSerialNumber()) # else: # self.cam0= pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice()) # print('fisrt camera connected') # self.isConnected=True else: self.isConnected=False print('no camera connected') except: self.isConnected=False print('no camera connected') self.bloqHandle=1 # bloque la taille du cercle self.setup() self.Color() self.cameName=self.confCCD.value(self.nbcam+"/name") self.setWindowTitle(self.cameName) p = pathlib.Path(__file__) sepa=os.sep self.icon=str(p.parent) + sepa + 'icons' +sepa self.setWindowIcon(QIcon(self.icon+'LOA.png')) #pg.setConfigOptions(antialias=True) self.winSC=FULLSCREEN(title=self.cameName,conf=self.confCCD,nbcam=self.nbcam) self.actionButton() self.bloqq=1 if self.isConnected==False: print ('not connected') self.nbcam='camTest' self.runButton.setEnabled(False) self.runButton.setStyleSheet("background-color:gray") self.runButton.setStyleSheet("QPushButton:!pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0)}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}") self.hSliderShutter.setEnabled(False) self.trigg.setEnabled(False) self.hSliderGain.setEnabled(False) self.stopButton.setEnabled(False) self.stopButton.setStyleSheet("background-color:gray") self.stopButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}") if self.isConnected==True: self.cam0.Open() self.cam0.GainAuto.SetValue('Off') self.cam0.TriggerMode.SetValue('Off') self.cam0.TriggerSelector.SetValue("AcquisitionStart") self.cam0.ExposureAuto.SetValue('Off') self.cam0.Width=self.cam0.Width.Max self.cam0.Height=self.cam0.Height.Max # self.hSliderShutter.setMinimum(self.cam0.ExposureTimeAbs.GetMin()) # self.hSliderShutter.setMaximum(self.cam0.ExposureTimeAbs.GetMax()) sh=int(self.confCCD.value(self.nbcam+"/shutter")) self.hSliderShutter.setValue(sh) self.shutterBox.setValue(int(sh)) self.cam0.ExposureTimeAbs.SetValue(int(sh*1000)) self.hSliderGain.setMinimum(self.cam0.GainRaw.GetMin()) self.hSliderGain.setMaximum(self.cam0.GainRaw.GetMax()) g=int(self.confCCD.value(self.nbcam+"/gain")) self.hSliderGain.setValue(g) self.cam0.GainRaw.SetValue(int(g)) self.gainBox.setMinimum(self.cam0.GainRaw.GetMin()) self.gainBox.setMaximum(self.cam0.GainRaw.GetMax()) self.gainBox.setValue(int(self.cam0.GainRaw.GetValue())) self.dimy=self.cam0.SensorHeight.GetValue() self.dimx=self.cam0.SensorWidth.GetValue() print("number of pixels :",self.dimx,'*',self.dimy) else : self.dimy=960 self.dimx=1240 def twoD_Gaussian(x,y, amplitude, xo, yo, sigma_x, sigma_y, theta, offset): xo = float(xo) yo = float(yo) a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2) b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2) c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2) return offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2))) # Create x and y indices x = np.arange(0,self.dimx) y = np.arange(0,self.dimy) y,x = np.meshgrid(y, x) self.data=twoD_Gaussian(x, y,250, 300, 600, 40, 40, 0, 10)+(50*np.random.rand(self.dimx,self.dimy)).round() #self.data=(50*np.random.rand(self.dimx,self.dimy)).round() + 150 self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) #self.p1.setGeometry(1,1,self.dimx,self.dimy) #self.winImage.setGeometry(1,1,self.dimx,self.dimy) self.Display(self.data) def setup(self): vbox1=QVBoxLayout() self.camNameLabel=QLabel('nomcam',self) self.camNameLabel.setText(self.confCCD.value(self.nbcam+"/name")) self.camNameLabel.setAlignment(Qt.AlignCenter) self.camNameLabel.setStyleSheet('font: bold 20px') self.camNameLabel.setStyleSheet('color: yellow') vbox1.addWidget(self.camNameLabel) hbox1=QHBoxLayout() # horizontal layout pour run et stop self.runButton=QPushButton(self) self.runButton.setMaximumWidth(60) self.runButton.setMinimumHeight(60) self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: green;}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}") self.stopButton=QPushButton(self) self.stopButton.setMaximumWidth(60) self.stopButton.setMinimumHeight(50) self.stopButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}") hbox1.addWidget(self.runButton) hbox1.addWidget(self.stopButton) # self.oneButton=QPushButton(self) # hbox1.addWidget(self.oneButton) vbox1.addLayout(hbox1) self.trigg=QComboBox() self.trigg.setMaximumWidth(60) self.trigg.addItem('OFF') self.trigg.addItem('ON') self.labelTrigger=QLabel('Trigger') self.labelTrigger.setMaximumWidth(60) self.itrig=self.trigg.currentIndex() hbox2=QHBoxLayout() hbox2.addWidget(self.labelTrigger) hbox2.addWidget(self.trigg) vbox1.addLayout(hbox2) self.labelExp=QLabel('Exposure (ms)') self.labelExp.setMaximumWidth(120) self.labelExp.setAlignment(Qt.AlignCenter) vbox1.addWidget(self.labelExp) self.hSliderShutter=QSlider(Qt.Horizontal) self.hSliderShutter.setMinimum(1) self.hSliderShutter.setMaximum(1000) self.hSliderShutter.setMaximumWidth(120) self.shutterBox=QSpinBox() self.shutterBox.setMinimum(1) self.shutterBox.setMaximum(1000) self.shutterBox.setMaximumWidth(60) hboxShutter=QHBoxLayout() hboxShutter.addWidget(self.hSliderShutter) hboxShutter.addWidget(self.shutterBox) vbox1.addLayout(hboxShutter) hboxGain=QHBoxLayout() self.labelGain=QLabel('Gain') self.labelGain.setMaximumWidth(120) self.labelGain.setAlignment(Qt.AlignCenter) vbox1.addWidget(self.labelGain) self.hSliderGain=QSlider(Qt.Horizontal) self.hSliderGain.setMaximumWidth(120) self.gainBox=QSpinBox() self.gainBox.setMaximumWidth(60) hboxGain.addWidget(self.hSliderGain) hboxGain.addWidget(self.gainBox) vbox1.addLayout(hboxGain) hbox3=QHBoxLayout() self.checkBoxScale=QCheckBox('AScale',self) self.checkBoxScale.setChecked(True) self.checkBoxScale.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image: url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}") hbox3.addWidget(self.checkBoxScale) self.checkBoxColor=QCheckBox('Color',self) self.checkBoxColor.setChecked(True) self.checkBoxColor.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image: url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}") hbox3.addWidget(self.checkBoxColor) vbox1.addLayout(hbox3) hbox4=QHBoxLayout() self.checkBoxZoom=QCheckBox('Zoom',self) self.checkBoxZoom.setChecked(False) self.checkBoxZoom.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image: url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}") hbox4.addWidget(self.checkBoxZoom) self.checkBoxFullScreen=QCheckBox('FScreen',self) self.checkBoxFullScreen.setChecked(False) self.checkBoxFullScreen.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image: url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}") hbox4.addWidget(self.checkBoxFullScreen) vbox1.addLayout(hbox4) vbox1.setContentsMargins(0,0,0,0) vbox1.addStretch(1) self.vbox1=vbox1 ### affichage image### self.winImage = pg.GraphicsLayoutWidget() self.winImage.setContentsMargins(0,0,0,0) self.winImage.setAspectLocked(True) self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.winImage.ci.setContentsMargins(0,0,0,0) vbox2=QVBoxLayout() vbox2.addWidget(self.winImage) vbox2.setContentsMargins(1,1,1,1) self.p1=self.winImage.addPlot() self.imh=pg.ImageItem() self.p1.addItem(self.imh) self.p1.setMouseEnabled(x=False,y=False) self.p1.setContentsMargins(0,0,0,0) self.p1.setAspectLocked(True,ratio=1) self.p1.showAxis('right',show=False) self.p1.showAxis('top',show=False) self.p1.showAxis('left',show=False) self.p1.showAxis('bottom',show=False) self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='y') self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='y') self.p1.addItem(self.vLine) self.p1.addItem(self.hLine, ignoreBounds=False) self.xc=int(self.confCCD.value(self.nbcam+"/xc")) self.yc=int(self.confCCD.value(self.nbcam+"/yc")) self.rx=int(self.confCCD.value(self.nbcam+"/rx")) self.ry=int(self.confCCD.value(self.nbcam+"/ry")) self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) self.ro1=pg.EllipseROI([self.xc,self.yc],[self.rx,self.ry],pen='y',movable=False)#maxBounds=QtCore.QRectF(0,0,self.rx,self.ry) self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)]) self.p1.addItem(self.ro1) #histogramme self.hist = pg.HistogramLUTItem() self.hist.setImageItem(self.imh) self.hist.autoHistogramRange() self.hist.gradient.loadPreset('flame') ## Graph coupe XY self.curve2=pg.PlotCurveItem() self.curve3=pg.PlotCurveItem() ## main layout hMainLayout=QHBoxLayout() if self.visuGauche==True: hMainLayout.addLayout(self.vbox1) hMainLayout.addLayout(vbox2) else: hMainLayout.addLayout(vbox2) hMainLayout.addLayout(self.vbox1) hMainLayout.setContentsMargins(1,1,1,1) hMainLayout.setSpacing(1) hMainLayout.setStretch(3,1) self.setLayout(hMainLayout) self.setContentsMargins(1,1,1,1) # Blocage de la souris self.shortcutb=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self) self.shortcutb.activated.connect(self.bloquer) self.shortcutb.setContext(Qt.ShortcutContext(3)) self.shortcutd=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self) self.shortcutd.activated.connect(self.debloquer) self.shortcutd.setContext(Qt.ShortcutContext(3)) self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self) self.shortcutPu.activated.connect(self.paletteup) self.shortcutPu.setContext(Qt.ShortcutContext(3)) #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus. self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self) self.shortcutPd.activated.connect(self.palettedown) self.shortcutPd.setContext(Qt.ShortcutContext(3)) # mvt de la souris self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) self.vb=self.p1.vb # text pour afficher fwhm sur p1 self.textX = pg.TextItem(angle=-90) self.textY = pg.TextItem() def actionButton(self): self.runButton.clicked.connect(self.acquireMultiImage) self.stopButton.clicked.connect(self.stopAcq) self.hSliderShutter.sliderMoved.connect(self.mSliderShutter) self.shutterBox.editingFinished.connect(self.shutter) self.hSliderGain.sliderMoved.connect(self.mSliderGain) self.gainBox.editingFinished.connect(self.gain) self.trigg.currentIndexChanged.connect(self.Trig) self.checkBoxColor.stateChanged.connect(self.Color) self.ro1.sigRegionChangeFinished.connect(self.roiChanged) self.checkBoxZoom.stateChanged.connect(self.Zoom) self.checkBoxFullScreen.stateChanged.connect(self.FullScreen) # self.oneButton.clicked.connect(self.acquireOneImage) def shutter(self): sh=self.shutterBox.value() # self.hSliderShutter.setValue(sh) # set value of slider time.sleep(0.1) print(sh,'sh') self.cam0.ExposureTimeAbs.SetValue(int(sh*1000)) self.confCCD.setValue(self.nbcam+"/shutter",float(sh)) self.confCCD.sync() def mSliderShutter(self): # for shutter slider sh=self.hSliderShutter.value() self.shutterBox.setValue(sh) # time.sleep(0.1) self.cam0.ExposureTimeAbs.SetValue(int(sh*1000)) # Set shutter CCD in microseconde self.confCCD.setValue(self.nbcam+"/shutter",float(sh)) def Color(self): """ image in colour """ if self.checkBoxColor.isChecked()==1: self.color='flame' self.hist.gradient.loadPreset('flame') else: self.hist.gradient.loadPreset('grey') self.color='grey' def Zoom(self): if self.checkBoxZoom.isChecked()==1: self.p1.setXRange(self.xc-200,self.xc+200) self.p1.setYRange(self.yc-200,self.yc+200) else: self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) def FullScreen(self): if self.checkBoxFullScreen.isChecked()==1: self.open_widget(self.winSC) self.winSC.Display(self.data,color=self.color) #self.winSC.showMaximized() else: self.winSC.close() def gain(self): g=self.gainBox.value() # self.hSliderGain.setValue(g) # set slider value time.sleep(0.1) self.cam0.GainRaw.SetValue(int(g)) self.confCCD.setValue(self.nbcam+"/gain",float(g)) self.confCCD.sync() def mSliderGain(self): g=self.hSliderGain.value() self.gainBox.setValue(g) # set valeur de la box time.sleep(0.1) self.cam0.GainRaw.SetValue(int(g)) self.confCCD.setValue(self.nbcam+"/gain",float(g)) self.confCCD.sync() def Trig(self): self.itrig=self.trigg.currentIndex() if self.itrig==0: self.cam0.TriggerMode.SetValue('Off') # print ("trigger OFF") if self.itrig==1: self.cam0.TriggerMode.SetValue('On') # print("Trigger ON") def acquireMultiImage(self): #print('live...') self.runButton.setEnabled(False) self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0)}") #self.runButton.setStyleSheet("background-color:gray") try: self.threadRunAcq=ThreadRunAcq(self) self.threadRunAcq.newDataRun.connect(self.Display) self.threadRunAcq.start() except : pass def acquireOneImage(self): self.runButton.setEnabled(False) self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0)}") #self.runButton.setStyleSheet("background-color:gray") try: self.threadOneAcq=ThreadOneAcq(self) self.threadOneAcq.newDataOne.connect(self.Display) self.threadOneAcq.start() except : print('error') pass self.runButton.setEnabled(True) self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}") def stopAcq(self): # print('Stop live') try: self.threadRunAcq.stopThreadRunAcq() print('ici') self.cam0.ExecuteSoftwareTrigger() except : print('error stop thread') pass self.runButton.setEnabled(True) #self.runButton.setStyleSheet("background-color: rgb(0, 200, 0)") self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}") #self.threadAcq.terminate() def Display(self,data): self.data=data if self.checkBoxScale.isChecked()==1: # autoscale on self.imh.setImage(data.astype(float),autoLevels=True,autoDownsample=True) if self.checkBoxFullScreen.isChecked()==1 and self.winSC.isWinOpen==True: self.winSC.Display(self.data,autoLevels=True,color=self.color) else : self.imh.setImage(data.astype(float),autoLevels=False,autoDownsample=True) if self.checkBoxFullScreen.isChecked()==1 and self.winSC.isWinOpen==True: self.winSC.Display(self.data,autoLevels=False,color=self.color) if self.winSC.isWinOpen==False: self.checkBoxFullScreen.setChecked(False) def bloquer(self): # bloque la croix self.bloqq=1 self.confCCD.setValue(self.nbcam+"/xc",int(self.xc)) # save cross postion in ini file self.confCCD.setValue(self.nbcam+"/yc",int(self.yc)) print('xc',self.xc,'yc',self.yc) def debloquer(self): # deblaoque la croix : elle bouge avec la souris self.bloqq=0 def roiChanged(self): self.rx=self.ro1.size()[0] self.ry=self.ro1.size()[1] self.confCCD.setValue(self.nbcam+"/rx",int(self.rx)) self.confCCD.setValue(self.nbcam+"/ry",int(self.ry)) def mouseMoved(self,evt): ## pour que la cross suive le mvt de la souris if self.bloqq==0: # souris non bloquer pos = evt[0] ## using signal proxy turns original arguments into a tuple if self.p1.sceneBoundingRect().contains(pos): mousePoint = self.vb.mapSceneToView(pos) self.xc = (mousePoint.x()) self.yc= (mousePoint.y()) if ((self.xc>0 and self.xc<self.data.shape[0]) and (self.yc>0 and self.yc<self.data.shape[1]) ): self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) # la croix ne bouge que dans le graph self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)]) def paletteup(self): levels=self.imh.getLevels() if levels[0]==None: xmax =self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax+(xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def palettedown(self): levels=self.imh.getLevels() if levels[0]==None: xmax=self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax- (xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def open_widget(self,fene): """ open new widget """ if fene.isWinOpen==False: fene.setup fene.isWinOpen=True #fene.Display(self.data) fene.show() else: #fene.activateWindow() fene.raise_() fene.showNormal() def closeEvent(self,event): self.fin() event.accept() def fin(self): try : self.threadRunAcq.stopThreadRunAcq() except : pass try : self.cam0.close() except : pass sys.exit(0)
class Tree(QTreeView): """File system tree """ _fileActivated = pyqtSignal() def __init__(self, fileBrowser): QTreeView.__init__(self, fileBrowser) self._fileBrowser = fileBrowser self.setAttribute(Qt.WA_MacShowFocusRect, False) self.setAttribute(Qt.WA_MacSmallSize) self.setContextMenuPolicy(Qt.ActionsContextMenu) self.setHeaderHidden(True) self.setUniformRowHeights(True) self.setTextElideMode(Qt.ElideMiddle) # dir model self._dirsModel = _FileSystemModel(self) self._dirsModel.setNameFilterDisables(False) self._dirsModel.setFilter(QDir.AllDirs | QDir.AllEntries | QDir.CaseSensitive | QDir.NoDotAndDotDot) # self._dirsModel.directoryLoaded.connect(self.setFocus) TODO don't have this signal in my Qt version # create proxy model self._filteredModel = FileBrowserFilteredModel(self) self._filteredModel.setSourceModel(self._dirsModel) self.setModel(self._filteredModel) if not sys.platform.startswith('win'): self._dirsModel.setRootPath("/") else: self._dirsModel.setRootPath('') # shortcut accessible only when self._tree has focus self._upShortcut = QShortcut(QKeySequence("BackSpace"), self) self._upShortcut.setContext(Qt.WidgetShortcut) self._upShortcut.activated.connect(self.moveUp) # shortcut accessible only when self._tree has focus self._homeShortcut = QShortcut(QKeySequence("`"), self) self._homeShortcut.setContext(Qt.WidgetShortcut) self._homeShortcut.activated.connect(self._goUserHomeDir) # shortcut accessible only when self._tree has focus self._homeShortcut = QShortcut(QKeySequence("."), self) self._homeShortcut.setContext(Qt.WidgetShortcut) self._homeShortcut.activated.connect(self._goCurrentDir) self.activated.connect(self._onActivated) self._fileActivated.connect(fileBrowser.fileActivated) # QDirModel loads item asynchronously, therefore we need timer for setting focus to the first item self._setFocusTimer = QTimer() self._setFocusTimer.timeout.connect(self._setFirstItemAsCurrent) self._setFocusTimer.setInterval(50) self._timerAttempts = 0 def term(self): self._setFocusTimer.stop() def _onActivated(self, idx): """File or directory doubleClicked """ index = self._filteredModel.mapToSource(idx) path = self._dirsModel.filePath(index) if os.path.isdir(path): self._fileBrowser.setCurrentPath(path) else: self._fileActivated.emit() core.workspace().openFile(path) core.workspace().focusCurrentDocument() def moveUp(self): """User pressed Up key or button. Move focus and root up """ current = self.currentIndex() if not current.isValid(): current = self.rootIndex().child(0, 0) self.setCurrentIndex(current) if current.parent() == self.rootIndex() or \ current == self.rootIndex(): # need to move root up if self.rootIndex().parent().isValid(): # not reached root of the FS tree newRoot = self.rootIndex().parent() parentPath = self._filteredModelIndexToPath(current.parent()) self._fileBrowser.setCurrentPath(self._filteredModelIndexToPath(newRoot)) self.collapseAll() # if moving root up - collapse all items parentIndex = self._filteredModel.mapFromSource(self._dirsModel.index(parentPath)) self._setCurrentItem(parentIndex) else: # need to move selection up parentOfCurrent = self.currentIndex().parent() self._setCurrentItem(parentOfCurrent) # move selection up def _goUserHomeDir(self): """Go to home directory """ self._fileBrowser.setCurrentPath(os.path.expanduser("~")) self.collapseAll() def _goCurrentDir(self): """Go to current directory """ self._fileBrowser.setCurrentPath(_getCurDir()) self.collapseAll() def _filteredModelIndexToPath(self, index): """Map index to file path """ srcIndex = self._filteredModel.mapToSource(index) return self._dirsModel.filePath(srcIndex) def currentPath(self): """Get current path (root of the tree) """ index = self.rootIndex() index = self._filteredModel.mapToSource(index) return self._dirsModel.filePath(index) def _isDescendant(self, child, parent): """Check if child is descendant of parent """ while child.isValid(): if child.parent() == parent: return True child = child.parent() return False def _setFirstItemAsCurrent(self): """QDirModel loads items asynchronously. Therefore we select current item by timer """ if not self.currentIndex().isValid() or \ not self._isDescendant(self.currentIndex(), self.rootIndex()): firstChild = self.rootIndex().child(0, 0) if firstChild.isValid(): self._setFocusTimer.stop() self._setCurrentItem(self.rootIndex().child(0, 0)) else: self._timerAttempts -= 1 if not self._timerAttempts: self._setFocusTimer.stop() else: # nothing to do, have focus self._setFocusTimer.stop() def setCurrentPath(self, path): """Set current path (root of the tree) """ # get index index = self._dirsModel.index(path) # set current path self._filteredModel.invalidate() newRoot = self._filteredModel.mapFromSource(index) self.setRootIndex(newRoot) self._timerAttempts = 10 self._setFocusTimer.start() def _setCurrentItem(self, index): """Make the item current and select it """ self.setCurrentIndex(index) self.selectionModel().select(index, QItemSelectionModel.SelectCurrent)
def p_shortcut_connect(k, cb): # an alias to simplify code sc = QShortcut(KS(k), ui.pc_panel) sc.setContext(Qt.WidgetWithChildrenShortcut) sc.activated.connect(cb)
class DockWidget(QDockWidget): """Extended QDockWidget for Enki main window """ closed = pyqtSignal() """ closed() **Signal** emitted, when dock is closed """ shown = pyqtSignal() """ shown() **Signal** emitted, when dock is shown """ def __init__(self, parentObject, windowTitle, windowIcon=QIcon(), shortcut=None): QDockWidget.__init__(self, parentObject) self._showAction = None self.setObjectName(str(self.__class__)) self.setWindowTitle(windowTitle) if not windowIcon.isNull(): self.setWindowIcon(windowIcon) if shortcut is not None: self.showAction().setShortcut(shortcut) self._titleBar = _TitleBar(self) self.setTitleBarWidget(self._titleBar) if shortcut is not None: toolTip = "Move focus with <b>%s</b>,<br/>close with <b>Esc</b>" % shortcut else: toolTip = "Close with <b>Esc</b>" self._titleBar.setToolTip(toolTip) self._closeShortcut = QShortcut(QKeySequence("Esc"), self) self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut) self._closeShortcut.activated.connect(self._close) def keyPressEvent(self, event): """Catch Esc. Not using QShortcut, because dock shall be closed, only if child widgets haven't catched Esc event """ if event.key() == Qt.Key_Escape and \ event.modifiers() == Qt.NoModifier: self._hide() else: QDockWidget.keyPressEvent(self, event) def showAction(self): """Action shows the widget and set focus on it. Add this action to the main menu """ if not self._showAction: self._showAction = QAction(self.windowIcon(), self.windowTitle(), self) self._showAction.triggered.connect(self.show) self._showAction.triggered.connect(self._handleFocusProxy) return self._showAction def titleBarWidget(self): """QToolBar on the title. You may add own actions to this tool bar """ # method was added only for documenting return QDockWidget.titleBarWidget(self) def _handleFocusProxy(self): """Set focus to focus proxy. Called after widget has been shown """ if self.focusProxy() is not None: self.setFocus() def _close(self): """Hide and return focus to MainWindow focus proxy """ self.close() if ( self.parent() is not None and self.parent().focusProxy() is not None and self.hasFocus() ): self.parent().focusProxy().setFocus() def closeEvent(self, event): """Widget was closed""" self.closed.emit() def show(self): QDockWidget.show(self) # If floating, then active this window so it will receive keyboard # input. if self.isFloating(): self.activateWindow() def showEvent(self, event): """Widget was shown""" self.shown.emit() def isPinned(self): """True if the widget is pinned; false if unpinned (auto-hide mode).""" return not self._titleBar.tbUnPinned.isChecked()
def __init__(self): QMainWindow.__init__(self) Ui_MainWindow.setupUi(self, self) self.playlistDrop.dragEnterEvent = self.playlistDragEnterEvent self.playlistDrop.dropEvent = self.playlistDropEvent self.playlistModel = PlaylistModel() self.playlistTable.setModel(self.playlistModel) self.playlistTable.customContextMenuRequested.connect(self.playlistContextMenu) self.playlistTable.doubleClicked.connect(self.onPlaylistDoubleClick) self.playback = PlaybackWidget(self) self.playbackLayout.addWidget(self.playback) self.playback.playButton.clicked.connect(self.onPlaySelected) self.playback.nextButton.clicked.connect(self.onNextClicked) self.playback.prevButton.clicked.connect(self.onPrevClicked) self.libraryDock.setTitleBarWidget(QWidget()) self.playlistsDock.setTitleBarWidget(QWidget()) self.toggleLibraryButton.clicked.connect(self.onToggleLibrary) self.togglePlaylistsButton.clicked.connect(self.onTogglePlaylists) self.library = LibraryWidget(self) self.libraryDock.setWidget(self.library) self.libraryDock.hide() self.library.itemsActivated.connect(self.onLibraryItemActivated) self.playlists = PlaylistsWidget(self) self.playlistsDock.setWidget(self.playlists) self.playlistsDock.hide() self.playlists.loadPlaylist.connect(self.onPlaylistLoad) self.dockState = 0 self.settings = QSettings('txplaya', 'txplaya') if u'geometry/main' in self.settings.allKeys(): self.setGeometry(self.settings.value(u'geometry/main')) for col in range(self.playlistModel.columnCount()): width = self.settings.value(u'geometry/playlist/col/%d' % col) self.playlistTable.setColumnWidth(col, int(width)) dockState = int(self.settings.value(u'geometry/dock/state')) self.dockShow(dockState) self.systemTray = QSystemTrayIcon(self.windowIcon()) self.systemTray.setToolTip('Playa') self.systemTray.show() self.systemTray.activated.connect(self.systemTrayToggle) systemTrayMenu = QMenu() systemTrayMenu.addAction(self.restore) systemTrayMenu.addAction(self.quit) self.systemTray.setContextMenu(systemTrayMenu) self.restore.triggered.connect(self.restoreWindow) self.quit.triggered.connect(self.quitEvent) self.quitButton.clicked.connect(self.quitEvent) self.quitFlag = False # keyboard shortcuts focusLibraryShortcut = QShortcut(QKeySequence('Ctrl+F'), self) focusLibraryShortcut.activated.connect(self.onFocusLibrary) deleteTrackShortcut = QShortcut(QKeySequence('Del'), self.playlistTable) deleteTrackShortcut.setContext(Qt.WidgetShortcut) deleteTrackShortcut.activated.connect(self.onDeleteTrack) togglePlaybackShortcut = QShortcut(QKeySequence('Space'), self) togglePlaybackShortcut.activated.connect(self.onTogglePlayback) startShortcut = QShortcut(QKeySequence(Qt.Key_Return), self.playlistTable) startShortcut.setContext(Qt.WidgetShortcut) startShortcut.activated.connect(self.onPlaySelected) undoShortcut = QShortcut(QKeySequence('Ctrl+Z'), self) undoShortcut.activated.connect(self.onPlaylistUndo) redoShortcut = QShortcut(QKeySequence('Ctrl+Shift+Z'), self) redoShortcut.activated.connect(self.onPlaylistRedo) saveShortcut = QShortcut(QKeySequence('Ctrl+S'), self) saveShortcut.activated.connect(self.onPlaylistSave) self.infoStreamStart() QTimer.singleShot(200, self.fetchLibrary)
class DockWidget(QDockWidget): """Extended QDockWidget for Enki main window """ closed = pyqtSignal() """ closed() **Signal** emitted, when dock is closed """ shown = pyqtSignal() """ shown() **Signal** emitted, when dock is shown """ def __init__(self, parentObject, windowTitle, windowIcon=QIcon(), shortcut=None): QDockWidget.__init__(self, parentObject) self._showAction = None self.setObjectName(str(self.__class__)) self.setWindowTitle(windowTitle) self.setFeatures(self.features() & (~QDockWidget.DockWidgetFloatable)) if not windowIcon.isNull(): self.setWindowIcon(windowIcon) if shortcut is not None: self.showAction().setShortcut(shortcut) self._titleBar = _TitleBar(self) self.setTitleBarWidget(self._titleBar) if shortcut is not None: toolTip = "Move focus with <b>%s</b>,<br/>close with <b>Esc</b>" % shortcut else: toolTip = "Close with <b>Esc</b>" self._titleBar.setToolTip(toolTip) self._closeShortcut = QShortcut(QKeySequence("Esc"), self) self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut) self._closeShortcut.activated.connect(self._close) def keyPressEvent(self, event): """Catch Esc. Not using QShortcut, because dock shall be closed, only if child widgets haven't catched Esc event """ if event.key() == Qt.Key_Escape and \ event.modifiers() == Qt.NoModifier: self._hide() else: QDockWidget.keyPressEvent(self, event) def showAction(self): """Action shows the widget and set focus on it. Add this action to the main menu """ if not self._showAction: self._showAction = QAction(self.windowIcon(), self.windowTitle(), self) self._showAction.triggered.connect(self.show) self._showAction.triggered.connect(self._handleFocusProxy) return self._showAction def titleBarWidget(self): """QToolBar on the title. You may add own actions to this tool bar """ # method was added only for documenting return QDockWidget.titleBarWidget(self) def _handleFocusProxy(self): """Set focus to focus proxy. Called after widget has been shown """ if self.focusProxy() is not None: self.setFocus() def _close(self): """Hide and return focus to MainWindow focus proxy """ self.close() if self.parent() is not None and \ self.parent().focusProxy() is not None: self.parent().focusProxy().setFocus() def closeEvent(self, event): """Widget was closed""" self.closed.emit() def showEvent(self, event): """Widget was shown""" self.shown.emit()
def __init__(self, controller: 'Controller') -> None: super().__init__() self._controller = controller self.setCacheMode(QGraphicsView.CacheBackground) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self._show_filtered = False self._location2item: Dict[Location, List[FileItem]] = defaultdict(list) self.setAcceptDrops(True) self._scene = FileGraphicsScene() self._scene.sig_files_drop.connect(self._controller.on_files_drop) self.setScene(self._scene) self._scene.selectionChanged.connect(self.on_selection_changed) self._style = FileViewStyle() self._modes: List[Mode] = [ IconMode(self), ListMode(self), DetailMode(self) ] self._mode = self._modes[FileItemStyle.ICON.value] self._layout: Optional[RootLayout] = None self._items: List[FileItem] = [] self._file_collection: Optional[FileCollection] = None self._needs_layout = True self.apply_zoom() self._cursor_item: Optional[FileItem] = None self._crop_thumbnails = False self.setBackgroundBrush(QBrush(Qt.white, Qt.SolidPattern)) self._resize_timer: Optional[int] = None self.setDragMode(QGraphicsView.RubberBandDrag) self.setRenderHints(QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing | QPainter.Antialiasing) shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_G), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(self._on_reset) shortcut = QShortcut(QKeySequence(Qt.Key_Slash), self) shortcut.setContext(Qt.WidgetShortcut) shortcut.activated.connect(lambda: self._controller.show_location_toolbar(False)) self._leap_widget = LeapWidget(self) self._leap_widget.sig_leap.connect(self.leap_to) self._scroll_timer = None self._is_scrolling = False self.verticalScrollBar().sliderReleased.connect(self._on_vertical_scrollbar_slider_released) self.verticalScrollBar().valueChanged.connect(self._on_vertical_scrollbar_slider_value_changed)
class SEELIGHTTHREAD(QWidget) : '''open and plot file : SEE(file='nameFile,path=pathFileName,confpath,confMot) Make plot profile ands differents measurements(max,min mean...) Can open .spe .SPE .sif .TIFF files confpath :usefull if more than 2 SEE object used confMot usefull if RSAI motors is read ''' newMesurment=QtCore.pyqtSignal(object) def __init__(self,parent=None,file=None,path=None,**kwds): print('LightThread') super(SEELIGHTTHREAD, self).__init__() self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # dark style self.parent=parent version=__version__ p = pathlib.Path(__file__) sepa=os.sep self.icon=str(p.parent) + sepa+'icons' +sepa ## kwds definition: if "confpath"in kwds : self.confpath=kwds["confpath"] self.conf=QtCore.QSettings(self.confpath, QtCore.QSettings.IniFormat) else: self.conf=QtCore.QSettings(str(p.parent / 'confVisu.ini'), QtCore.QSettings.IniFormat) if "name" in kwds: self.name=kwds["name"] else: self.name="VISU" if "meas" in kwds: self.meas=kwds["meas"] else: self.meas="on" if "confMot" in kwds: print('motor accepted') if self.meas=="on": self.confMot=kwds["confoMot"] self.winM=MEAS(confMot=self.confMot,conf=self.conf,name=self.name) else : if self.meas=="on": self.winM=MEAS(self,conf=self.conf,name=self.name) if "aff" in kwds: self.aff=kwds["aff"] else: self.aff="left" if "saveTiff" in kwds: self.tiff=kwds["saveTiff"] else: self.tiff=True self.nomFichier='' self.ite=None self.path=path self.setWindowTitle('Visualization'+' v.'+ version) self.bloqKeyboard=bool((self.conf.value(self.name+"/bloqKeyboard")) ) # block cross by keyboard self.bloqq=1 # block the cross by click on mouse self.setup() self.shortcut() self.actionButton() self.activateWindow() self.raise_() self.showNormal() self.setWindowIcon(QIcon(self.icon+'LOA.png')) def twoD_Gaussian(x,y, amplitude, xo, yo, sigma_x, sigma_y, theta, offset): xo = float(xo) yo = float(yo) a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2) b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2) c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2) return offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2))) if file==None: # to have a gaussian picture when we start self.dimy=960 self.dimx=1240 # Create x and y index self.x = np.arange(0,self.dimx) self.y = np.arange(0,self.dimy) self.y,self.x = np.meshgrid(self.y, self.x) self.data=twoD_Gaussian(self.x, self.y,450, 800, 600, 40, 40, 0, 10)+(50*np.random.rand(self.dimx,self.dimy)).round() #self.data=(50*np.random.rand(self.dimx,self.dimy)).round() + 150 else: if path==None: self.path=self.conf.value(self.name+"/path") self.data=self.OpenF(fileOpen=self.path+'/'+file) self.Display(self.data) def setup(self): # definition of all button TogOff=self.icon+'Toggle_Off.png' TogOn=self.icon+'Toggle_On.png' TogOff=pathlib.Path(TogOff) TogOff=pathlib.PurePosixPath(TogOff) TogOn=pathlib.Path(TogOn) TogOn=pathlib.PurePosixPath(TogOn) self.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(%s);}""QCheckBox::indicator:checked { image: url(%s);}""QCheckBox{font :10pt;}" % (TogOff,TogOn) ) vbox1=QVBoxLayout() self.hbox0=QHBoxLayout() vbox1.addLayout(self.hbox0) hbox1=QHBoxLayout() self.checkBoxPlot=QCheckBox('CROSS',self) self.checkBoxPlot.setChecked(False) self.label_CrossValue=QLabel() self.label_CrossValue.setStyleSheet("font:13pt") hbox1.addWidget(self.checkBoxPlot) hbox1.addWidget(self.label_CrossValue) hbox2=QHBoxLayout() self.label_Cross=QLabel() #self.label_Cross.setMaximumHeight(20) self.label_Cross.setMaximumWidth(170) self.label_Cross. setStyleSheet("font:12pt") hbox2.addWidget(self.label_Cross) vbox1.addLayout(hbox1) vbox1.addLayout(hbox2) self.ZoomLabel=QLabel('Zoom') vbox1.addWidget(self.ZoomLabel) self.checkBoxZoom=QSlider(Qt.Horizontal) self.checkBoxZoom.setMaximumWidth(250) self.checkBoxZoom.setMinimum(0) self.checkBoxZoom.setMaximum(200) self.checkBoxZoom.setValue(0) vbox1.addWidget(self.checkBoxZoom) self.checkBoxScale=QCheckBox('Auto Scale',self) self.checkBoxScale.setChecked(True) self.checkBoxScale.setMaximumWidth(100) self.checkBoxColor=QCheckBox('Color',self) self.checkBoxColor.setChecked(True) self.checkBoxHist=QCheckBox('Hist',self) self.checkBoxHist.setChecked(False) self.maxGraphBox=QCheckBox('Max',self) hbox3=QHBoxLayout() grid_layout = QGridLayout() grid_layout.setVerticalSpacing(0) grid_layout.setHorizontalSpacing(10) grid_layout.addWidget(self.checkBoxScale, 0, 0) grid_layout.addWidget(self.checkBoxColor,1,0) grid_layout.addWidget(self.checkBoxHist, 0, 1) #grid_layout.addWidget(self.checkBoxZoom, 1, 0) grid_layout.addWidget(self.maxGraphBox, 1,1) hbox3.addLayout(grid_layout) vbox1.addLayout(hbox3) hbox4=QHBoxLayout() if self.meas=='on': self.MeasButton=QPushButton('Meas.') hbox4.addWidget(self.MeasButton) vbox1.addLayout(hbox4) vbox1.addStretch(1) self.winImage = pg.GraphicsLayoutWidget() #self.winImage.setContentsMargins(1,1,1,1) self.winImage.setAspectLocked(True) self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) #self.winImage.ci.setContentsMargins(1,1,1,1) vbox2=QVBoxLayout() # self.dockImage=QDockWidget(self) # self.dockImage.setWidget(self.winImage) # self.dockImage.setFeatures(QDockWidget.DockWidgetFloatable) #vbox2.addWidget(self.dockImage) vbox2.addWidget(self.winImage) vbox2.setContentsMargins(0,0,0,0) self.p1=self.winImage.addPlot() self.imh=pg.ImageItem() self.axeX=self.p1.getAxis('bottom') self.axeY=self.p1.getAxis('left') self.p1.addItem(self.imh) self.p1.setMouseEnabled(x=False,y=False) self.p1.setContentsMargins(0,0,0,0) self.p1.setAspectLocked(True,ratio=1) self.p1.showAxis('right',show=False) self.p1.showAxis('top',show=False) self.p1.showAxis('left',show=True) self.p1.showAxis('bottom',show=True) if self.bloqKeyboard==True: self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='r') self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='r') else: self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='y') self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='y') self.xc=int(self.conf.value(self.name+"/xc")) self.yc=int(self.conf.value(self.name+"/yc")) self.rx=int(self.conf.value(self.name+"/rx")) self.ry=int(self.conf.value(self.name+"/ry")) self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) self.ro1=pg.EllipseROI([self.xc,self.yc],[self.rx,self.ry],pen='y',movable=False,maxBounds=QtCore.QRectF(0,0,self.rx,self.ry)) self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)]) # text for fwhm on p1 self.textX = pg.TextItem(angle=-90) self.textY = pg.TextItem() #histogram self.hist = pg.HistogramLUTItem() self.hist.setImageItem(self.imh) self.hist.autoHistogramRange() self.hist.gradient.loadPreset('flame') ## XY graph self.curve2=pg.PlotCurveItem() self.curve3=pg.PlotCurveItem() ## main layout hMainLayout=QHBoxLayout() if self.aff=='right': hMainLayout.addLayout(vbox2) hMainLayout.addLayout(vbox1) else : hMainLayout.addLayout(vbox1) hMainLayout.addLayout(vbox2) hMainLayout.setContentsMargins(1,1,1,1) hMainLayout.setSpacing(1) hMainLayout.setStretch(10,1) self.setLayout(hMainLayout) self.setContentsMargins(1,1,1,1) def actionButton(self): # action of button self.checkBoxColor.stateChanged.connect(self.Color) self.checkBoxPlot.stateChanged.connect(self.PlotXY) self.ro1.sigRegionChangeFinished.connect(self.roiChanged) self.checkBoxZoom.valueChanged.connect(self.Zoom) #self.checkBoxZoom.stateChanged.connect(self.Zoom) self.checkBoxHist.stateChanged.connect(self.HIST) self.maxGraphBox.stateChanged.connect(self.Coupe) if self.meas=='on': self.MeasButton.clicked.connect(self.Measurement,QtCore.Qt.DirectConnection) # send data to widget measurement if self.parent is not None : # reveceive data display it self.parent.dataSignal.connect(self.Display)#,QtCore.Qt.DirectConnection) def shortcut(self): # keyboard shortcut self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self) self.shortcutPu.activated.connect(self.paletteup) self.shortcutPu.setContext(Qt.ShortcutContext(3)) #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus. self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self) self.shortcutPd.activated.connect(self.palettedown) self.shortcutPd.setContext(Qt.ShortcutContext(3)) self.shortcutOpen=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+o"),self) self.shortcutOpen.activated.connect(self.OpenF) self.shortcutOpen.setContext(Qt.ShortcutContext(3)) self.shortcutSave=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+s"),self) self.shortcutSave.activated.connect(self.SaveF) self.shortcutSave.setContext(Qt.ShortcutContext(3)) if self.meas=='on': self.shortcutMeas=QtGui.QShortcut(QtGui.QKeySequence('Ctrl+m'),self) self.shortcutMeas.activated.connect(self.Measurement) self.shortcutMeas.setContext(Qt.ShortcutContext(3)) self.shortcutBloq=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self) self.shortcutBloq.activated.connect(self.bloquer) self.shortcutBloq.setContext(Qt.ShortcutContext(3)) self.shortcutDebloq=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self) self.shortcutDebloq.activated.connect(self.debloquer) self.shortcutDebloq.setContext(Qt.ShortcutContext(3)) # mousse action: self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) self.p1.scene().sigMouseClicked.connect(self.mouseClick) self.vb=self.p1.vb def Measurement(self) : # show widget for measurement on all image or ROI (max, min mean ...) if self.ite=='rect': self.RectChanged() self.winM.setFile(self.nomFichier) self.open_widget(self.winM) self.winM.Display(self.cut) if self.ite=='cercle': self.CercChanged() self.winM.setFile(self.nomFichier) self.open_widget(self.winM) self.winM.Display(self.cut) # if self.ite=='line': # self.LigneChanged() # self.winM.setFile(self.nomFichier) # self.open_widget(self.winM) # self.winM.Display(self.cut) if self.meas=="on": if self.ite==None: self.winM.setFile(self.nomFichier) self.open_widget(self.winM) self.winM.Display(self.data) def Display(self,data): # display the data and refresh all the calculated things and plots self.data=data self.dimy=np.shape(self.data)[1] self.dimx=np.shape(self.data)[0] self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) self.p1.setAspectLocked(True,ratio=1) if self.checkBoxScale.isChecked()==1: # autoscale on self.imh.setImage(self.data.astype(float),autoLevels=True,autoDownsample=True) else : self.imh.setImage(self.data.astype(float),autoLevels=False,autoDownsample=True) if self.meas=="on" : if self.winM.isWinOpen==True: self.newMesurment.emit(self.data)# measurement update #self.Measurement() self.Zoom() # update zoom def mouseClick(self): # block the cross if mousse button clicked if self.bloqq==1: self.bloqq=0 else : self.bloqq=1 self.conf.setValue(self.name+"/xc",int(self.xc)) # save cross postion in ini file self.conf.setValue(self.name+"/yc",int(self.yc)) def mouseMoved(self,evt): ## the cross mouve with the mousse mvt if self.bloqKeyboard==False : #mouse not blocked by keyboard if self.bloqq==0: # mouse not blocked by mouse click pos = evt[0] ## using signal proxy turns original arguments into a tuple if self.p1.sceneBoundingRect().contains(pos): mousePoint = self.vb.mapSceneToView(pos) self.xMouse = (mousePoint.x()) self.yMouse= (mousePoint.y()) if ((self.xMouse>0 and self.xMouse<self.dimx-1) and (self.yMouse>0 and self.yMouse<self.dimy-1) ): self.xc = self.xMouse self.yc= self.yMouse self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) # the cross move only in the graph #self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)]) self.PlotXY() def fwhm(self,x, y, order=3): """ Determine full-with-half-maximum of a peaked set of points, x and y. """ y=gaussian_filter(y,5) # filtre for reducing noise half_max = np.amax(y)/2.0 s = splrep(x, y - half_max,k=order) # F roots = sproot(s) # Given the knots . if len(roots) > 2: pass elif len(roots) < 2: pass else: return np.around(abs(roots[1] - roots[0]),decimals=2) def Coupe(self): # make plot profile on cross if self.maxGraphBox.isChecked()==True and self.bloqKeyboard==False: # find and fix the cross on the maximum of the image dataF=gaussian_filter(self.data,5) (self.xc,self.yc)=pylab.unravel_index(dataF.argmax(),self.data.shape) #take the max ndimage.measurements.center_of_mass(dataF)# self.vLine.setPos(self.xc) self.hLine.setPos(self.yc) dataCross=self.data[int(self.xc),int(self.yc)] coupeX=self.data[int(self.xc),:] coupeY=self.data[:,int(self.yc)] xxx=np.arange(0,int(self.dimx),1)# yyy=np.arange(0,int(self.dimy),1)# coupeXMax=np.max(coupeX) coupeYMax=np.max(coupeY) if coupeXMax==0: # avoid zero coupeXMax=1 if coupeYMax==0: coupeYMax=1 self.label_Cross.setText('x='+ str(int(self.xc)) + ' y=' + str(int(self.yc)) ) dataCross=round(dataCross,3) # take data value on the cross self.label_CrossValue.setText(' v.=' + str(dataCross)) coupeXnorm=(self.data.shape[0]/10)*(coupeX/coupeXMax) # normalize the curves self.curve2.setData(20+self.xminR+coupeXnorm,yyy,clear=True) coupeYnorm=(self.data.shape[1]/10)*(coupeY/coupeYMax) self.curve3.setData(xxx,20+self.yminR+coupeYnorm,clear=True) def PlotXY(self): # plot curves on the graph if self.checkBoxPlot.isChecked()==1: self.p1.addItem(self.vLine, ignoreBounds=False) self.p1.addItem(self.hLine, ignoreBounds=False) self.p1.addItem(self.curve2) self.p1.addItem(self.curve3) self.p1.showAxis('left',show=True) self.p1.showAxis('bottom',show=True) self.p1.addItem(self.textX) self.p1.addItem(self.textY) self.Coupe() else: self.p1.removeItem(self.vLine) self.p1.removeItem(self.hLine) self.p1.removeItem(self.curve2) self.p1.removeItem(self.curve3) self.p1.removeItem(self.textX) self.p1.removeItem(self.textY) self.p1.showAxis('left',show=False) self.p1.showAxis('bottom',show=False) self.p1.removeItem(self.textX) self.p1.removeItem(self.textY) def paletteup(self): # change the color scale levels=self.imh.getLevels() if levels[0]==None: xmax =self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax-(xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def palettedown(self): levels=self.imh.getLevels() if levels[0]==None: xmax=self.data.max() xmin=self.data.min() else : xmax=levels[1] xmin=levels[0] self.imh.setLevels([xmin, xmax+ (xmax- xmin) / 10]) #hist.setImageItem(imh,clear=True) self.hist.setHistogramRange(xmin,xmax) def Color(self): """ image in colour/n&b """ if self.checkBoxColor.isChecked()==1: self.hist.gradient.loadPreset('flame') else: self.hist.gradient.loadPreset('grey') def Zoom(self): """Zoom function """ self.zo=self.checkBoxZoom.value() # if self.checkBoxPlot.isChecked()==0: # self.xc=self.dimx/2 # self.yc=self.dimy/2 if self.zo<=2: self.zo=0 self.p1.setXRange(0,self.dimx) self.p1.setYRange(0,self.dimy) self.xminR=0 self.yminR=0 self.xmaxR=self.dimx self.ymaxR=self.dimy else: self.xminR=self.xc-(self.dimx-self.xc)*(1-self.zo/200) self.xmaxR=self.xc+(self.dimx-self.xc)*(1-self.zo/200) self.yminR=self.yc-(self.dimy-self.yc)*(1-self.zo/200) self.ymaxR=self.yc+(self.dimy-self.yc)*(1-self.zo/200) if self.xminR<0: self.xminR=0 if self.xmaxR>self.dimx: self.xmaxR=self.dimx if self.yminR<0: self.yminR=0 if self.ymaxR>self.dimy: self.ymaxR=self.dimy self.p1.setXRange(self.xminR,self.xmaxR) self.p1.setYRange(self.yminR,self.ymaxR) self.Coupe() def roiChanged(self): self.rx=self.ro1.size()[0] self.ry=self.ro1.size()[1] self.conf.setValue(self.name+"/rx",int(self.rx)) self.conf.setValue(self.name+"/ry",int(self.ry)) def bloquer(self): # block the cross self.bloqKeyboard=bool(True) self.conf.setValue(self.name+"/xc",int(self.xc))# save cross postion in ini file self.conf.setValue(self.name+"/yc",int(self.yc)) self.conf.setValue(self.name+"/bloqKeyboard",bool(self.bloqKeyboard)) self.vLine.setPen('r') self.hLine.setPen('r') def debloquer(self): # unblock the cross self.bloqKeyboard=bool(False) self.vLine.setPen('y') self.hLine.setPen('y') self.conf.setValue(self.name+"/bloqKeyboard",bool(self.bloqKeyboard)) def HIST(self): #show histogramm if self.checkBoxHist.isChecked()==1: self.winImage.addItem(self.hist) else: self.winImage.removeItem(self.hist) def OpenF(self,fileOpen=False): #open file in txt spe TIFF sif format fileOpen=fileOpen print(fileOpen) print('open') if fileOpen==False: print('ici') chemin=self.conf.value(self.name+"/path") fname=QtGui.QFileDialog.getOpenFileName(self,"Open File",chemin,"Images (*.txt *.spe *.TIFF *.sif *.tif);;Text File(*.txt);;Ropper File (*.SPE);;Andor File(*.sif);; TIFF file(*.TIFF)") fichier=fname[0] else: fichier=str(fileOpen) ext=os.path.splitext(fichier)[1] if ext=='.txt': # text file data=np.loadtxt(str(fichier)) elif ext=='.spe' or ext=='.SPE': # SPE file dataSPE=SpeFile(fichier) data1=dataSPE.data[0]#.transpose() # first frame data=data1#np.flipud(data1) elif ext=='.TIFF' or ext=='.tif':# tiff File dat=Image.open(fichier) data=np.array(dat) elif ext=='.sif': sifop=SifFile() im=sifop.openA(fichier) data=np.rot90(im,3) # self.data=self.data[250:495,:] else : msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Wrong file format !") msg.setInformativeText("The format of the file must be : .SPE .TIFF .sif or .txt ") msg.setWindowTitle("Warning ...") msg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) msg.exec_() chemin=os.path.dirname(fichier) self.conf.setValue(self.name+"/path",chemin) self.conf.setValue(self.name+"/lastFichier",os.path.split(fichier)[1]) self.fileName.setText(os.path.split(fichier)[1]) self.nomFichier=os.path.split(fichier)[1] self.newDataReceived(data) def SaveF (self): # save data in TIFF if self.tiff==True: fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as TIFF",self.path) self.path=os.path.dirname(str(fname[0])) fichier=fname[0] ext=os.path.splitext(fichier)[1] #print(ext) print(fichier,' is saved') self.conf.setValue(self.name+"/path",self.path) time.sleep(0.1) img_PIL = Image.fromarray(self.data) img_PIL.save(str(fname[0])+'.TIFF',format='TIFF') else : fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as txt",self.path) self.path=os.path.dirname(str(fname[0])) fichier=fname[0] ext=os.path.splitext(fichier)[1] #print(ext) print(fichier,' is saved') self.conf.setValue(self.name+"/path",self.path) time.sleep(0.1) np.savetxt(str(fichier)+'.txt',self.data) def newDataReceived(self,data): # Do display and save origin data when new data is sent to visu self.data=data self.dimy=np.shape(self.data)[1] self.dimx=np.shape(self.data)[0] #self.Display(self.data) self.dataSignal.emit(self.data) def open_widget(self,fene): """ open new widget """ if fene.isWinOpen==False: fene.setup fene.isWinOpen=True #fene.Display(self.data) fene.show() else: #fene.activateWindow() fene.raise_() fene.showNormal() def closeEvent(self,event): # when the window is closed if self.winM.isWinOpen==True: self.winM.close()
class SearchWidget(QFrame): """Widget, appeared, when Ctrl+F pressed. Has different forms for different search modes """ Normal = 'normal' Good = 'good' Bad = 'bad' Incorrect = 'incorrect' visibilityChanged = pyqtSignal(bool) """ visibilityChanged(visible) **Signal** emitted, when widget has been shown or hidden """ # pylint: disable=W0105 searchInDirectoryStartPressed = pyqtSignal(type(re.compile('')), list, str) """ searchInDirectoryStartPressed(regEx, mask, path) **Signal** emitted, when 'search in directory' button had been pressed """ # pylint: disable=W0105 searchInDirectoryStopPressed = pyqtSignal() """ searchInDirectoryStopPressed() **Signal** emitted, when 'stop search in directory' button had been pressed """ # pylint: disable=W0105 replaceCheckedStartPressed = pyqtSignal(str) """ replaceCheckedStartPressed(replText) **Signal** emitted, when 'replace checked' button had been pressed """ # pylint: disable=W0105 replaceCheckedStopPressed = pyqtSignal() """ replaceCheckedStartPressed() **Signal** emitted, when 'stop replacing checked' button had been pressed """ # pylint: disable=W0105 searchRegExpChanged = pyqtSignal(type(re.compile(''))) """ searchRegExpValidStateChanged(regEx) **Signal** emitted, when search regexp has been changed. If reg exp is invalid - regEx object contains empty pattern """ # pylint: disable=W0105 searchNext = pyqtSignal() """ searchNext() **Signal** emitted, when 'Search Next' had been pressed """ # pylint: disable=W0105 searchPrevious = pyqtSignal() """ searchPrevious() **Signal** emitted, when 'Search Previous' had been pressed """ # pylint: disable=W0105 replaceFileOne = pyqtSignal(str) """ replaceFileOne(replText) **Signal** emitted, when 'Replace' had been pressed """ # pylint: disable=W0105 replaceFileAll = pyqtSignal(str) """ replaceFileAll(replText) **Signal** emitted, when 'Replace All' had been pressed """ # pylint: disable=W0105 def __init__(self, plugin): QFrame.__init__(self, core.workspace()) self._mode = None self.plugin = plugin uic.loadUi(os.path.join(os.path.dirname(__file__), 'SearchWidget.ui'), self) self.cbSearch.setCompleter(None) self.cbReplace.setCompleter(None) self.cbMask.setCompleter(None) self.fsModel = QDirModel(self.cbPath.lineEdit()) self.fsModel.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) self.cbPath.lineEdit().setCompleter( QCompleter(self.fsModel, self.cbPath.lineEdit())) self._pathBackspaceShortcut = QShortcut(QKeySequence("Ctrl+Backspace"), self.cbPath, self._onPathBackspace) self._pathBackspaceShortcut.setContext(Qt.WidgetWithChildrenShortcut) # TODO QDirModel is deprecated but QCompleter does not yet handle # QFileSystemodel - please update when possible.""" self.cbSearch.setCompleter(None) self.pbSearchStop.setVisible(False) self.pbReplaceCheckedStop.setVisible(False) self._progress = QProgressBar(self) self._progress.setAlignment(Qt.AlignCenter) self._progress.setToolTip(self.tr("Search in progress...")) self._progress.setMaximumSize(QSize(80, 16)) core.mainWindow().statusBar().insertPermanentWidget(1, self._progress) self._progress.setVisible(False) # cd up action self.tbCdUp = QToolButton(self.cbPath.lineEdit()) self.tbCdUp.setIcon(QIcon(":/enkiicons/go-up.png")) self.tbCdUp.setCursor(Qt.ArrowCursor) self.tbCdUp.installEventFilter(self) # for drawing button self.cbSearch.installEventFilter( self) # for catching Tab and Shift+Tab self.cbReplace.installEventFilter( self) # for catching Tab and Shift+Tab self.cbPath.installEventFilter(self) # for catching Tab and Shift+Tab self.cbMask.installEventFilter(self) # for catching Tab and Shift+Tab self._closeShortcut = QShortcut(QKeySequence("Esc"), self) self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut) self._closeShortcut.activated.connect(self.hide) # connections self.cbSearch.lineEdit().textChanged.connect( self._onSearchRegExpChanged) self.cbSearch.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbReplace.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbPath.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbMask.lineEdit().returnPressed.connect(self._onReturnPressed) self.cbRegularExpression.stateChanged.connect( self._onSearchRegExpChanged) self.cbCaseSensitive.stateChanged.connect(self._onSearchRegExpChanged) self.cbWholeWord.stateChanged.connect(self._onSearchRegExpChanged) self.tbCdUp.clicked.connect(self._onCdUpPressed) self.pbNext.pressed.connect(self.searchNext) self.pbPrevious.pressed.connect(self.searchPrevious) self.pbSearchStop.pressed.connect(self.searchInDirectoryStopPressed) self.pbReplaceCheckedStop.pressed.connect( self.replaceCheckedStopPressed) core.mainWindow().hideAllWindows.connect(self.hide) core.workspace().escPressed.connect(self.hide) core.workspace().currentDocumentChanged.connect( lambda old, new: self.setVisible(self.isVisible() and new is not None)) def show(self): """Reimplemented function. Sends signal """ super(SearchWidget, self).show() self.visibilityChanged.emit(self.isVisible()) def hide(self): """Reimplemented function. Sends signal, returns focus to workspace """ super(SearchWidget, self).hide() core.workspace().focusCurrentDocument() self.visibilityChanged.emit(self.isVisible()) def setVisible(self, visible): """Reimplemented function. Sends signal """ super(SearchWidget, self).setVisible(visible) self.visibilityChanged.emit(self.isVisible()) def _regExEscape(self, text): """Improved version of re.escape() Doesn't escape space, comma, underscore. Escapes \n and \t """ text = re.escape(text) # re.escape escapes space, comma, underscore, but, it is not necessary and makes text not readable for symbol in (' ,_=\'"/:@#%&'): text = text.replace('\\' + symbol, symbol) text = text.replace('\\\n', '\\n') text = text.replace('\\\t', '\\t') return text def _makeEscapeSeqsVisible(self, text): """Replace invisible \n and \t with escape sequences """ text = text.replace('\\', '\\\\') text = text.replace('\t', '\\t') text = text.replace('\n', '\\n') return text def setMode(self, mode): """Change search mode. i.e. from "Search file" to "Replace directory" """ if self._mode == mode and self.isVisible(): if core.workspace().currentDocument() is not None and \ not core.workspace().currentDocument().hasFocus(): self.cbSearch.lineEdit().selectAll() self.cbSearch.setFocus() self._mode = mode # Set Search and Replace text document = core.workspace().currentDocument() if document is not None and \ document.hasFocus() and \ document.qutepart.selectedText: searchText = document.qutepart.selectedText self.cbReplace.setEditText(self._makeEscapeSeqsVisible(searchText)) if self.cbRegularExpression.checkState() == Qt.Checked: searchText = self._regExEscape(searchText) self.cbSearch.setEditText(searchText) if not self.cbReplace.lineEdit().text() and \ self.cbSearch.lineEdit().text() and \ not self.cbRegularExpression.checkState() == Qt.Checked: replaceText = self.cbSearch.lineEdit().text().replace('\\', '\\\\') self.cbReplace.setEditText(replaceText) # Move focus to Search edit self.cbSearch.setFocus() self.cbSearch.lineEdit().selectAll() # Set search path if mode & MODE_FLAG_DIRECTORY and \ not (self.isVisible() and self.cbPath.isVisible()): try: searchPath = os.path.abspath(str(os.path.curdir)) except OSError: # current directory might have been deleted pass else: self.cbPath.setEditText(searchPath) # Set widgets visibility flag according to state widgets = (self.wSearch, self.pbPrevious, self.pbNext, self.pbSearch, self.wReplace, self.wPath, self.pbReplace, self.pbReplaceAll, self.pbReplaceChecked, self.wOptions, self.wMask) # wSear pbPrev pbNext pbSear wRepl wPath pbRep pbRAll pbRCHK wOpti wMask visible = \ {MODE_SEARCH: (1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,), MODE_REPLACE: (1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,), MODE_SEARCH_DIRECTORY: (1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1,), MODE_REPLACE_DIRECTORY: (1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,), MODE_SEARCH_OPENED_FILES: (1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,), MODE_REPLACE_OPENED_FILES: (1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1,)} for i, widget in enumerate(widgets): widget.setVisible(visible[mode][i]) # Search next button text if mode == MODE_REPLACE: self.pbNext.setText('Next') else: self.pbNext.setText('Next↵') # Finaly show all with valid size self.show() # show before updating widgets and labels self._updateLabels() self._updateWidgets() def eventFilter(self, object_, event): """ Event filter for mode switch tool button Draws icons in the search and path lineEdits """ if event.type( ) == QEvent.Paint and object_ is self.tbCdUp: # draw CdUp button in search path QLineEdit toolButton = object_ lineEdit = self.cbPath.lineEdit() lineEdit.setContentsMargins(lineEdit.height(), 0, 0, 0) height = lineEdit.height() availableRect = QRect(0, 0, height, height) if toolButton.rect() != availableRect: toolButton.setGeometry(availableRect) painter = QPainter(toolButton) toolButton.icon().paint(painter, availableRect) return True elif event.type( ) == QEvent.KeyPress: # Tab and Shift+Tab in QLineEdits if event.key() == Qt.Key_Tab: self._moveFocus(1) return True elif event.key() == Qt.Key_Backtab: self._moveFocus(-1) return True return QFrame.eventFilter(self, object_, event) def _onReturnPressed(self): """Return or Enter pressed on widget. Search next or Replace next """ if self.pbReplace.isVisible(): self.pbReplace.click() elif self.pbNext.isVisible(): self.pbNext.click() elif self.pbSearch.isVisible(): self.pbSearch.click() elif self.pbSearchStop.isVisible(): self.pbSearchStop.click() def _onPathBackspace(self): """Ctrl+Backspace pressed on path. Remove 1 path level. Default behavior would be to remove one word on Linux or all on Windows """ path = self.cbPath.currentText() if path.endswith('/') or \ path.endswith('\\'): path = path[:-1] head, tail = os.path.split(path) if head and \ head != path: if not head.endswith(os.sep): head += os.sep self.cbPath.lineEdit().setText(head) def _moveFocus(self, step): """Move focus forward or backward according to step. Standard Qt Keyboard focus algorithm doesn't allow circular navigation """ allFocusableWidgets = (self.cbSearch, self.cbReplace, self.cbPath, self.cbMask) visibleWidgets = [ widget for widget in allFocusableWidgets if widget.isVisible() ] try: focusedIndex = visibleWidgets.index(QApplication.focusWidget()) except ValueError: print('Invalid focused widget in Search Widget', file=sys.stderr) return nextFocusedIndex = (focusedIndex + step) % len(visibleWidgets) visibleWidgets[nextFocusedIndex].setFocus() visibleWidgets[nextFocusedIndex].lineEdit().selectAll() def _updateLabels(self): """Update 'Search' 'Replace' 'Path' labels geometry """ width = 0 if self.lSearch.isVisible(): width = max(width, self.lSearch.minimumSizeHint().width()) if self.lReplace.isVisible(): width = max(width, self.lReplace.minimumSizeHint().width()) if self.lPath.isVisible(): width = max(width, self.lPath.minimumSizeHint().width()) self.lSearch.setMinimumWidth(width) self.lReplace.setMinimumWidth(width) self.lPath.setMinimumWidth(width) def _updateWidgets(self): """Update geometry of widgets with buttons """ width = 0 if self.wSearchRight.isVisible(): width = max(width, self.wSearchRight.minimumSizeHint().width()) if self.wReplaceRight.isVisible(): width = max(width, self.wReplaceRight.minimumSizeHint().width()) if self.wPathRight.isVisible(): width = max(width, self.wPathRight.minimumSizeHint().width()) self.wSearchRight.setMinimumWidth(width) self.wReplaceRight.setMinimumWidth(width) self.wPathRight.setMinimumWidth(width) def updateComboBoxes(self): """Update comboboxes with last used texts """ searchText = self.cbSearch.currentText() replaceText = self.cbReplace.currentText() maskText = self.cbMask.currentText() # search if searchText: index = self.cbSearch.findText(searchText) if index == -1: self.cbSearch.addItem(searchText) # replace if replaceText: index = self.cbReplace.findText(replaceText) if index == -1: self.cbReplace.addItem(replaceText) # mask if maskText: index = self.cbMask.findText(maskText) if index == -1: self.cbMask.addItem(maskText) def _searchPatternTextAndFlags(self): """Get search pattern and flags """ pattern = self.cbSearch.currentText() pattern = pattern.replace( '\u2029', '\n') # replace unicode paragraph separator with habitual \n if not self.cbRegularExpression.checkState() == Qt.Checked: pattern = re.escape(pattern) if self.cbWholeWord.checkState() == Qt.Checked: pattern = r'\b' + pattern + r'\b' flags = 0 if not self.cbCaseSensitive.checkState() == Qt.Checked: flags = re.IGNORECASE return pattern, flags def getRegExp(self): """Read search parameters from controls and present it as a regular expression """ pattern, flags = self._searchPatternTextAndFlags() return re.compile(pattern, flags) def isSearchRegExpValid(self): """Try to compile search pattern to check if it is valid Returns bool result and text error """ pattern, flags = self._searchPatternTextAndFlags() try: re.compile(pattern, flags) except re.error as ex: return False, str(ex) return True, None def _getSearchMask(self): """Get search mask as list of patterns """ mask = [s.strip() for s in self.cbMask.currentText().split(' ')] # remove empty mask = [_f for _f in mask if _f] return mask def setState(self, state): """Change line edit color according to search result """ widget = self.cbSearch.lineEdit() color = { SearchWidget.Normal: QApplication.instance().palette().color(QPalette.Base), SearchWidget.Good: QColor(Qt.green), SearchWidget.Bad: QColor(Qt.red), SearchWidget.Incorrect: QColor(Qt.darkYellow) } stateColor = color[state] if state != SearchWidget.Normal: stateColor.setAlpha(100) pal = widget.palette() pal.setColor(widget.backgroundRole(), stateColor) widget.setPalette(pal) def setSearchInProgress(self, inProgress): """Search thread started or stopped """ self.pbSearchStop.setVisible(inProgress) self.pbSearch.setVisible(not inProgress) self._updateWidgets() self._progress.setVisible(inProgress) def onSearchProgressChanged(self, value, total): """Signal from the thread, progress changed """ self._progress.setValue(value) self._progress.setMaximum(total) def setReplaceInProgress(self, inProgress): """Replace thread started or stopped """ self.pbReplaceCheckedStop.setVisible(inProgress) self.pbReplaceChecked.setVisible(not inProgress) self._updateWidgets() def setSearchInFileActionsEnabled(self, enabled): """Set enabled state for Next, Prev, Replace, ReplaceAll """ for button in (self.pbNext, self.pbPrevious, self.pbReplace, self.pbReplaceAll): button.setEnabled(enabled) def _onSearchRegExpChanged(self): """User edited search text or checked/unchecked checkboxes """ valid, error = self.isSearchRegExpValid() if valid: self.setState(self.Normal) core.mainWindow().statusBar().clearMessage() self.pbSearch.setEnabled(len(self.getRegExp().pattern) > 0) else: core.mainWindow().statusBar().showMessage(error, 3000) self.setState(self.Incorrect) self.pbSearch.setEnabled(False) self.searchRegExpChanged.emit(re.compile('')) return self.searchRegExpChanged.emit(self.getRegExp()) def _onCdUpPressed(self): """User pressed "Up" button, need to remove one level from search path """ text = self.cbPath.currentText() if not os.path.exists(text): return editText = os.path.normpath(os.path.join(text, os.path.pardir)) self.cbPath.setEditText(editText) def on_pbSearch_pressed(self): """Handler of click on "Search" button (for search in directory) """ self.setState(SearchWidget.Normal) self.searchInDirectoryStartPressed.emit(self.getRegExp(), self._getSearchMask(), self.cbPath.currentText()) def on_pbReplace_pressed(self): """Handler of click on "Replace" (in file) button """ self.replaceFileOne.emit(self.cbReplace.currentText()) def on_pbReplaceAll_pressed(self): """Handler of click on "Replace all" (in file) button """ self.replaceFileAll.emit(self.cbReplace.currentText()) def on_pbReplaceChecked_pressed(self): """Handler of click on "Replace checked" (in directory) button """ self.replaceCheckedStartPressed.emit(self.cbReplace.currentText()) def on_pbBrowse_pressed(self): """Handler of click on "Browse" button. Explores FS for search directory path """ path = QFileDialog.getExistingDirectory(self, self.tr("Search path"), self.cbPath.currentText()) if path: self.cbPath.setEditText(path)