def draw_bg_rect(self, painter: QPainter, rect: QRect, color: int): painter.setPen(Qt.NoPen) brush = QBrush(QColor(color)) painter.setBrush(brush) painter.drawRect(rect) # draw line at bottom of the rect painter.setPen(QColor(self.invert_color(color, bw=True))) painter.drawLine(rect.x(), rect.bottom(), rect.right(), rect.bottom())
def paint_wide_item(self, painter, option, index): painter.save() font = self.font fm = self.fm email_field, subject, snippet, date, unread = self.item_data(index) # If email is unread paint certain parts bold, if not then just set font_bold and fm_bold # to font and fm to avoid unnecessary checks later. if unread is False: font_bold = font fm_bold = fm else: font_bold = self.font_bold fm_bold = self.fm_bold option_rect = option.rect option_rect.setX(10) option_rect.setY(option_rect.y() + 10) row_height = (option_rect.height()) // 3 option_rect.setWidth(option_rect.width() - 10) viewport_width = option_rect.width() email_field_rect = QRect(*option_rect.getRect()) email_field_rect.setHeight(row_height) email_field_width = viewport_width // 2 email_field_rect.setWidth(email_field_width) #email_field = fm_bold.elidedText(email_field, Qt.ElideRigth, email_field_width) painter.setFont(font_bold) painter.drawText(email_field_rect, 0, email_field) date_rect = QRect(*option_rect.getRect()) date_rect.setHeight(row_height) date_rect.setLeft(email_field_rect.right()) date_width = viewport_width // 2 date_rect.setWidth(date_width) #date = fm_bold.elidedText(date, Qt.ElideLeft, date_width) painter.drawText(date_rect, Qt.AlignRight, date) subject_rect = QRect(*option_rect.getRect()) subject_rect.setTop(email_field_rect.bottom()) subject_rect.setHeight(row_height) subject_width = min(fm_bold.horizontalAdvance(subject), viewport_width) subject = fm_bold.elidedText(subject, Qt.ElideRight, subject_width) painter.drawText(subject_rect, 0, subject) snippet_rect = QRect(*option_rect.getRect()) snippet_rect.setTop(subject_rect.bottom()) snippet_rect.setHeight(row_height) snippet_rect.setWidth(viewport_width) snippet_width = min(fm.horizontalAdvance(snippet), viewport_width) snippet = fm.elidedText(snippet, Qt.ElideRight, snippet_width) painter.setFont(font) painter.drawText(snippet_rect, 0, snippet) painter.restore()
def to_image_rect(self, rect: QRect) -> QRect: rect = QRect(rect) if rect.top() > rect.bottom(): _top, _bottom = rect.top(), rect.bottom() rect.setBottom(_top), rect.setTop(_bottom) if rect.left() > rect.right(): _left, _right = rect.left(), rect.right() rect.setLeft(_right) rect.setRight(_left) return QRect( self.to_image_coord(rect.topLeft()), self.to_image_coord(rect.bottomRight()) )
def applyMargin(rect, margin): result = QRect(rect) result.setLeft(result.left()+margin) result.setRight(result.right()-margin) result.setTop(result.top()+margin) result.setBottom(result.bottom()-margin) return result
def __autoScrollAdvance(self): """Advance the auto scroll """ pos = QCursor.pos() pos = self.mapFromGlobal(pos) margin = self.__autoScrollMargin vvalue = self.verticalScrollBar().value() hvalue = self.horizontalScrollBar().value() vrect = QRect(0, 0, self.width(), self.height()) # What should be the speed advance = 10 # We only do auto scroll if the mouse is inside the view. if vrect.contains(pos): if pos.x() < vrect.left() + margin: self.horizontalScrollBar().setValue(hvalue - advance) if pos.y() < vrect.top() + margin: self.verticalScrollBar().setValue(vvalue - advance) if pos.x() > vrect.right() - margin: self.horizontalScrollBar().setValue(hvalue + advance) if pos.y() > vrect.bottom() - margin: self.verticalScrollBar().setValue(vvalue + advance) if self.verticalScrollBar().value() == vvalue and \ self.horizontalScrollBar().value() == hvalue: self.__stopAutoScroll() else: self.__stopAutoScroll() log.debug("Auto scroll advance")
def paint_real_time_tips(self, qp: QPainter): if not self.__enable_real_time_tips or self.__l_pressing: return qp.drawLine(0, self.__mouse_on_coordinate.y(), self.__width, self.__mouse_on_coordinate.y()) qp.drawLine(self.__mouse_on_coordinate.x(), 0, self.__mouse_on_coordinate.x(), self.__height) tip_text = self.format_real_time_tip() fm = QFontMetrics(self.__tip_font) text_width = fm.width(tip_text) text_height = fm.height() tip_area = QRect(self.__mouse_on_coordinate, QSize(text_width, text_height)) tip_area.setTop(tip_area.top() - fm.height()) tip_area.setBottom(tip_area.bottom() - fm.height()) if tip_area.right() > self.__axis_width: tip_area.setLeft(tip_area.left() - text_width) tip_area.setRight(tip_area.right() - text_width) qp.setFont(self.__tip_font) qp.setBrush(QColor(36, 169, 225)) qp.drawRect(tip_area) qp.drawText(tip_area, Qt.AlignLeft, tip_text)
def saveScreenshot(self, clipboard=False, fileName='screenshot.png', picType='png'): fullWindow = QRect(0, 0, self.width() - 1, self.height() - 1) selected = QRect(self.selectedArea) if selected.left() < 0: selected.setLeft(0) if selected.right() >= self.width(): selected.setRight(self.width() - 1) if selected.top() < 0: selected.setTop(0) if selected.bottom() >= self.height(): selected.setBottom(self.height() - 1) source = (fullWindow & selected) source.setTopLeft( QPoint(source.topLeft().x() * self.scale, source.topLeft().y() * self.scale)) source.setBottomRight( QPoint(source.bottomRight().x() * self.scale, source.bottomRight().y() * self.scale)) image = self.screenPixel.copy(source) image.setDevicePixelRatio(1) if clipboard: QGuiApplication.clipboard().setImage(QImage(image), QClipboard.Clipboard) else: image.save(fileName, picType, 10) self.target_img = image self.screen_shot_grabed.emit(QImage(image))
def draw_hex_and_ascii(self, painter: QPainter): scroll_value = self.verticalScrollBar().value() first_index = scroll_value * self.bytes_per_row last_index = min( self.max_data_index + 1, (scroll_value + self.visible_rows()) * self.bytes_per_row, ) for i, byte_index in enumerate(range(first_index, last_index)): if byte_index in self.data: bg_color = self.data[byte_index]["color"] text_color = self.invert_color(bg_color, bw=True) byte_hex = self.int_to_hex( self.data[byte_index]["value"]).upper() byte_ascii = chr(self.data[byte_index]["value"]) if byte_ascii not in string.printable: byte_ascii = "." start_block = False if "start_block" in self.data[byte_index]: start_block = True y = self.first_row_y + int( i / self.bytes_per_row) * self.row_height # draw hex x = self.hex_table_x + (i % self.bytes_per_row) * self.byte_width rect = QRect(x, y, self.byte_width, self.row_height) self.draw_bg_rect(painter, rect, bg_color) self.draw_text(painter, byte_hex, x + 6, y + 15, text_color) if start_block: painter.drawLine(rect.x(), rect.top() + 1, rect.x(), rect.bottom()) # draw ascii x = self.ascii_table_x + ( i % self.bytes_per_row) * self.ascii_width rect = QRect(x, y, self.ascii_width, self.row_height) self.draw_bg_rect(painter, rect, bg_color) self.draw_text(painter, byte_ascii, x + 3, y + 15, text_color) if start_block: painter.drawLine(rect.x(), rect.top() + 1, rect.x(), rect.bottom())
def popup(self, pos=None, searchText=""): """ Popup the menu at `pos` (in screen coordinates). 'Search' text field is initialized with `searchText` if provided. """ if pos is None: pos = QPoint() self.__clearCurrentItems() self.__search.setText(searchText) self.__suggestPage.setFilterFixedString(searchText) self.ensurePolished() if self.testAttribute(Qt.WA_Resized) and self.sizeGripEnabled(): size = self.size() else: size = self.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) self.setGeometry(geom) self.show() if searchText: self.setFocusProxy(self.__search) else: self.setFocusProxy(None)
def merge(self, pos, layer): # Determine the overlapping area area = QRect(pos, QSize(layer.width(), layer.height())) area &= QRect(0, 0, self.width(), self.height()) for y in range(area.top(), area.bottom() + 1): for x in range(area.left(), area.right() + 1): cell = layer.cellAt(x - pos.x(), y - pos.y()) if (not cell.isEmpty()): self.setCell(x, y, cell)
def merge(self, pos, layer): # Determine the overlapping area area = QRect(pos, QSize(layer.width(), layer.height())) area &= QRect(0, 0, self.width(), self.height()) for y in range(area.top(), area.bottom()+1): for x in range(area.left(), area.right()+1): cell = layer.cellAt(x - pos.x(), y - pos.y()) if (not cell.isEmpty()): self.setCell(x, y, cell)
def _create_qrect_with_border(source: QRect, border: int) -> QRect: """ Takes a QRect item, copies it and adds a border, by shrinking the input by border pixels on each side. In other words: It performs a centered scaling, by reducing the input QRect size by 2*border pixels. """ target = QRect(source) target.setRight(target.right() - border) target.setLeft(target.left() + border) target.setTop(target.top() + border) target.setBottom(target.bottom() - border) return target
def adjust_area(self, area: QRect) -> QRect: if self.__layout == LAYOUT_VERTICAL: if area.top() < self.__longitudinal_since: area.setTop(self.__longitudinal_since) if area.bottom() > self.__longitudinal_until: area.setBottom(self.__longitudinal_until) elif self.__layout == LAYOUT_HORIZON: if area.left() < self.__longitudinal_since: area.setLeft(self.__longitudinal_since) if area.right() > self.__longitudinal_until: area.setRight(self.__longitudinal_until) return area
def popup_position_from_source(popup, source, orientation=Qt.Vertical): popup.ensurePolished() source.ensurePolished() if popup.testAttribute(Qt.WA_Resized): size = popup.size() else: size = popup.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(source) source_rect = QRect(source.mapToGlobal(QPoint(0, 0)), source.size()) if orientation == Qt.Vertical: if source_rect.right() + size.width() < screen_geom.right(): x = source_rect.right() else: x = source_rect.left() - size.width() # bottom overflow dy = source_rect.top() + size.height() - screen_geom.bottom() if dy < 0: y = source_rect.top() else: y = source_rect.top() - dy else: # right overflow dx = source_rect.left() + size.width() - screen_geom.right() if dx < 0: x = source_rect.left() else: x = source_rect.left() - dx if source_rect.bottom() + size.height() < screen_geom.bottom(): y = source_rect.bottom() else: y = source_rect.top() - size.height() return QPoint(x, y)
class TilePainter(IPainter): def __init__(self, osm: "osm.Receiver", screen: "QRect"): super().__init__() self.tile_size = TILE_SIZE self.osm = osm self.osm.connect_handle_data(self.handle_network_data) self.zoom = 14 self.latitude = 56.86738408969649 self.longitude = 60.532554388046265 self.set_map_rect(screen) self.download() def draw_tile(self, painter: "QPainter", tile: "QTile"): if tile.zoom == self.zoom: self.drawn.append(tile) target = QRect(tile.map_x, tile.map_y, TILE_SIZE, TILE_SIZE) painter.drawPixmap(target, self.osm.get_tile((tile.x, tile.y))) def draw(self, painter: "QPainter"): for x in range(self.map_rect.left(), self.map_rect.right()): for y in range(self.map_rect.top(), self.map_rect.bottom()): tile = QTile(Tile(x, y, self.zoom), (x - self.map_rect.left()) * TILE_SIZE, (y - self.map_rect.top()) * TILE_SIZE) self.draw_tile(painter, tile) def set_map_rect(self, rect: "QRect"): x, y = Translator.deg2num(self.latitude, self.longitude, self.zoom) width = rect.width() // TILE_SIZE + 2 height = rect.height() // TILE_SIZE + 2 self.map_rect = QRect(x, y, width, height) def handle_network_data(self, reply): self.osm.handle_network_data(reply) self.osm.purge_cache(self.map_rect) self.drawn = [ tile for tile in self.drawn if self.osm.exist_tile((tile.x, tile.y)) ] self.download() def download(self): self.drawn.clear() for x in range(self.map_rect.left(), self.map_rect.right()): for y in range(self.map_rect.top(), self.map_rect.bottom()): tile = Tile(x, y, self.zoom) if not self.osm.exist_tile((tile.x, tile.y)): self.osm.download_tile(tile) return
def adjustPosition(self, p): rect = self.rect() screen = QApplication.desktop().screenGeometry(self.getToolTipScreen()) if p.x() + rect.width() > screen.x() + screen.width(): # p.rx() -= 4 + rect.width() p.setX(p.x() - 4 + rect.width()) if p.y() + rect.height() > screen.y() + screen.height(): # p.ry() -= 24 + rect.height () p.setY(p.x() - 24 + rect.height()) if p.y() < screen.y(): p.setY(screen.y()) if p.x() + rect.width() > screen.x() + screen.width(): p.setX(screen.x() + screen.width() - rect.width()) if p.x() < screen.x(): p.setX(screen.x()) if p.y() + rect.height() > screen.y() + screen.height(): p.setY(screen.y() + screen.height() - rect.height()) futureRect = QRect(p.x(), p.y(), rect.width(), rect.height()) cursor = QCursor.pos() if futureRect.contains(cursor): offset = QPoint() diff = cursor.x() - futureRect.left() minDiff = diff offset = QPoint(diff + abs(self.cursorOffset.x()) + 1, 0) diff = futureRect.right() - cursor.x() if diff < minDiff: minDiff = diff offset = QPoint(-diff - abs(self.cursorOffset.x()) - 1, 0) diff = cursor.y() - futureRect.top() if diff < minDiff: minDiff = diff offset = QPoint(0, diff + abs(self.cursorOffset.y()) + 1) diff = futureRect.bottom() - cursor.y() if diff < minDiff: minDiff = diff offset = QPoint(0, -diff - abs(self.cursorOffset.y()) - 1) p += offset assert not QRect(p.x(), p.y(), rect.width(), rect.height()).contains(cursor) return p
def drawBackground(self, painter, rect): roomRect = QRect(rect.x() + (rect.width() - self.roomWidth) * .5, rect.y() + (rect.height() - self.roomHeight) * .5, self.roomWidth, self.roomHeight) gridWidth = roomRect.width() - (roomRect.width() % self.gridSize) gridHeight = roomRect.height() - (roomRect.height() % self.gridSize) left = int((self.roomWidth - gridWidth + 2 * roomRect.left()) * .5) top = int((self.roomHeight - gridHeight + 2 * roomRect.top()) * .5) painter.setPen(QPen(QColor("black"), 2, Qt.SolidLine)) if self.grid: for x in range(left, int(roomRect.right()), self.gridSize): for y in range(top, int(roomRect.bottom()), self.gridSize): painter.drawPoint(x, y) painter.drawRect(roomRect)
def paint(self, painter: QPainter, option: 'QStyleOptionViewItem', index: QModelIndex) -> None: """ Paint the playlist on the screen :param painter: Controls actual painting :param option: Options for painting :param index: Index of item """ playlist = index.model().at(index.row()) if not index.isValid(): return painter.save() # Save current state, before altering for custom painting painter.setRenderHints(QPainter.Antialiasing, True) painter.setRenderHints(QPainter.HighQualityAntialiasing, True) painter.setRenderHints(QPainter.SmoothPixmapTransform, True) playlist_pix: QPixmap = index.data(Qt.DecorationRole) # Tiled pixmap title_font = QApplication.font() title_font.setPixelSize(15) title_fm = QFontMetrics(title_font) icon_rect = QRect(option.rect.left() + PlaylistDelegate.pad_horizontal, option.rect.top(), PlaylistDelegate.icon_diameter, PlaylistDelegate.icon_diameter) title_rect = title_fm.boundingRect(option.rect.left() + PlaylistDelegate.pad_horizontal, icon_rect.bottom() + PlaylistDelegate.pad_vertical, icon_rect.width(), 0, Qt.AlignHCenter | Qt.AlignTop | Qt.TextWordWrap, playlist.name) # Draw icon painter.drawPixmap(icon_rect, playlist_pix) # Draw title painter.setFont(title_font) painter.setPen(Qt.white) painter.drawText(title_rect, Qt.AlignHCenter | Qt.AlignTop | Qt.TextWordWrap, playlist.name) painter.restore()
def paintEvent(self, event): painter = QPainter(self) margin = 25 pad = 10 ind = 50 cr = self.contentsRect() size = cr.size() boxWidth = (size.width() - 2 * margin - ind - 6 * pad) / 7 boxHeight = boxWidth / 1.618 date = datetime.date.today() prevMonth = date.month - 1 top = cr.top() + margin while True: if not date.weekday(): top += boxHeight + pad if prevMonth != date.month: top += boxHeight + pad rect = QRect(cr.left() + margin + ind + \ date.weekday() * (boxWidth + pad), top, boxWidth, boxHeight) if rect.bottom() > cr.bottom() - margin: break if prevMonth != date.month: monRect = QRect(cr.left() + margin, top, ind, boxHeight) painter.drawText(monRect, Qt.AlignCenter, date.strftime('%b')) elif not date.weekday(): monRect = QRect(cr.left() + margin, top, ind, boxHeight) painter.drawText(monRect, Qt.AlignCenter, date.strftime('%V')) if date in self.busyDays: color = QColor(200, 100, 100) elif date.weekday() > 4: color = QColor(0, 0, 120) else: color = QColor(60, 60, 180) painter.fillRect(rect, color) painter.drawText(rect, Qt.AlignCenter, str(date.day)) prevMonth = date.month date += datetime.timedelta(days=1)
def computeDiffRegion(self, other): ret = QRegion() dx = other.x() - self.mX dy = other.y() - self.mY r = QRect(0, 0, self.width(), self.height()) r &= QRect(dx, dy, other.width(), other.height()) for y in range(r.top(), r.bottom()+1): for x in range(r.left(), r.right()+1): if (self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): rangeStart = x while (x <= r.right() and self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): x += 1 rangeEnd = x ret += QRect(rangeStart, y, rangeEnd - rangeStart, 1) return ret
def paintEvent(self, event): par = self.parent() size = min(self.spinner_size, par.width(), par.height()) dot_count = 5 dot_size = int(size / dot_count) * 1.5 r = par.rect() spinner_rect = QRect(r.width() / 2 - size / 2, r.height() / 2 - size / 2, size, size) painter = QPainter() painter.begin(self) painter.setPen(QPen(Qt.NoPen)) for i in range(dot_count): if self.counter % dot_count == i: painter.setBrush(QBrush(QColor(0, 0, 0))) d_size = dot_size * 1.1 else: painter.setBrush(QBrush(QColor(200, 200, 200))) d_size = dot_size r = size / 2 - dot_size / 2 x = r * math.cos(2 * math.pi * i / dot_count) y = r * math.sin(2 * math.pi * i / dot_count) x_center = spinner_rect.left( ) + spinner_rect.width() / 2 - dot_size / 2 y_center = spinner_rect.top( ) + spinner_rect.height() / 2 - dot_size / 2 painter.drawEllipse(x_center + x, y_center + y, d_size, d_size) if self.message: painter.setPen(QPen(Qt.black)) if self.font_size: f = painter.font() f.setPointSize(self.font_size) painter.setFont(f) spinner_rect.setTop(spinner_rect.bottom() + 3) spinner_rect.setHeight(painter.fontMetrics().height() * 1.5) r = painter.boundingRect(spinner_rect, Qt.AlignHCenter | Qt.AlignTop, self.message) painter.drawText(r.bottomLeft(), self.message) painter.end()
def computeDiffRegion(self, other): ret = QRegion() dx = other.x() - self.mX dy = other.y() - self.mY r = QRect(0, 0, self.width(), self.height()) r &= QRect(dx, dy, other.width(), other.height()) for y in range(r.top(), r.bottom() + 1): for x in range(r.left(), r.right() + 1): if (self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): rangeStart = x while (x <= r.right() and self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): x += 1 rangeEnd = x ret += QRect(rangeStart, y, rangeEnd - rangeStart, 1) return ret
def __updateHandles(self): """ Private method to update the handles. """ r = QRect(self.__selection) s2 = self.__handleSize // 2 self.__TLHandle.moveTopLeft(r.topLeft()) self.__TRHandle.moveTopRight(r.topRight()) self.__BLHandle.moveBottomLeft(r.bottomLeft()) self.__BRHandle.moveBottomRight(r.bottomRight()) self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2)) self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y())) self.__RHandle.moveTopRight( QPoint(r.right(), r.y() + r.height() // 2 - s2)) self.__BHandle.moveBottomLeft( QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
def displayGraph(self, selection: QRect): reader = self.mediaPlayer.reader() if not reader: logging.error("Video not available") self.values = [] for frame_number in range(reader.num_frames): frame = reader.frame(frame_number) temperatures = frame.data if not selection.isEmpty(): temperatures = temperatures[ selection.top() : selection.bottom(), selection.left() : selection.right(), ] self.values.append(numpy.average(temperatures)) self.plot.setData(self.values) self.displayCurrentTemperature(self.mediaPlayer.position()) self.plotItem.getViewBox().autoRange(padding=0.11) self.plotItem.getViewBox().setRange(xRange=(-10, reader.num_frames * 1.12))
def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) roundedRect = QRect() radius = 6 roundedRect.setX(self.rect().x() + radius / 2) roundedRect.setY(self.rect().y() + radius / 2) roundedRect.setWidth(self.rect().width() - radius) roundedRect.setHeight(self.rect().height() - radius) palette = QPalette() rectColor = palette.color(QPalette.Window) painter.setBrush(QBrush(rectColor)) roundedRectPen = QPen(Qt.black) painter.setPen(roundedRectPen) painter.drawRoundedRect(roundedRect, radius, radius) closeButtonGeometry = self.closeButton.geometry() lineColor = palette.color(QPalette.Text) pen = QPen(lineColor) pen.setWidth(1) painter.setPen(pen) # horizontal line if hasattr(self, 'detailsButton'): detailsButtonGeometry = self.detailsButton.geometry() y = (closeButtonGeometry.bottom() + detailsButtonGeometry.top()) / 2 left = QPoint( min(closeButtonGeometry.left(), detailsButtonGeometry.left()), y) right = QPoint( max(closeButtonGeometry.right(), detailsButtonGeometry.right()) - 8, y) painter.drawLine(left, right) # vertical line # close button and details button have Preferred size policy x = closeButtonGeometry.left() - pen.width() top = QPoint(x, roundedRect.top() + roundedRectPen.width()) bottom = QPoint(x, roundedRect.bottom() - roundedRectPen.width()) painter.drawLine(top, bottom)
def paintEvent(self, event): p = QPainter(self) # Need this configuration to enable stylesheets for subclasses of QWidgets opt = QStyleOption() opt.initFrom(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self) # Set font font = QFont(p.font()) font.setFamily("Helvetica Neue") p.setFont(font) actionY = 0 for action in self.actionList: actionRect = QRect(0, actionY, self.actionWidth, self.actionHeight) if action.isChecked(): p.fillRect(actionRect, QColor(35, 35, 35)) #if action == mOverAction: # p.fillRect(actionRect, QColor(150, 150, 150)) # Draw text for button p.setPen(QColor(255, 255, 255)) size = p.fontMetrics().size(Qt.TextSingleLine, action.text()) actionTextRect = QRect( QPoint(actionRect.width() / 2 - size.width() / 2, actionRect.bottom() - size.height() - 5), size) p.drawText(actionTextRect, Qt.AlignCenter, action.text()) # Draw button actionIconRect = QRect( 0, actionY, actionRect.width(), actionRect.height() - 2 * actionTextRect.height() - 10) actionIcon = QIcon(action.icon()) actionIcon.paint(p, actionIconRect) # Move to next button location actionY += actionRect.height()
def widget_popup_geometry(pos, widget): widget.ensurePolished() if widget.testAttribute(Qt.WA_Resized): size = widget.size() else: size = widget.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) return geom
class ResizeHelper(QWidget): offsetChanged = pyqtSignal(QPoint) offsetXChanged = pyqtSignal(int) offsetYChanged = pyqtSignal(int) offsetBoundsChanged = pyqtSignal(QRect) def __init__(self, parent=None): super().__init__(parent) self.mMouseAnchorPoint = QPoint() self.mOffset = QPoint() self.mOldSize = QSize() self.mDragging = False self.mOffsetBounds = QRect() self.mScale = 0.0 self.mNewSize = QSize() self.mOrigOffset = QPoint() self.setMinimumSize(20, 20) self.setOldSize(QSize(1, 1)) def oldSize(self): return self.mOldSize def newSize(self): return self.mNewSize def offset(self): return self.mOffset def offsetBounds(self): return self.mOffsetBounds def setOldSize(self, size): self.mOldSize = size self.recalculateMinMaxOffset() self.recalculateScale() def setNewSize(self, size): self.mNewSize = size self.recalculateMinMaxOffset() self.recalculateScale() def setOffset(self, offset): # Clamp the offset within the offset bounds newOffset = QPoint( min(self.mOffsetBounds.right(), max(self.mOffsetBounds.left(), offset.x())), min(self.mOffsetBounds.bottom(), max(self.mOffsetBounds.top(), offset.y()))) if (self.mOffset != newOffset): xChanged = self.mOffset.x() != newOffset.x() yChanged = self.mOffset.y() != newOffset.y() self.mOffset = newOffset if (xChanged): self.offsetXChanged.emit(self.mOffset.x()) if (yChanged): self.offsetYChanged.emit(self.mOffset.y()) self.offsetChanged.emit(self.mOffset) self.update() ## Method to set only the X offset, provided for convenience. */ def setOffsetX(self, x): self.setOffset(QPoint(x, self.mOffset.y())) ## Method to set only the Y offset, provided for convenience. */ def setOffsetY(self, y): self.setOffset(QPoint(self.mOffset.x(), y)) ## Method to set only new width, provided for convenience. */ def setNewWidth(self, width): self.mNewSize.setWidth(width) self.recalculateMinMaxOffset() self.recalculateScale() ## Method to set only new height, provided for convenience. */ def setNewHeight(self, height): self.mNewSize.setHeight(height) self.recalculateMinMaxOffset() self.recalculateScale() def paintEvent(self, event): _size = self.size() - QSize(2, 2) if (_size.isEmpty()): return origX = (_size.width() - self.mNewSize.width() * self.mScale) / 2 + 0.5 origY = (_size.height() - self.mNewSize.height() * self.mScale) / 2 + 0.5 oldRect = QRect(self.mOffset, self.mOldSize) painter = QPainter(self) painter.translate(origX, origY) painter.scale(self.mScale, self.mScale) pen = QPen(Qt.black) pen.setCosmetic(True) painter.setPen(pen) painter.drawRect(QRect(QPoint(0, 0), self.mNewSize)) pen.setColor(Qt.white) painter.setPen(pen) painter.setBrush(Qt.white) painter.setOpacity(0.5) painter.drawRect(oldRect) pen.setColor(Qt.black) pen.setStyle(Qt.DashLine) painter.setOpacity(1.0) painter.setBrush(Qt.NoBrush) painter.setPen(pen) painter.drawRect(oldRect) painter.end() def mousePressEvent(self, event): self.mMouseAnchorPoint = event.pos() self.mOrigOffset = self.mOffset self.mDragging = event.button() == Qt.LeftButton def mouseMoveEvent(self, event): if (not self.mDragging): return pos = event.pos() if (pos != self.mMouseAnchorPoint): self.setOffset(self.mOrigOffset + (pos - self.mMouseAnchorPoint) / self.mScale) self.offsetChanged.emit(self.mOffset) def resizeEvent(self, event): self.recalculateScale() def recalculateScale(self): _size = self.size() - QSize(2, 2) if (_size.isEmpty()): return if self.mOldSize.width() < self.mNewSize.width(): width = self.mNewSize.width() else: width = 2 * self.mOldSize.width() - self.mNewSize.width() if self.mOldSize.height() < self.mNewSize.height(): height = self.mNewSize.height() else: height = 2 * self.mOldSize.height() - self.mNewSize.height() # Pick the smallest scale scaleW = _size.width() / width scaleH = _size.height() / height if scaleW < scaleH: self.mScale = scaleW else: self.mScale = scaleH self.update() def recalculateMinMaxOffset(self): offsetBounds = self.mOffsetBounds if (self.mOldSize.width() <= self.mNewSize.width()): offsetBounds.setLeft(0) offsetBounds.setRight(self.mNewSize.width() - self.mOldSize.width()) else: offsetBounds.setLeft(self.mNewSize.width() - self.mOldSize.width()) offsetBounds.setRight(0) if (self.mOldSize.height() <= self.mNewSize.height()): offsetBounds.setTop(0) offsetBounds.setBottom(self.mNewSize.height() - self.mOldSize.height()) else: offsetBounds.setTop(self.mNewSize.height() - self.mOldSize.height()) offsetBounds.setBottom(0) if (self.mOffsetBounds != offsetBounds): self.mOffsetBounds = offsetBounds self.offsetBoundsChanged.emit(self.mOffsetBounds)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = QColor(color) self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert (self.pos == pos) self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage(QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height())) target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height())) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int) ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4 * 4 downsample_threshold = (7. / 16) * 255 labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero( labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen( QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x - self.brushSize // 2 - 1))) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1))) self.bb.setBottom( max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1))) #update/move position self.pos = pos
class corkDelegate(QStyledItemDelegate): def __init__(self, parent=None): QStyledItemDelegate.__init__(self, parent) self.factor = settings.corkSizeFactor / 100. self.lastPos = None self.editing = None self.margin = 5 self.bgColors = {} def newStyle(self): return settings.corkStyle == "new" def setCorkSizeFactor(self, v): self.factor = v / 100. def sizeHint(self, option, index): if self.newStyle(): defaultSize = QSize(300, 210) else: defaultSize = QSize(300, 200) return defaultSize * self.factor def editorEvent(self, event, model, option, index): # We catch the mouse position in the widget to know which part to edit if type(event) == QMouseEvent: self.lastPos = event.pos() # - option.rect.topLeft() return QStyledItemDelegate.editorEvent(self, event, model, option, index) def createEditor(self, parent, option, index): self.updateRects(option, index) bgColor = self.bgColors.get(index, "white") if self.mainLineRect.contains(self.lastPos): # One line summary self.editing = Outline.summarySentence edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) if self.newStyle(): f.setBold(True) else: f.setItalic(True) edt.setAlignment(Qt.AlignCenter) edt.setPlaceholderText(self.tr("One line summary")) edt.setFont(f) edt.setStyleSheet("background: {}; color: black;".format(bgColor)) return edt elif self.titleRect.contains(self.lastPos): # Title self.editing = Outline.title edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) if self.newStyle(): f.setPointSize(f.pointSize() + 4) else: edt.setAlignment(Qt.AlignCenter) f.setBold(True) edt.setFont(f) edt.setStyleSheet("background: {}; color: black;".format(bgColor)) # edt.setGeometry(self.titleRect) return edt else: # self.mainTextRect.contains(self.lastPos): # Summary self.editing = Outline.summaryFull edt = QPlainTextEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrameShape(QFrame.NoFrame) try: # QPlainTextEdit.setPlaceholderText was introduced in Qt 5.3 edt.setPlaceholderText(self.tr("Full summary")) except AttributeError: pass edt.setStyleSheet("background: {}; color: black;".format(bgColor)) return edt def updateEditorGeometry(self, editor, option, index): if self.editing == Outline.summarySentence: # One line summary editor.setGeometry(self.mainLineRect) elif self.editing == Outline.title: # Title editor.setGeometry(self.titleRect) elif self.editing == Outline.summaryFull: # Summary editor.setGeometry(self.mainTextRect) def setEditorData(self, editor, index): item = index.internalPointer() if self.editing == Outline.summarySentence: # One line summary editor.setText(item.data(Outline.summarySentence)) elif self.editing == Outline.title: # Title editor.setText(index.data()) elif self.editing == Outline.summaryFull: # Summary editor.setPlainText(item.data(Outline.summaryFull)) def setModelData(self, editor, model, index): if self.editing == Outline.summarySentence: # One line summary model.setData(index.sibling(index.row(), Outline.summarySentence), editor.text()) elif self.editing == Outline.title: # Title model.setData(index, editor.text(), Outline.title) elif self.editing == Outline.summaryFull: # Summary model.setData(index.sibling(index.row(), Outline.summaryFull), editor.toPlainText()) def updateRects(self, option, index): if self.newStyle(): self.updateRects_v2(option, index) else: self.updateRects_v1(option, index) def updateRects_v2(self, option, index): margin = self.margin * 2 iconSize = max(24 * self.factor, 18) item = index.internalPointer() fm = QFontMetrics(option.font) h = fm.lineSpacing() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) top = 15 * self.factor self.topRect = QRect(self.itemRect) self.topRect.setHeight(top) self.cardRect = QRect(self.itemRect.topLeft() + QPoint(0, top), self.itemRect.bottomRight()) self.iconRect = QRect(self.cardRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect(self.cardRect.topRight() - QPoint(margin + self.factor * 18, 1), self.cardRect.topRight() + QPoint(- margin - self.factor * 4, self.factor * 24)) self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.titleRect.setBottom(self.iconRect.bottom()) self.mainRect = QRect(self.iconRect.bottomLeft() + QPoint(0, margin), self.cardRect.bottomRight() - QPoint(margin, 2*margin)) self.mainRect.setLeft(self.titleRect.left()) self.mainLineRect = QRect(self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, h)) self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentence): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) def updateRects_v1(self, option, index): margin = self.margin iconSize = max(16 * self.factor, 12) item = index.internalPointer() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect(self.itemRect.topRight() - QPoint(iconSize + margin, 0), self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin)) self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.bottomRect = QRect(QPoint(self.itemRect.x(), self.iconRect.bottom() + margin), QPoint(self.itemRect.right(), self.itemRect.bottom())) self.topRect = QRect(self.itemRect.topLeft(), self.bottomRect.topRight()) self.mainRect = self.bottomRect.adjusted(margin, margin, -margin, -margin) self.mainLineRect = QRect(self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, iconSize)) self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentence): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) if item.data(Outline.label) in ["", "0", 0]: self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin)) def paint(self, p, option, index): if self.newStyle(): self.paint_v2(p, option, index) else: self.paint_v1(p, option, index) def paint_v2(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle, rect=self.mainRect): p.translate(rect.center()) p.rotate(angle) p.translate(-rect.center()) def drawRect(r): p.save() p.setBrush(Qt.gray) p.drawRect(r) p.restore() # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) #p.drawRoundedRect(option.rect, 12, 12) p.drawRect(option.rect) p.restore() # Background p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] if c == QColor(Qt.transparent): c = QColor(Qt.white) col = mixColors(c, QColor(Qt.white), .2) backgroundColor = col p.setBrush(col) else: p.setBrush(Qt.white) backgroundColor = QColor(Qt.white) # Cache background color self.bgColors[index] = backgroundColor.name() p.setPen(Qt.NoPen) p.drawRect(self.cardRect) if item.isFolder(): itemPoly = QPolygonF([ self.topRect.topLeft(), self.topRect.topLeft() + QPoint(self.topRect.width() * .35, 0), self.cardRect.topLeft() + QPoint(self.topRect.width() * .45, 0), self.cardRect.topRight(), self.cardRect.bottomRight(), self.cardRect.bottomLeft() ]) p.drawPolygon(itemPoly) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.drawRect(self.labelRect) w = self.labelRect.width() poly = QPolygonF([ self.labelRect.bottomLeft() + QPointF(0, 1), self.labelRect.bottomLeft() + QPointF(0, w / 2), self.labelRect.bottomLeft() + QPointF(w / 2, 1), self.labelRect.bottomRight() + QPointF(1, w / 2), self.labelRect.bottomRight() + QPointF(1, 1), ]) p.drawPolygon(poly) p.restore() if settings.viewSettings["Cork"]["Corner"] == "Nothing" or \ color == Qt.transparent: # No corner, so title can be full width self.titleRect.setRight(self.mainRect.right()) # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() if text: p.setPen(Qt.black) textColor = QColor(Qt.black) if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black # If title setting is compile, we have to hack the color # Or we won't see anything in some themes if settings.viewSettings["Cork"]["Text"] == "Compile": if item.compile() in [0, "0"]: col = mixColors(QColor(Qt.black), backgroundColor) else: col = Qt.black textColor = col p.setPen(col) f = QFont(option.font) f.setPointSize(f.pointSize() + 4) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, self.titleRect.width()) p.drawText(self.titleRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText) p.restore() # One line summary background lineSummary = item.data(Outline.summarySentence) fullSummary = item.data(Outline.summaryFull) # Border if settings.viewSettings["Cork"]["Border"] != "Nothing": p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) col = colors[settings.viewSettings["Cork"]["Border"]] pen.setColor(col) p.setPen(pen) if item.isFolder(): p.drawPolygon(itemPoly) else: p.drawRect(self.cardRect) p.restore() # Draw status status = item.data(Outline.status) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(self.cardRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(170)) _rotate(-35, rect=self.cardRect) p.drawText(self.cardRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setBold(True) p.setFont(f) p.setPen(textColor) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText) p.restore() # Full summary if fullSummary: p.save() p.setFont(option.font) p.setPen(textColor) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary) p.restore() def paint_v1(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle): p.translate(self.mainRect.center()) p.rotate(angle) p.translate(-self.mainRect.center()) # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) p.drawRoundedRect(option.rect, 12, 12) p.restore() # Stack if item.isFolder() and item.childCount() > 0: p.save() p.setBrush(Qt.white) for i in reversed(range(3)): p.drawRoundedRect(self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10, 10) p.restore() # Background itemRect = self.itemRect p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] col = mixColors(c, QColor(Qt.white), .2) p.setBrush(col) else: p.setBrush(Qt.white) pen = p.pen() pen.setWidth(2) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Title bar topRect = self.topRect p.save() if item.isFolder(): color = QColor(Qt.darkGreen) else: color = QColor(Qt.blue).lighter(175) p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(topRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(self.labelRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() if color != Qt.transparent: p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft()) # One line summary background lineSummary = item.data(Outline.summarySentence) fullSummary = item.data(Outline.summaryFull) if lineSummary or not fullSummary: m = self.margin r = self.mainLineRect.adjusted(-m, -m, m, m / 2) p.save() p.setPen(Qt.NoPen) p.setBrush(QColor("#EEE")) p.drawRect(r) p.restore() # Border p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) if settings.viewSettings["Cork"]["Border"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Border"]] if col == Qt.transparent: col = Qt.black pen.setColor(col) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() titleRect = self.titleRect if text: if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black p.setPen(col) f = QFont(option.font) # f.setPointSize(f.pointSize() + 1) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width()) p.drawText(titleRect, Qt.AlignCenter, elidedText) p.restore() # Draw the line bottomRect = self.bottomRect p.save() # p.drawLine(itemRect.x(), iconRect.bottom() + margin, # itemRect.right(), iconRect.bottom() + margin) p.drawLine(bottomRect.topLeft(), bottomRect.topRight()) p.restore() # Lines if True: p.save() p.setPen(QColor("#EEE")) fm = QFontMetrics(option.font) h = fm.lineSpacing() l = self.mainTextRect.topLeft() + QPoint(0, h) while self.mainTextRect.contains(l): p.drawLine(l, QPoint(self.mainTextRect.right(), l.y())) l.setY(l.y() + h) p.restore() # Draw status mainRect = self.mainRect status = item.data(Outline.status) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(mainRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(175)) _rotate(-35) p.drawText(mainRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setItalic(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText) p.restore() # Full summary if fullSummary: p.setFont(option.font) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
def mouseMoveEvent(self, evt): """ Protected method to handle mouse movements. @param evt mouse move event (QMouseEvent) """ shouldShowHelp = not self.__helpTextRect.contains(evt.pos()) if shouldShowHelp != self.__showHelp: self.__showHelp = shouldShowHelp self.update() if self.__mouseDown: if self.__newSelection: p = evt.pos() r = self.rect() self.__selection = self.__normalizeSelection( QRect(self.__dragStartPoint, self.__limitPointToRect(p, r))) elif self.__mouseOverHandle is None: # moving the whole selection r = self.rect().normalized() s = self.__selectionBeforeDrag.normalized() p = s.topLeft() + evt.pos() - self.__dragStartPoint r.setBottomRight(r.bottomRight() - QPoint(s.width(), s.height()) + QPoint(1, 1)) if not r.isNull() and r.isValid(): self.__selection.moveTo(self.__limitPointToRect(p, r)) else: # dragging a handle r = QRect(self.__selectionBeforeDrag) offset = evt.pos() - self.__dragStartPoint if self.__mouseOverHandle in \ [self.__TLHandle, self.__THandle, self.__TRHandle]: r.setTop(r.top() + offset.y()) if self.__mouseOverHandle in \ [self.__TLHandle, self.__LHandle, self.__BLHandle]: r.setLeft(r.left() + offset.x()) if self.__mouseOverHandle in \ [self.__BLHandle, self.__BHandle, self.__BRHandle]: r.setBottom(r.bottom() + offset.y()) if self.__mouseOverHandle in \ [self.__TRHandle, self.__RHandle, self.__BRHandle]: r.setRight(r.right() + offset.x()) r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect())) r.setBottomRight( self.__limitPointToRect(r.bottomRight(), self.rect())) self.__selection = self.__normalizeSelection(r) self.update() else: if self.__selection.isNull(): return found = False for r in self.__handles: if r.contains(evt.pos()): self.__mouseOverHandle = r found = True break if not found: self.__mouseOverHandle = None if self.__selection.contains(evt.pos()): self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.CrossCursor) else: if self.__mouseOverHandle in [ self.__TLHandle, self.__BRHandle ]: self.setCursor(Qt.SizeFDiagCursor) elif self.__mouseOverHandle in [ self.__TRHandle, self.__BLHandle ]: self.setCursor(Qt.SizeBDiagCursor) elif self.__mouseOverHandle in [ self.__LHandle, self.__RHandle ]: self.setCursor(Qt.SizeHorCursor) elif self.__mouseOverHandle in [ self.__THandle, self.__BHandle ]: self.setCursor(Qt.SizeVerCursor)
def paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) r = QRect(self.__selection) if not self.__selection.isNull(): grey = QRegion(self.rect()) if self.__mode == SnapshotRegionGrabber.Ellipse: reg = QRegion(r, QRegion.Ellipse) else: reg = QRegion(r) grey = grey.subtracted(reg) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawRect(painter, r, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated(-self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText(self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isNull(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. txt = "{0}, {1} ({2} x {3})".format( self.__locale.toString(self.__selection.x()), self.__locale.toString(self.__selection.y()), self.__locale.toString(self.__selection.width()), self.__locale.toString(self.__selection.height())) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) if textRect.width() < r.width() - 2 * self.__handleSize and \ textRect.height() < r.height() - 2 * self.__handleSize and \ r.width() > 100 and \ r.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(r.center()) textRect.moveCenter(r.center()) elif r.y() - 3 > textRect.height() and \ r.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) elif r.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) textRect.moveTopRight(QPoint(r.x() - 5, r.y())) elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \ r.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) elif r.right() + textRect.width() + 3 < self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawRect(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2) or \ not self.__mouseDown: self.__updateHandles() painter.setPen(Qt.NoPen) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.StrokeMask)) painter.drawRect(self.rect()) handleColor.setAlpha(60) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.FillMask)) painter.drawRect(self.rect())
def paint(self, painter, option, index): if (index.isValid() == False): return painter.save() painter.setOpacity(0.6) if (option.state & QStyle.State_Selected): painter.fillRect(option.rect, option.palette.highlight()) if (option.state & QStyle.State_MouseOver): painter.setOpacity(0.25) painter.fillRect(option.rect, option.palette.highlight()) painter.setOpacity(1.0) painter.setFont(option.font) metrics = QFontMetrics(option.font) regular = QFont(option.font) italics = QFont(option.font) italics.setItalic(True) icon = QIcon(index.data(CPE.IMAGE)) rect = option.rect margin = 4 decoratonSize = QSize(option.decorationSize) imageSize = icon.actualSize(option.decorationSize) leftSideThumbnail = (decoratonSize.width() - imageSize.width()) / 2 if (rect.width() < decoratonSize.width()): leftSideThumbnail = max(0, (rect.width() - imageSize.width()) / 2) topSizeThumbnail = ( (rect.height() - imageSize.height()) / 2) + rect.top() painter.drawImage( QRect(leftSideThumbnail, topSizeThumbnail, imageSize.width(), imageSize.height()), icon.pixmap(imageSize).toImage()) labelWidth = rect.width() - decoratonSize.width() - (margin * 3) if (decoratonSize.width() + (margin * 2) < rect.width()): textRect = QRect(decoratonSize.width() + margin, margin + rect.top(), labelWidth, metrics.height()) textTitle = metrics.elidedText( str(index.row() + 1) + ". " + index.data(CPE.TITLE), Qt.ElideRight, labelWidth) painter.drawText(textRect, Qt.TextWordWrap, textTitle) if rect.height() / (metrics.lineSpacing() + margin) > 5 or index.data( CPE.KEYWORDS) is not None: painter.setOpacity(0.6) textRect = QRect(textRect.left(), textRect.bottom() + margin, labelWidth, metrics.height()) if textRect.bottom() < rect.bottom(): textKeyWords = index.data(CPE.KEYWORDS) if textKeyWords == None: textKeyWords = i18n("No keywords") painter.setOpacity(0.3) painter.setFont(italics) textKeyWords = metrics.elidedText(textKeyWords, Qt.ElideRight, labelWidth) painter.drawText(textRect, Qt.TextWordWrap, textKeyWords) painter.setFont(regular) if rect.height() / (metrics.lineSpacing() + margin) > 3: painter.setOpacity(0.6) textRect = QRect(textRect.left(), textRect.bottom() + margin, labelWidth, metrics.height()) if textRect.bottom() + metrics.height() < rect.bottom(): textLastEdit = index.data(CPE.LASTEDIT) if textLastEdit is None: textLastEdit = i18n("No last edit timestamp") if index.data(CPE.EDITOR) is not None: textLastEdit += " - " + index.data(CPE.EDITOR) if (index.data(CPE.LASTEDIT) is None) and (index.data( CPE.EDITOR) is None): painter.setOpacity(0.3) painter.setFont(italics) textLastEdit = metrics.elidedText(textLastEdit, Qt.ElideRight, labelWidth) painter.drawText(textRect, Qt.TextWordWrap, textLastEdit) painter.setFont(regular) descRect = QRect(textRect.left(), textRect.bottom() + margin, labelWidth, (rect.bottom() - margin) - (textRect.bottom() + margin)) if textRect.bottom() + metrics.height() < rect.bottom(): textRect.setBottom(textRect.bottom() + (margin / 2)) textRect.setLeft(textRect.left() - (margin / 2)) painter.setOpacity(0.4) painter.drawLine(textRect.bottomLeft(), textRect.bottomRight()) painter.setOpacity(1.0) textDescription = index.data(CPE.DESCRIPTION) if textDescription is None: textDescription = i18n("No description") painter.setOpacity(0.3) painter.setFont(italics) linesTotal = floor(descRect.height() / metrics.lineSpacing()) if linesTotal == 1: textDescription = metrics.elidedText( textDescription, Qt.ElideRight, labelWidth) painter.drawText(descRect, Qt.TextWordWrap, textDescription) else: descRect.setHeight(linesTotal * metrics.lineSpacing()) totalDescHeight = metrics.boundingRect( descRect, Qt.TextWordWrap, textDescription).height() if totalDescHeight > descRect.height(): if totalDescHeight - metrics.lineSpacing( ) > descRect.height(): painter.setOpacity(0.5) painter.drawText(descRect, Qt.TextWordWrap, textDescription) descRect.setHeight( (linesTotal - 1) * metrics.lineSpacing()) painter.drawText(descRect, Qt.TextWordWrap, textDescription) descRect.setHeight( (linesTotal - 2) * metrics.lineSpacing()) painter.drawText(descRect, Qt.TextWordWrap, textDescription) else: painter.setOpacity(0.75) painter.drawText(descRect, Qt.TextWordWrap, textDescription) descRect.setHeight( (linesTotal - 1) * metrics.lineSpacing()) painter.drawText(descRect, Qt.TextWordWrap, textDescription) else: painter.drawText(descRect, Qt.TextWordWrap, textDescription) painter.setFont(regular) painter.restore()
def paint(self, painter, option, index): """ Public method to paint the specified list item. @param painter painter object to paint to (QPainter) @param option style option used for painting (QStyleOptionViewItem) @param index model index of the item (QModelIndex) """ opt = QStyleOptionViewItem(option) self.initStyleOption(opt, index) widget = opt.widget style = widget.style() if widget is not None else QApplication.style() height = opt.rect.height() center = height // 2 + opt.rect.top() # Prepare title font titleFont = QFont(opt.font) titleFont.setBold(True) titleFont.setPointSize(titleFont.pointSize() + 1) titleMetrics = QFontMetrics(titleFont) if Globals.isWindowsPlatform(): colorRole = QPalette.Text else: colorRole = QPalette.HighlightedText if opt.state & QStyle.State_Selected else QPalette.Text leftPos = self.__padding rightPos = opt.rect.right() - self.__padding - GreaseMonkeyConfigurationListDelegate.RemoveIconSize # Draw background style.drawPrimitive(QStyle.PE_PanelItemViewItem, opt, painter, widget) # Draw checkbox checkBoxYPos = center - GreaseMonkeyConfigurationListDelegate.CheckBoxSize // 2 opt2 = QStyleOptionViewItem(opt) if opt2.checkState == Qt.Checked: opt2.state |= QStyle.State_On else: opt2.state |= QStyle.State_Off styleCheckBoxRect = style.subElementRect(QStyle.SE_ViewItemCheckIndicator, opt2, widget) opt2.rect = QRect(leftPos, checkBoxYPos, styleCheckBoxRect.width(), styleCheckBoxRect.height()) style.drawPrimitive(QStyle.PE_IndicatorViewItemCheck, opt2, painter, widget) leftPos = opt2.rect.right() + self.__padding # Draw icon iconYPos = center - GreaseMonkeyConfigurationListDelegate.IconSize // 2 iconRect = QRect( leftPos, iconYPos, GreaseMonkeyConfigurationListDelegate.IconSize, GreaseMonkeyConfigurationListDelegate.IconSize, ) pixmap = index.data(Qt.DecorationRole).pixmap(GreaseMonkeyConfigurationListDelegate.IconSize) painter.drawPixmap(iconRect, pixmap) leftPos = iconRect.right() + self.__padding # Draw script name name = index.data(Qt.DisplayRole) leftTitleEdge = leftPos + 2 rightTitleEdge = rightPos - self.__padding leftPosForVersion = titleMetrics.width(name) + self.__padding nameRect = QRect( leftTitleEdge, opt.rect.top() + self.__padding, rightTitleEdge - leftTitleEdge, titleMetrics.height() ) painter.setFont(titleFont) style.drawItemText(painter, nameRect, Qt.AlignLeft, opt.palette, True, name, colorRole) # Draw version version = index.data(Qt.UserRole) versionRect = QRect( nameRect.x() + leftPosForVersion, nameRect.y(), rightTitleEdge - leftTitleEdge, titleMetrics.height() ) versionFont = titleFont painter.setFont(versionFont) style.drawItemText(painter, versionRect, Qt.AlignLeft, opt.palette, True, version, colorRole) # Draw description infoYPos = nameRect.bottom() + opt.fontMetrics.leading() infoRect = QRect(nameRect.x(), infoYPos, nameRect.width(), opt.fontMetrics.height()) info = opt.fontMetrics.elidedText(index.data(Qt.UserRole + 1), Qt.ElideRight, infoRect.width()) painter.setFont(opt.font) style.drawItemText(painter, infoRect, Qt.AlignLeft | Qt.TextSingleLine, opt.palette, True, info, colorRole) # Draw remove button removeIconYPos = center - GreaseMonkeyConfigurationListDelegate.RemoveIconSize // 2 removeIconRect = QRect( rightPos, removeIconYPos, GreaseMonkeyConfigurationListDelegate.RemoveIconSize, GreaseMonkeyConfigurationListDelegate.RemoveIconSize, ) painter.drawPixmap(removeIconRect, self.__removePixmap)
def mouseMoveEvent(self, evt): """ Protected method to handle mouse movements. @param evt mouse move event (QMouseEvent) """ shouldShowHelp = not self.__helpTextRect.contains(evt.pos()) if shouldShowHelp != self.__showHelp: self.__showHelp = shouldShowHelp self.update() if self.__mouseDown: if self.__newSelection: p = evt.pos() r = self.rect() self.__selection = self.__normalizeSelection( QRect(self.__dragStartPoint, self.__limitPointToRect(p, r))) elif self.__mouseOverHandle is None: # moving the whole selection r = self.rect().normalized() s = self.__selectionBeforeDrag.normalized() p = s.topLeft() + evt.pos() - self.__dragStartPoint r.setBottomRight( r.bottomRight() - QPoint(s.width(), s.height()) + QPoint(1, 1)) if not r.isNull() and r.isValid(): self.__selection.moveTo(self.__limitPointToRect(p, r)) else: # dragging a handle r = QRect(self.__selectionBeforeDrag) offset = evt.pos() - self.__dragStartPoint if self.__mouseOverHandle in \ [self.__TLHandle, self.__THandle, self.__TRHandle]: r.setTop(r.top() + offset.y()) if self.__mouseOverHandle in \ [self.__TLHandle, self.__LHandle, self.__BLHandle]: r.setLeft(r.left() + offset.x()) if self.__mouseOverHandle in \ [self.__BLHandle, self.__BHandle, self.__BRHandle]: r.setBottom(r.bottom() + offset.y()) if self.__mouseOverHandle in \ [self.__TRHandle, self.__RHandle, self.__BRHandle]: r.setRight(r.right() + offset.x()) r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect())) r.setBottomRight( self.__limitPointToRect(r.bottomRight(), self.rect())) self.__selection = self.__normalizeSelection(r) self.update() else: if self.__selection.isNull(): return found = False for r in self.__handles: if r.contains(evt.pos()): self.__mouseOverHandle = r found = True break if not found: self.__mouseOverHandle = None if self.__selection.contains(evt.pos()): self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.CrossCursor) else: if self.__mouseOverHandle in [self.__TLHandle, self.__BRHandle]: self.setCursor(Qt.SizeFDiagCursor) elif self.__mouseOverHandle in [self.__TRHandle, self.__BLHandle]: self.setCursor(Qt.SizeBDiagCursor) elif self.__mouseOverHandle in [self.__LHandle, self.__RHandle]: self.setCursor(Qt.SizeHorCursor) elif self.__mouseOverHandle in [self.__THandle, self.__BHandle]: self.setCursor(Qt.SizeVerCursor)
def paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) r = QRect(self.__selection) if not self.__selection.isNull(): grey = QRegion(self.rect()) if self.__mode == SnapshotRegionGrabber.Ellipse: reg = QRegion(r, QRegion.Ellipse) else: reg = QRegion(r) grey = grey.subtracted(reg) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawRect(painter, r, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated( -self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText( self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isNull(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. txt = "{0:n}, {1:n} ({2:n} x {3:n})".format( self.__selection.x(), self.__selection.y(), self.__selection.width(), self.__selection.height()) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) if textRect.width() < r.width() - 2 * self.__handleSize and \ textRect.height() < r.height() - 2 * self.__handleSize and \ r.width() > 100 and \ r.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(r.center()) textRect.moveCenter(r.center()) elif r.y() - 3 > textRect.height() and \ r.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) elif r.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) textRect.moveTopRight(QPoint(r.x() - 5, r.y())) elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \ r.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) elif r.right() + textRect.width() + 3 < self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawRect(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2) or \ not self.__mouseDown: self.__updateHandles() painter.setPen(Qt.NoPen) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.StrokeMask)) painter.drawRect(self.rect()) handleColor.setAlpha(60) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.FillMask)) painter.drawRect(self.rect())
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() # bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None # an empty scene, where we add all drawn line segments # a QGraphicsLineItem, and which we can use to then # render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = QColor(color) self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): """ pos -- QPointF-like """ self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert self.pos == pos self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage( QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied ) # TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height())) target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height())) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int) ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,)) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,)) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4 * 4 downsample_threshold = (7.0 / 16) * 255 labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): # data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True # update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) # grow bounding box self.bb.setLeft(min(self.bb.left(), max(0, x - self.brushSize // 2 - 1))) self.bb.setRight(max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1))) self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1))) # update/move position self.pos = pos
def paint_smallicon_view(self, painter: QPainter) -> None: self.thumbnail_rect = QRect(0, 0, self.tile_rect.height(), self.tile_rect.height()) font = self.style.font fm = self.style.fm painter.setFont(font) self.paint_thumbnail(painter) if self.zoom_index in [0, 1]: text_option = QTextOption(Qt.AlignLeft | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) text_rect = QRect(QPoint(self.tile_rect.height() + 4, 0), QPoint(self.tile_rect.width(), self.tile_rect.height())) text = self.fileinfo.basename() text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) painter.drawText(QRectF(text_rect), text, text_option) elif self.zoom_index in [2]: text_rect = QRect(QPoint(self.tile_rect.height() + 4, 0), QPoint(self.tile_rect.width() - 80, self.tile_rect.height())) text = self.fileinfo.basename() text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) text_option = QTextOption(Qt.AlignLeft | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) painter.drawText(QRectF(text_rect), text, text_option) text_rect = QRect(QPoint(self.tile_rect.width() - 80, 0), QPoint(self.tile_rect.width(), self.tile_rect.height())) text = bytefmt.humanize(self.fileinfo.size()) text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) text_option = QTextOption(Qt.AlignRight | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) painter.setPen(QColor(96, 96, 96)) painter.drawText(QRectF(text_rect), text, text_option) else: top_left_text, top_right_text, bottom_left_text, bottom_right = self.make_text() row1_rect = QRect(QPoint(self.tile_rect.left() + self.tile_rect.height() + 8, self.tile_rect.top()), QPoint(self.tile_rect.right() - 8, self.tile_rect.top() + self.tile_rect.height() / 2)) row2_rect = QRect(QPoint(self.tile_rect.left() + self.tile_rect.height() + 8, self.tile_rect.top() + self.tile_rect.height() / 2), QPoint(self.tile_rect.right() - 8, self.tile_rect.bottom())) # row 1 text_rect = QRect(QPoint(row1_rect.left(), row1_rect.top()), QPoint(row1_rect.right() - 80, row1_rect.bottom())) text = self.fileinfo.basename() text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) text_option = QTextOption(Qt.AlignLeft | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) painter.drawText(QRectF(text_rect), text, text_option) text_rect = QRect(QPoint(row1_rect.left() - 80, row1_rect.top()), QPoint(row1_rect.right(), row1_rect.bottom())) text = bytefmt.humanize(self.fileinfo.size()) text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) text_option = QTextOption(Qt.AlignRight | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) painter.setPen(QColor(96, 96, 96)) painter.drawText(QRectF(text_rect), text, text_option) # row 2 text_rect = QRect(QPoint(row2_rect.left(), row2_rect.top()), QPoint(row2_rect.right() - 80, row2_rect.bottom())) text = bottom_left_text text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) text_option = QTextOption(Qt.AlignLeft | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) painter.drawText(QRectF(text_rect), text, text_option) text_rect = QRect(QPoint(row2_rect.left() - 80, row2_rect.top()), QPoint(row2_rect.right(), row2_rect.bottom())) text = top_left_text text = fm.elidedText(text, Qt.ElideRight, text_rect.width()) text_option = QTextOption(Qt.AlignRight | Qt.AlignVCenter) text_option.setWrapMode(QTextOption.NoWrap) painter.setPen(QColor(96, 96, 96)) painter.drawText(QRectF(text_rect), text, text_option)
class ResizeHelper(QWidget): offsetChanged = pyqtSignal(QPoint) offsetXChanged = pyqtSignal(int) offsetYChanged = pyqtSignal(int) offsetBoundsChanged = pyqtSignal(QRect) def __init__(self, parent = None): super().__init__(parent) self.mMouseAnchorPoint = QPoint() self.mOffset = QPoint() self.mOldSize = QSize() self.mDragging = False self.mOffsetBounds = QRect() self.mScale = 0.0 self.mNewSize = QSize() self.mOrigOffset = QPoint() self.setMinimumSize(20, 20) self.setOldSize(QSize(1, 1)) def oldSize(self): return self.mOldSize def newSize(self): return self.mNewSize def offset(self): return self.mOffset def offsetBounds(self): return self.mOffsetBounds def setOldSize(self, size): self.mOldSize = size self.recalculateMinMaxOffset() self.recalculateScale() def setNewSize(self, size): self.mNewSize = size self.recalculateMinMaxOffset() self.recalculateScale() def setOffset(self, offset): # Clamp the offset within the offset bounds newOffset = QPoint(min(self.mOffsetBounds.right(), max(self.mOffsetBounds.left(), offset.x())), min(self.mOffsetBounds.bottom(), max(self.mOffsetBounds.top(), offset.y()))) if (self.mOffset != newOffset): xChanged = self.mOffset.x() != newOffset.x() yChanged = self.mOffset.y() != newOffset.y() self.mOffset = newOffset if (xChanged): self.offsetXChanged.emit(self.mOffset.x()) if (yChanged): self.offsetYChanged.emit(self.mOffset.y()) self.offsetChanged.emit(self.mOffset) self.update() ## Method to set only the X offset, provided for convenience. */ def setOffsetX(self, x): self.setOffset(QPoint(x, self.mOffset.y())) ## Method to set only the Y offset, provided for convenience. */ def setOffsetY(self, y): self.setOffset(QPoint(self.mOffset.x(), y)) ## Method to set only new width, provided for convenience. */ def setNewWidth(self, width): self.mNewSize.setWidth(width) self.recalculateMinMaxOffset() self.recalculateScale() ## Method to set only new height, provided for convenience. */ def setNewHeight(self, height): self.mNewSize.setHeight(height) self.recalculateMinMaxOffset() self.recalculateScale() def paintEvent(self, event): _size = self.size() - QSize(2, 2) if (_size.isEmpty()): return origX = (_size.width() - self.mNewSize.width() * self.mScale) / 2 + 0.5 origY = (_size.height() - self.mNewSize.height() * self.mScale) / 2 + 0.5 oldRect = QRect(self.mOffset, self.mOldSize) painter = QPainter(self) painter.translate(origX, origY) painter.scale(self.mScale, self.mScale) pen = QPen(Qt.black) pen.setCosmetic(True) painter.setPen(pen) painter.drawRect(QRect(QPoint(0, 0), self.mNewSize)) pen.setColor(Qt.white) painter.setPen(pen) painter.setBrush(Qt.white) painter.setOpacity(0.5) painter.drawRect(oldRect) pen.setColor(Qt.black) pen.setStyle(Qt.DashLine) painter.setOpacity(1.0) painter.setBrush(Qt.NoBrush) painter.setPen(pen) painter.drawRect(oldRect) painter.end() def mousePressEvent(self, event): self.mMouseAnchorPoint = event.pos() self.mOrigOffset = self.mOffset self.mDragging = event.button() == Qt.LeftButton def mouseMoveEvent(self, event): if (not self.mDragging): return pos = event.pos() if (pos != self.mMouseAnchorPoint): self.setOffset(self.mOrigOffset + (pos - self.mMouseAnchorPoint) / self.mScale) self.offsetChanged.emit(self.mOffset) def resizeEvent(self, event): self.recalculateScale() def recalculateScale(self): _size = self.size() - QSize(2, 2) if (_size.isEmpty()): return if self.mOldSize.width() < self.mNewSize.width(): width = self.mNewSize.width() else: width = 2 * self.mOldSize.width() - self.mNewSize.width() if self.mOldSize.height() < self.mNewSize.height(): height = self.mNewSize.height() else: height = 2 * self.mOldSize.height() - self.mNewSize.height() # Pick the smallest scale scaleW = _size.width() / width scaleH = _size.height() / height if scaleW < scaleH: self.mScale = scaleW else: self.mScale = scaleH self.update() def recalculateMinMaxOffset(self): offsetBounds = self.mOffsetBounds if (self.mOldSize.width() <= self.mNewSize.width()): offsetBounds.setLeft(0) offsetBounds.setRight(self.mNewSize.width() - self.mOldSize.width()) else: offsetBounds.setLeft(self.mNewSize.width() - self.mOldSize.width()) offsetBounds.setRight(0) if (self.mOldSize.height() <= self.mNewSize.height()): offsetBounds.setTop(0) offsetBounds.setBottom(self.mNewSize.height() - self.mOldSize.height()) else: offsetBounds.setTop(self.mNewSize.height() - self.mOldSize.height()) offsetBounds.setBottom(0) if (self.mOffsetBounds != offsetBounds): self.mOffsetBounds = offsetBounds self.offsetBoundsChanged.emit(self.mOffsetBounds)
def updateBrush(self, cursorPos, _list = None): # get the current tile layer currentLayer = self.currentTileLayer() layerWidth = currentLayer.width() layerHeight = currentLayer.height() numTiles = layerWidth * layerHeight paintCorner = 0 # if we are in vertex paint mode, the bottom right corner on the map will appear as an invalid tile offset... if (self.mBrushMode == BrushMode.PaintVertex): if (cursorPos.x() == layerWidth): cursorPos.setX(cursorPos.x() - 1) paintCorner |= 1 if (cursorPos.y() == layerHeight): cursorPos.setY(cursorPos.y() - 1) paintCorner |= 2 # if the cursor is outside of the map, bail out if (not currentLayer.bounds().contains(cursorPos)): return terrainTileset = None terrainId = -1 if (self.mTerrain): terrainTileset = self.mTerrain.tileset() terrainId = self.mTerrain.id() # allocate a buffer to build the terrain tilemap (TODO: this could be retained per layer to save regular allocation) newTerrain = [] for i in range(numTiles): newTerrain.append(0) # allocate a buffer of flags for each tile that may be considered (TODO: this could be retained per layer to save regular allocation) checked = array('B') for i in range(numTiles): checked.append(0) # create a consideration list, and push the start points transitionList = QList() initialTiles = 0 if (_list): # if we were supplied a list of start points for p in _list: transitionList.append(p) initialTiles += 1 else: transitionList.append(cursorPos) initialTiles = 1 brushRect = QRect(cursorPos, cursorPos) # produce terrain with transitions using a simple, relative naive approach (considers each tile once, and doesn't allow re-consideration if selection was bad) while (not transitionList.isEmpty()): # get the next point in the consideration list p = transitionList.takeFirst() x = p.x() y = p.y() i = y*layerWidth + x # if we have already considered this point, skip to the next # TODO: we might want to allow re-consideration if prior tiles... but not for now, this would risk infinite loops if (checked[i]): continue tile = currentLayer.cellAt(p).tile currentTerrain = terrain(tile) # get the tileset for this tile tileset = None if (terrainTileset): # if we are painting a terrain, then we'll use the terrains tileset tileset = terrainTileset elif (tile): # if we're erasing terrain, use the individual tiles tileset (to search for transitions) tileset = tile.tileset() else: # no tile here and we're erasing terrain, not much we can do continue # calculate the ideal tile for this position preferredTerrain = 0xFFFFFFFF mask = 0 if (initialTiles): # for the initial tiles, we will insert the selected terrain and add the surroundings for consideration if (self.mBrushMode == BrushMode.PaintTile): # set the whole tile to the selected terrain preferredTerrain = makeTerrain(terrainId) mask = 0xFFFFFFFF else: # Bail out if encountering a tile from a different tileset if (tile and tile.tileset() != tileset): continue # calculate the corner mask mask = 0xFF << (3 - paintCorner)*8 # mask in the selected terrain preferredTerrain = (currentTerrain & ~mask) | (terrainId << (3 - paintCorner)*8) initialTiles -= 1 # if there's nothing to paint... skip this tile if (preferredTerrain == currentTerrain and (not tile or tile.tileset() == tileset)): continue else: # Bail out if encountering a tile from a different tileset if (tile and tile.tileset() != tileset): continue # following tiles each need consideration against their surroundings preferredTerrain = currentTerrain mask = 0 # depending which connections have been set, we update the preferred terrain of the tile accordingly if (y > 0 and checked[i - layerWidth]): preferredTerrain = ((terrain(newTerrain[i - layerWidth]) << 16) | (preferredTerrain & 0x0000FFFF))&0xFFFFFFFF mask |= 0xFFFF0000 if (y < layerHeight - 1 and checked[i + layerWidth]): preferredTerrain = ((terrain(newTerrain[i + layerWidth]) >> 16) | (preferredTerrain & 0xFFFF0000))&0xFFFFFFFF mask |= 0x0000FFFF if (x > 0 and checked[i - 1]): preferredTerrain = (((terrain(newTerrain[i - 1]) << 8) & 0xFF00FF00) | (preferredTerrain & 0x00FF00FF))&0xFFFFFFFF mask |= 0xFF00FF00 if (x < layerWidth - 1 and checked[i + 1]): preferredTerrain = (((terrain(newTerrain[i + 1]) >> 8) & 0x00FF00FF) | (preferredTerrain & 0xFF00FF00))&0xFFFFFFFF mask |= 0x00FF00FF # find the most appropriate tile in the tileset paste = None if (preferredTerrain != 0xFFFFFFFF): paste = findBestTile(tileset, preferredTerrain, mask) if (not paste): continue # add tile to the brush newTerrain[i] = paste checked[i] = True # expand the brush rect to fit the edit set brushRect |= QRect(p, p) # consider surrounding tiles if terrain constraints were not satisfied if (y > 0 and not checked[i - layerWidth]): above = currentLayer.cellAt(x, y - 1).tile if (topEdge(paste) != bottomEdge(above)): transitionList.append(QPoint(x, y - 1)) if (y < layerHeight - 1 and not checked[i + layerWidth]): below = currentLayer.cellAt(x, y + 1).tile if (bottomEdge(paste) != topEdge(below)): transitionList.append(QPoint(x, y + 1)) if (x > 0 and not checked[i - 1]): left = currentLayer.cellAt(x - 1, y).tile if (leftEdge(paste) != rightEdge(left)): transitionList.append(QPoint(x - 1, y)) if (x < layerWidth - 1 and not checked[i + 1]): right = currentLayer.cellAt(x + 1, y).tile if (rightEdge(paste) != leftEdge(right)): transitionList.append(QPoint(x + 1, y)) # create a stamp for the terrain block stamp = TileLayer(QString(), brushRect.left(), brushRect.top(), brushRect.width(), brushRect.height()) for y in range(brushRect.top(), brushRect.bottom()+1): for x in range(brushRect.left(), brushRect.right()+1): i = y*layerWidth + x if (not checked[i]): continue tile = newTerrain[i] if (tile): stamp.setCell(x - brushRect.left(), y - brushRect.top(), Cell(tile)) else: # TODO: we need to do something to erase tiles where checked[i] is True, and newTerrain[i] is NULL # is there an eraser stamp? investigate how the eraser works... pass # set the new tile layer as the brush self.brushItem().setTileLayer(stamp) del checked del newTerrain self.mPaintX = cursorPos.x() self.mPaintY = cursorPos.y() self.mOffsetX = cursorPos.x() - brushRect.left() self.mOffsetY = cursorPos.y() - brushRect.top()
class corkDelegate(QStyledItemDelegate): def __init__(self, parent=None): QStyledItemDelegate.__init__(self, parent) self.factor = settings.corkSizeFactor / 100. self.defaultSize = QSize(300, 200) self.lastPos = None self.editing = None self.margin = 5 def setCorkSizeFactor(self, v): self.factor = v / 100. def sizeHint(self, option, index): return self.defaultSize * self.factor def editorEvent(self, event, model, option, index): # We catch the mouse position in the widget to know which part to edit if type(event) == QMouseEvent: self.lastPos = event.pos() # - option.rect.topLeft() return QStyledItemDelegate.editorEvent(self, event, model, option, index) def createEditor(self, parent, option, index): self.updateRects(option, index) if self.mainLineRect.contains(self.lastPos): # One line summary self.editing = Outline.summarySentance edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) edt.setAlignment(Qt.AlignCenter) edt.setPlaceholderText(self.tr("One line summary")) f = QFont(option.font) f.setItalic(True) edt.setFont(f) return edt elif self.titleRect.contains(self.lastPos): # Title self.editing = Outline.title edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) # f.setPointSize(f.pointSize() + 1) f.setBold(True) edt.setFont(f) edt.setAlignment(Qt.AlignCenter) # edt.setGeometry(self.titleRect) return edt else: # self.mainTextRect.contains(self.lastPos): # Summary self.editing = Outline.summaryFull edt = QPlainTextEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrameShape(QFrame.NoFrame) edt.setPlaceholderText(self.tr("Full summary")) return edt def updateEditorGeometry(self, editor, option, index): if self.editing == Outline.summarySentance: # One line summary editor.setGeometry(self.mainLineRect) elif self.editing == Outline.title: # Title editor.setGeometry(self.titleRect) elif self.editing == Outline.summaryFull: # Summary editor.setGeometry(self.mainTextRect) def setEditorData(self, editor, index): item = index.internalPointer() if self.editing == Outline.summarySentance: # One line summary editor.setText(item.data(Outline.summarySentance.value)) elif self.editing == Outline.title: # Title editor.setText(index.data()) elif self.editing == Outline.summaryFull: # Summary editor.setPlainText(item.data(Outline.summaryFull.value)) def setModelData(self, editor, model, index): if self.editing == Outline.summarySentance: # One line summary model.setData(index.sibling(index.row(), Outline.summarySentance.value), editor.text()) elif self.editing == Outline.title: # Title model.setData(index, editor.text(), Outline.title.value) elif self.editing == Outline.summaryFull: # Summary model.setData(index.sibling(index.row(), Outline.summaryFull.value), editor.toPlainText()) def updateRects(self, option, index): margin = self.margin iconSize = max(16 * self.factor, 12) item = index.internalPointer() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect(self.itemRect.topRight() - QPoint(iconSize + margin, 0), self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin)) self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.bottomRect = QRect(QPoint(self.itemRect.x(), self.iconRect.bottom() + margin), QPoint(self.itemRect.right(), self.itemRect.bottom())) self.topRect = QRect(self.itemRect.topLeft(), self.bottomRect.topRight()) self.mainRect = self.bottomRect.adjusted(margin, margin, -margin, -margin) self.mainLineRect = QRect(self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, iconSize)) self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentance.value): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) if item.data(Outline.label.value) in ["", "0"]: self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin)) def paint(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle): p.translate(self.mainRect.center()) p.rotate(angle) p.translate(-self.mainRect.center()) # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) p.drawRoundedRect(option.rect, 12, 12) p.restore() # Stack if item.isFolder() and item.childCount() > 0: p.save() p.setBrush(Qt.white) for i in reversed(range(3)): p.drawRoundedRect(self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10, 10) p.restore() # Background itemRect = self.itemRect p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] col = mixColors(c, QColor(Qt.white), .2) p.setBrush(col) else: p.setBrush(Qt.white) pen = p.pen() pen.setWidth(2) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Title bar topRect = self.topRect p.save() if item.isFolder(): color = QColor(Qt.darkGreen) else: color = QColor(Qt.blue).lighter(175) p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(topRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(self.labelRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft()) # One line summary background lineSummary = item.data(Outline.summarySentance.value) fullSummary = item.data(Outline.summaryFull.value) if lineSummary or not fullSummary: m = self.margin r = self.mainLineRect.adjusted(-m, -m, m, m / 2) p.save() p.setPen(Qt.NoPen) p.setBrush(QColor("#EEE")) p.drawRect(r) p.restore() # Border p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) if settings.viewSettings["Cork"]["Border"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Border"]] if col == Qt.transparent: col = Qt.black pen.setColor(col) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() titleRect = self.titleRect if text: if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black p.setPen(col) f = QFont(option.font) # f.setPointSize(f.pointSize() + 1) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width()) p.drawText(titleRect, Qt.AlignCenter, elidedText) p.restore() # Draw the line bottomRect = self.bottomRect p.save() # p.drawLine(itemRect.x(), iconRect.bottom() + margin, # itemRect.right(), iconRect.bottom() + margin) p.drawLine(bottomRect.topLeft(), bottomRect.topRight()) p.restore() # Lines if True: p.save() p.setPen(QColor("#EEE")) fm = QFontMetrics(option.font) h = fm.lineSpacing() l = self.mainTextRect.topLeft() + QPoint(0, h) while self.mainTextRect.contains(l): p.drawLine(l, QPoint(self.mainTextRect.right(), l.y())) l.setY(l.y() + h) p.restore() # Draw status mainRect = self.mainRect status = item.data(Outline.status.value) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(mainRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(175)) _rotate(-35) p.drawText(mainRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setItalic(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText) p.restore() # Full summary if fullSummary: p.setFont(option.font) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)