def comment_toggle(self): """ Toggles commenting out selected lines, or lines with cursor. """ blocks = self.get_selected_blocks() # iterate through lines in doc commenting or uncommenting # based on whether everything is commented or not commentAllOut = any([ not str(block.text()).lstrip().startswith('#') for block in blocks ]) if commentAllOut: for block in blocks: cursor = QtGui.QTextCursor(block) cursor.select(QtGui.QTextCursor.LineUnderCursor) selectedText = cursor.selectedText() right_split = len(selectedText.lstrip()) count = len(selectedText) split_index = count - right_split split_text = selectedText[split_index:] newText = ' ' * split_index + '#' + split_text cursor.insertText(newText) else: for block in blocks: cursor = QtGui.QTextCursor(block) cursor.select(QtGui.QTextCursor.LineUnderCursor) selectedText = cursor.selectedText() newText = str(selectedText).replace('#', '', 1) cursor.insertText(newText)
def lineNumberAreaPaintEvent(self, event): mypainter = QtGui.QPainter(self) block = self.editor.firstVisibleBlock() blockNumber = block.blockNumber() blockGeo = self.editor.blockBoundingGeometry(block) top = blockGeo.translated(self.editor.contentOffset()).top() bottom = top + self.editor.blockBoundingRect(block).height() p = self.editor.textCursor().position() doc = self.editor.document() current_block = doc.findBlock(p).blockNumber() height = self.editor.fontMetrics().height() while block.isValid() and (top <= event.rect().bottom()): if not block.isVisible(): continue if block.isVisible() and (bottom >= event.rect().top()): number = str(blockNumber + 1) colour = QtCore.Qt.darkGray font = self.font() if blockNumber == current_block: colour = QtCore.Qt.yellow font = QtGui.QFont(font) font.setBold(True) mypainter.setFont(font) mypainter.setPen(colour) mypainter.drawText(0, top, self.width(), height, QtCore.Qt.AlignRight, number) block = block.next() top = bottom bottom = top + self.editor.blockBoundingRect(block).height() blockNumber += 1
def __init__(self, shortcuthandler): super(ShortcutEditor, self).__init__() self.shortcuthandler = shortcuthandler self.shortcut_dict = shortcuthandler.shortcut_dict model = QtGui.QStandardItemModel() self.setModel(model) root = model.invisibleRootItem() model.setHorizontalHeaderLabels(['Shortcut', 'Description']) for item in self.shortcut_dict.items(): row = [QtGui.QStandardItem(val) for val in item] root.appendRow(row) self.header().setStretchLastSection(False) rtc = QtWidgets.QHeaderView.ResizeToContents try: self.header().setResizeMode(rtc) except AttributeError: # 'PySide2.QtWidgets.QHeaderView' object has no attribute 'setResizeMode' # TODO: Find compatible way to resize header. pass self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) self.setUniformRowHeights(True) self.resize(500, 400)
def update_icon(self, tab_index=None, size=(10, 10)): """ Represent the document's save state by setting an icon on the tab. """ if tab_index is None: tab_index = self.tabs.currentIndex() px = QtGui.QPixmap(*size) ico = QtGui.QIcon(px) self.tabs.setTabIcon(tab_index, ico)
def add_rows(self, rows): root = self.invisibleRootItem() for name, shortcut, about, action in rows: name_item = QtGui.QStandardItem(name) shortcut_item = QtGui.QStandardItem(shortcut) shortcut_item.setData(action, ACTION_ROLE) about = self.single_line_description(about) # print(about) about_item = QtGui.QStandardItem(about) # about_item.setData(about, QtCore.Qt.DecorationRole) row = [name_item, shortcut_item, about_item] root.appendRow(row)
def format(self, rgb, style=''): """ Return a QtGui.QTextCharFormat with the given attributes. """ color = QtGui.QColor(*rgb) textFormat = QtGui.QTextCharFormat() textFormat.setForeground(color) if 'bold' in style: textFormat.setFontWeight(QtGui.QFont.Bold) if 'italic' in style: textFormat.setFontItalic(True) return textFormat
def key_to_sequence(key): """ Convert the given QtCore.Qt.Key type to a QKeySequence including currently held modifiers. The only downside to this being that, for keys that require shift to be held, the sequence Shift+Key will be returned. """ QT = QtCore.Qt modifier_map = { QT.Key_Control: QT.ControlModifier, QT.Key_Shift: QT.ShiftModifier, QT.Key_Alt: QT.AltModifier, QT.Key_Meta: QT.MetaModifier, } app = QtWidgets.QApplication held = app.keyboardModifiers() combo = 0 for mod in modifier_map.values(): if held & mod == mod: combo |= mod combo |= key combo = QtGui.QKeySequence(combo) return combo
def test_app(qtbot): app = qt_api.QApplication.instance() # add the package path to sys.path FOLDER = os.path.dirname(__file__) PACKAGE_PATH = os.path.dirname(FOLDER) # set the application icon ICON_PATH = os.path.join(PACKAGE_PATH, 'icons', 'PythonEditor.png') icon = QtGui.QIcon(ICON_PATH) app.setWindowIcon(icon) # set style (makes palette work on linux) # Plastique isn't available on Windows, so try multiple styles. styles = QtWidgets.QStyleFactory.keys() for style_name in ['Plastique', 'Fusion']: if style_name not in styles: continue print('Setting style to:', style_name) style = QtWidgets.QStyleFactory.create(style_name) QtWidgets.QApplication.setStyle(style) break app.setPalette(nukepalette.getNukePalette()) _ide = ide.IDE()
def __init__(self): super(VisualDebug, self).__init__() self.layout = QtWidgets.QGridLayout(self) self.setMinimumWidth(900) self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) self.treeview = WidgetTreeView() self.treemodel = QtGui.QStandardItemModel() self.treeview.setModel(self.treemodel) self.treeview.setUniformRowHeights(True) self.layout.addWidget(self.treeview) self.treemodel.setHorizontalHeaderLabels([ 'metaObject className', 'objectName', 'windowTitle', 'text', 'title', '__repr__', ]) self.treeview.header().setStretchLastSection(False) mode = QtWidgets.QHeaderView.ResizeToContents try: self.treeview.header().setResizeMode(mode) except AttributeError: # setResizeMode not supported in PyQt pass rootItem = self.treemodel.invisibleRootItem() qApp = QtWidgets.QApplication.instance() for w in qApp.topLevelWidgets(): # extra stuff self.recurseWidgets(w, rootItem)
def __init__(self, handle_shortcuts=True, uid=None, init_features=True): super(Editor, self).__init__() self.setObjectName('Editor') self.setAcceptDrops(True) font = QtGui.QFont(DEFAULT_FONT) font.setPointSize(10) self.setFont(font) self.setMouseTracking(True) self.setStyleSheet(""" QToolTip { color: #F6F6F6; background-color: rgb(45, 42, 46); } """) self.shortcut_overrode_keyevent = False if uid is None: uid = str(uuid.uuid4()) self._uuid = uid self._changed = False self.wait_for_autocomplete = False self._handle_shortcuts = handle_shortcuts self._features_initialised = False self.emit_text_changed = True self.textChanged.connect(self._handle_textChanged) linenumberarea.LineNumberArea(self) if init_features: self.init_features()
def __init__(self, editor=None, tabeditor=None, terminal=None): super(ShortcutEditor, self).__init__() self.setWindowTitle('Shortcuts') model = QtGui.QStandardItemModel() self.setModel(model) root = model.invisibleRootItem() model.setHorizontalHeaderLabels(['Description', 'Shortcut', 'About']) self.header().setStretchLastSection(False) rtc = QtWidgets.QHeaderView.ResizeToContents try: self.header().setResizeMode(rtc) except AttributeError: # for PySide2: self.header().setSectionResizeMode(rtc) self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) self.setUniformRowHeights(True) self.resize(800, 600) widgets = [] if editor is not None: widgets.append(editor) if terminal is not None: widgets.append(terminal) if tabeditor is not None: widgets.append(tabeditor) for widget in widgets: for action in widget.actions(): name = action.text() # TODO: put shortcut in a keycatcher widget. shortcut = action.shortcut().toString() # if not shortcut.strip(): # continue if 'Placeholder' in action.toolTip(): continue about = ' '.join([ line.strip() for line in action.toolTip().splitlines() ]).strip() row = [ QtGui.QStandardItem(val) for val in [name, shortcut, about] ] root.appendRow(row)
def indent(self): """ Indent Selected Text """ blocks = self.get_selected_blocks() for block in blocks: cursor = QtGui.QTextCursor(block) cursor.movePosition(QtGui.QTextCursor.StartOfLine) cursor.insertText(' ')
def recursion(widget, parent): for child in widget.children(): infoList = self.getObjectInfo(child) items = [QtGui.QStandardItem(info) for info in infoList] parent.appendRow(items) childItem = items[0] childItem.setData(child, QtCore.Qt.UserRole) # childItem = QtGui.QStandardItem(', '.join(info)) recursion(child, childItem)
def mousePressEvent(self, event): if event.button() == QtCore.Qt.LeftButton: super(FileTree, self).mousePressEvent(event) if event.button() == QtCore.Qt.RightButton: menu = QtWidgets.QMenu() menu.addAction('New', 'print "does nothing"') menu.addAction('Delete', 'print "does nothing"') cursor = QtGui.QCursor() pos = cursor.pos() menu.exec_(pos)
def __init__(self): super(Terminal, self).__init__() self.setObjectName('Terminal') self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) self.setReadOnly(True) self.setup() self.destroyed.connect(self.stop) font = QtGui.QFont(DEFAULT_FONT) font.setPointSize(10) self.setFont(font)
def copy_tab_file_path(self, index): """ Copy the current tab's file path (if it has one) to the clipboard. """ data = self.tabData(index) path = data.get('path') if path is None or not path.strip(): print('No file path for "{0}".'.format(data['name'])) return clipboard = QtGui.QClipboard() clipboard.setText(path) print('Path copied to clipboard:') print(path)
def copy_block_or_selection(self): """ If there's no text selected, copy the current block. """ textCursor = self.editor.textCursor() selection = textCursor.selection() text = selection.toPlainText() if not text: textCursor.select(QtGui.QTextCursor.BlockUnderCursor) selection = textCursor.selection() text = selection.toPlainText() QtGui.QClipboard().setText(text)
def unindent(self): """ Unindent Selected Text TODO: Maintain original selection and cursor position. """ blocks = self.get_selected_blocks(ignoreEmpty=False) for block in blocks: cursor = QtGui.QTextCursor(block) cursor.select(QtGui.QTextCursor.LineUnderCursor) lineText = cursor.selectedText() if lineText.startswith(' '): newText = str(lineText[:4]).replace(' ', '') + lineText[4:] cursor.insertText(newText)
def cut_line(self): """ If no text selected, cut whole current line to clipboard. """ textCursor = self.editor.textCursor() if textCursor.hasSelection(): return textCursor.select(QtGui.QTextCursor.LineUnderCursor) text = textCursor.selectedText() textCursor.insertText('') QtGui.QClipboard().setText(text)
def keyPressEvent(self, event): event.accept() key = event.key() if key in [ QtCore.Qt.Key_Control, QtCore.Qt.Key_Alt, QtCore.Qt.Key_Meta, QtCore.Qt.Key_Shift ]: key = int(event.modifiers()) else: key += int(event.modifiers()) keyseq = QtGui.QKeySequence(key) text = keyseq.toString() self.setText(text)
def show_tab_menu(self): """ Show a list of tabs and go to the tab clicked. """ menu = QtWidgets.QMenu() from functools import partial for i in range(self.count()): tab_name = self.tabText(i) if not tab_name.strip(): button = self.tabBar().tabButton(i, QtWidgets.QTabBar.LeftSide) if not isinstance(button, TabButton): continue tab_name = button.text() action = partial(self.setCurrentIndex, i) menu.addAction(tab_name, action) menu.exec_(QtGui.QCursor().pos())
def add_action(action, widget, shortcut, func): """ Add action to widget with a shortcut that triggers the given function. :action: QtWidgets.QAction :widget: QtWidgets.QWidget :shortcut: str (e.g. 'Ctrl+S') or Qt Key :func: a callable that gets executed when triggering the action. """ key_seq = QtGui.QKeySequence(shortcut) a.setShortcut(key_seq) a.setShortcutContext(QtCore.Qt.WidgetShortcut) a.triggered.connect(func) widget.addAction(a)
def load_globals(self): """ Load globals into Tree """ self.treemodel.removeRows(0, self.treemodel.rowCount()) self.names = __dict__.copy() rootItem = self.treemodel.invisibleRootItem() for key, value in __dict__.iteritems(): # if hasattr(value, '__repr__'): try: items = [ QtGui.QStandardItem(i.__repr__()) for i in [key, value] ] rootItem.appendRow(items) except Exception, e: print(key, value, e)
def register_shortcuts(self, action_dict=None): """ Use the shortcut register to apply shortcuts to actions that exist on the widget. """ if action_dict is None: a = actions.load_actions_from_json action_dict = a() widgacts = action_dict.items() for widget_name, widget_actions in widgacts: if not hasattr(self, widget_name): continue widget = getattr(self, widget_name) if widget is None: continue acts = widget_actions.items() for action_name, attributes in acts: shortcuts = attributes['Shortcuts'] if len(shortcuts) == 0: continue for action in widget.actions(): if action.text() != action_name: continue break else: continue key_seqs = [] for shortcut in shortcuts: key_seq = QtGui.QKeySequence(shortcut) # convert to unicode again # to make sure the format # stays the same s = key_seq.toString() self.shortcut_dict[s] = action key_seqs.append(key_seq) action.setShortcuts(key_seqs) action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
def mouseReleaseEvent(self, event): self.tab_pressed = False i = self.tabAt(event.pos()) if event.button() == QtCore.Qt.LeftButton: if i == -1: i = self.currentIndex() if (i != self.start_move_index): self.tab_repositioned_signal.emit(i, self.start_move_index) self.handle_close_button_display(event) elif event.button() == QtCore.Qt.RightButton: menu = QtWidgets.QMenu() rename = partial(self._show_name_edit, i) menu.addAction('Rename', rename) move_to_first = partial(self.move_to_first, i) menu.addAction('Move Tab to First', move_to_first) move_to_last = partial(self.move_to_last, i) menu.addAction('Move Tab to Last', move_to_last) close_tab_func = partial(self.removeTab, i) menu.addAction('Close Tab', close_tab_func) copy_file_path = partial(self.copy_tab_file_path, i) menu.addAction('Copy File Path', copy_file_path) # Other ideas (TODO) """ menu.addAction('Close Other Tabs', ) menu.addAction('Close Tabs to Right', ) menu.addAction('Close Tabs to Left', ) menu.addAction('Pin Tab', ) """ menu.exec_(QtGui.QCursor().pos()) elif event.button() == QtCore.Qt.MiddleButton: if i != -1: self.removeTab(i) return super(Tabs, self).mouseReleaseEvent(event)
def recurseWidgets(self, widget, parent): # TODO: later try and turn this into a generator pushed by a QTimer # treeInfo = {} def recursion(widget, parent): for child in widget.children(): infoList = self.getObjectInfo(child) items = [QtGui.QStandardItem(info) for info in infoList] parent.appendRow(items) childItem = items[0] childItem.setData(child, QtCore.Qt.UserRole) # childItem = QtGui.QStandardItem(', '.join(info)) recursion(child, childItem) infoList = self.getObjectInfo(widget) items = [QtGui.QStandardItem(info) for info in infoList] # parentItem = QtGui.QStandardItem(', '.join(info)) #later setData adding widget object parent.appendRow(items) firstParent = items[0] firstParent.setData(widget, QtCore.Qt.UserRole) # parent.appendRow(parentItem) recursion(widget, firstParent)
def show_tab_menu(self): """ Show a list of tabs and go to the tab clicked. """ menu = QtWidgets.QMenu() current_index = self.tabs.currentIndex() from functools import partial for i in range(self.tabs.count()): tab_name = self.tabs.tabText(i) if not tab_name.strip(): continue func = partial(self.tabs.setCurrentIndex, i) action = menu.addAction(tab_name, func) if i == current_index: font = action.font() font.setBold(True) font.setUnderline(True) action.setFont(font) menu.setActiveAction(action) menu.exec_(QtGui.QCursor().pos())
def main(): app = QtWidgets.QApplication.instance() if not app: app = QtWidgets.QApplication(sys.argv) for widget in app.allWidgets(): if widget.objectName() == 'IDE': widget.close() PDF = 'PYTHONEDITOR_DEFAULT_FONT' fontbase = QtGui.QFontDatabase() current_folder = os.path.dirname(__file__) user_font_file = os.path.join(current_folder, 'scripts', 'fonts', 'DejaVu Sans Mono for Powerline.ttf') fontbase.addApplicationFont(user_font_file) os.environ[PDF] = 'DejaVu Sans Mono for Powerline' _ide = ide.IDE() _ide.setParent(app.activeWindow()) _ide.setWindowFlags(QtCore.Qt.Window) _ide.setPalette(ui_palette.get_palette_style()) # Plastique isn't available on Windows, so try multiple styles. styles = QtWidgets.QStyleFactory.keys() style_found = False for style_name in ['Plastique', 'Fusion']: if style_name in styles: print('Setting style to:', style_name) style_found = True break if style_found: style = QtWidgets.QStyleFactory.create(style_name) _ide.setStyle(style) print('PythonEditor import time: %.04f seconds' % (time.time() - start)) #_ide.showMaximized() _ide.show() if app.applicationName() in ['python', 'mayapy', 'UE4Editor']: sys.exit(app.exec_())
def set_shortcut(self, index, value, role=QtCore.Qt.DisplayRole): if (index.column() != 1) or (role != QtCore.Qt.EditRole): # not a shortcut return self.setData(index, value, role) # unassign shortcut if it was previously assigned if value in self._shortcut_handler.shortcut_dict.keys(): old_action = self._shortcut_handler.shortcut_dict[value] old_action.setShortcut(QtGui.QKeySequence()) # remove it from the shortcuts dict and # add it to the unassigned list del self._shortcut_handler.shortcut_dict[value] if old_action not in self._shortcut_handler.unassigned: self._shortcut_handler.unassigned.append(old_action) print('Removed shortcut %r from %r' % (value, old_action.text())) new_action = index.data(ACTION_ROLE) # remove any existing shortcuts associated with this action for shortcut in new_action.shortcuts(): s = shortcut.toString() if s in self._shortcut_handler.shortcut_dict: del self._shortcut_handler.shortcut_dict[s] key_seq = QtGui.QKeySequence.fromString(value) new_action.setShortcut(key_seq) # set the shortcut on the handler, so it'll be caught by the eventFilter. self._shortcut_handler.shortcut_dict[value] = new_action # remove action from the unassigned list if new_action in self._shortcut_handler.unassigned: self._shortcut_handler.unassigned.remove(new_action) print('Set shortcut for %r to %r' % (new_action.text(), key_seq.toString()))
def __init__(self): super(ObjectInspector, self).__init__() self.layout = QtWidgets.QGridLayout(self) self.setMinimumWidth(900) self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) self.treeview = QtWidgets.QTreeView() self.treemodel = QtGui.QStandardItemModel() self.treeview.setModel(self.treemodel) self.treeview.setUniformRowHeights(True) self.layout.addWidget(self.treeview) self.treemodel.setHorizontalHeaderLabels(['object name', 'object']) self.treeview.header().setStretchLastSection(False) mode = QtWidgets.QHeaderView.ResizeToContents self.treeview.header().setResizeMode(mode) self.load_globals() self.start_timer()