File indexing completed on 2024-09-22 04:08:47
0001 # Photobash Images is a Krita plugin to get CC0 images based on a search, 0002 # straight from the Krita Interface. Useful for textures and concept art! 0003 # Copyright (C) 2020 Pedro Reis. 0004 # 0005 # This program is free software: you can redistribute it and/or modify 0006 # it under the terms of the GNU General Public License as published by 0007 # the Free Software Foundation, either version 3 of the License, or 0008 # (at your option) any later version. 0009 # 0010 # This program is distributed in the hope that it will be useful, 0011 # but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 # GNU General Public License for more details. 0014 # 0015 # You should have received a copy of the GNU General Public License 0016 # along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 0018 from krita import * 0019 from PyQt5 import QtWidgets, QtCore 0020 0021 DRAG_DELTA = 30 0022 TRIANGLE_SIZE = 20 0023 0024 FAVOURITE_TRIANGLE = QPolygon([ 0025 QPoint(0, 0), 0026 QPoint(0, TRIANGLE_SIZE), 0027 QPoint(TRIANGLE_SIZE, 0) 0028 ]) 0029 0030 def customPaintEvent(instance, event): 0031 painter = QPainter(instance) 0032 painter.setRenderHint(QtGui.QPainter.Antialiasing, True) 0033 painter.setPen(QPen(Qt.black, 2, Qt.SolidLine)) 0034 painter.setBrush(QBrush(Qt.white, Qt.SolidPattern)) 0035 0036 # Calculations 0037 total_width = event.rect().width() 0038 total_height = event.rect().height() 0039 image_width = instance.qimage.width() 0040 image_height = instance.qimage.height() 0041 0042 try: 0043 var_w = total_width / image_width 0044 var_h = total_height / image_height 0045 except: 0046 var_w = 1 0047 var_h = 1 0048 0049 size = 0 0050 0051 if var_w <= var_h: 0052 size = var_w 0053 if var_w > var_h: 0054 size = var_h 0055 0056 wt2 = total_width * 0.5 0057 ht2 = total_height * 0.5 0058 0059 instance.scaled_width = image_width * size 0060 instance.scaled_height = image_height * size 0061 0062 offset_x = wt2 - (instance.scaled_width * 0.5) 0063 offset_y = ht2 - (instance.scaled_height * 0.5) 0064 0065 # Save State for Painter 0066 painter.save() 0067 painter.translate(offset_x, offset_y) 0068 painter.scale(size, size) 0069 painter.drawImage(0,0,instance.qimage) 0070 # paint something if it is a favourite 0071 if hasattr(instance, 'isFavourite'): 0072 if instance.isFavourite: 0073 # reset scale to draw favourite triangle 0074 painter.scale(1/size, 1/size) 0075 painter.drawPolygon(FAVOURITE_TRIANGLE) 0076 0077 # Restore Space 0078 painter.restore() 0079 0080 def customSetImage(instance, image): 0081 instance.qimage = QImage() if image is None else image 0082 instance.pixmap = QPixmap(50, 50).fromImage(instance.qimage) 0083 0084 instance.update() 0085 0086 def customMouseMoveEvent(self, event): 0087 if event.modifiers() != QtCore.Qt.ShiftModifier and event.modifiers() != QtCore.Qt.AltModifier: 0088 self.PREVIOUS_DRAG_X = None 0089 return 0090 0091 # alt modifier is reserved for scrolling through 0092 if self.PREVIOUS_DRAG_X and event.modifiers() == QtCore.Qt.AltModifier: 0093 if self.PREVIOUS_DRAG_X < event.x() - DRAG_DELTA: 0094 self.SIGNAL_WUP.emit(0) 0095 self.PREVIOUS_DRAG_X = event.x() 0096 elif self.PREVIOUS_DRAG_X > event.x() + DRAG_DELTA: 0097 self.SIGNAL_WDN.emit(0) 0098 self.PREVIOUS_DRAG_X = event.x() 0099 0100 return 0101 0102 # MimeData 0103 mimedata = QMimeData() 0104 url = QUrl().fromLocalFile(self.path) 0105 mimedata.setUrls([url]) 0106 0107 # create appropriate res image that will placed 0108 doc = Krita.instance().activeDocument() 0109 0110 # Saving a non-existent document causes crashes, so lets check for that first. 0111 if doc is None: 0112 return 0113 0114 scale = self.scale / 100 0115 0116 # only scale to document if it exists 0117 if self.fitCanvasChecked and not doc is None: 0118 fullImage = QImage(self.path).scaled(doc.width() * scale, doc.height() * scale, Qt.KeepAspectRatio, Qt.SmoothTransformation) 0119 else: 0120 fullImage = QImage(self.path) 0121 # scale image, now knowing the bounds 0122 fullImage = fullImage.scaled(fullImage.width() * scale, fullImage.height() * scale, Qt.KeepAspectRatio, Qt.SmoothTransformation) 0123 0124 fullPixmap = QPixmap(50, 50).fromImage(fullImage) 0125 mimedata.setImageData(fullPixmap) 0126 0127 # Clipboard 0128 QApplication.clipboard().setImage(self.qimage) 0129 0130 # drag, using information about the smaller version of the image 0131 drag = QDrag(self) 0132 drag.setMimeData(mimedata) 0133 drag.setPixmap(self.pixmap) 0134 drag.setHotSpot(QPoint(self.qimage.width() / 2, self.qimage.height() / 2)) 0135 drag.exec_(Qt.CopyAction) 0136 0137 class Photobash_Display(QWidget): 0138 SIGNAL_HOVER = QtCore.pyqtSignal(str) 0139 SIGNAL_CLOSE = QtCore.pyqtSignal(int) 0140 fitCanvasChecked = False 0141 scale = 100 0142 0143 def __init__(self, parent): 0144 super(Photobash_Display, self).__init__(parent) 0145 customSetImage(self, None) 0146 0147 def sizeHint(self): 0148 return QtCore.QSize(5000,5000) 0149 0150 def enterEvent(self, event): 0151 self.SIGNAL_HOVER.emit("D") 0152 0153 def leaveEvent(self, event): 0154 self.SIGNAL_HOVER.emit("None") 0155 0156 def mousePressEvent(self, event): 0157 if (event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton): 0158 self.SIGNAL_CLOSE.emit(0) 0159 0160 def mouseMoveEvent(self, event): 0161 customMouseMoveEvent(self, event) 0162 0163 def setFitCanvas(self, newFit): 0164 self.fitCanvasChecked = newFit 0165 0166 def setImageScale(self, newScale): 0167 self.scale = newScale 0168 0169 def setImage(self, path, image): 0170 self.path = path 0171 customSetImage(self, image) 0172 0173 def paintEvent(self, event): 0174 customPaintEvent(self, event) 0175 0176 class Photobash_Button(QWidget): 0177 SIGNAL_HOVER = QtCore.pyqtSignal(str) 0178 SIGNAL_LMB = QtCore.pyqtSignal(int) 0179 SIGNAL_WUP = QtCore.pyqtSignal(int) 0180 SIGNAL_WDN = QtCore.pyqtSignal(int) 0181 SIGNAL_PREVIEW = QtCore.pyqtSignal(str) 0182 SIGNAL_FAVOURITE = QtCore.pyqtSignal(str) 0183 SIGNAL_UN_FAVOURITE = QtCore.pyqtSignal(str) 0184 SIGNAL_OPEN_NEW = QtCore.pyqtSignal(str) 0185 SIGNAL_REFERENCE = QtCore.pyqtSignal(str) 0186 SIGNAL_DRAG = QtCore.pyqtSignal(int) 0187 PREVIOUS_DRAG_X = None 0188 fitCanvasChecked = False 0189 scale = 100 0190 isFavourite = False 0191 0192 def __init__(self, parent): 0193 super(Photobash_Button, self).__init__(parent) 0194 # Variables 0195 self.number = -1 0196 # QImage 0197 customSetImage(self, None) 0198 0199 self.scaled_width = 1 0200 self.scaled_height = 1 0201 0202 def setFavourite(self, newFavourite): 0203 self.isFavourite = newFavourite 0204 0205 def setImageScale(self, newScale): 0206 self.scale = newScale 0207 0208 def setFitCanvas(self, newFit): 0209 self.fitCanvasChecked = newFit 0210 0211 def setNumber(self, number): 0212 self.number = number 0213 0214 def sizeHint(self): 0215 return QtCore.QSize(2000,2000) 0216 0217 def enterEvent(self, event): 0218 self.SIGNAL_HOVER.emit(str(self.number)) 0219 0220 def leaveEvent(self, event): 0221 self.SIGNAL_HOVER.emit("None") 0222 0223 def mousePressEvent(self, event): 0224 if event.modifiers() == QtCore.Qt.NoModifier and event.buttons() == QtCore.Qt.LeftButton: 0225 self.SIGNAL_LMB.emit(self.number) 0226 if event.modifiers() == QtCore.Qt.AltModifier: 0227 self.PREVIOUS_DRAG_X = event.x() 0228 0229 def mouseDoubleClickEvent(self, event): 0230 # Prevent double click to open the same image twice 0231 pass 0232 0233 def mouseMoveEvent(self, event): 0234 customMouseMoveEvent(self, event) 0235 0236 def wheelEvent(self,event): 0237 delta = event.angleDelta() 0238 if delta.y() > 20: 0239 self.SIGNAL_WUP.emit(0) 0240 elif delta.y() < -20: 0241 self.SIGNAL_WDN.emit(0) 0242 0243 # menu opened with right click 0244 def contextMenuEvent(self, event): 0245 cmenu = QMenu(self) 0246 0247 cmenuDisplay = cmenu.addAction("Preview in Docker") 0248 favouriteString = "Unpin" if self.isFavourite else "Pin to Beginning" 0249 cmenuFavourite = cmenu.addAction(favouriteString) 0250 cmenuOpenNew = cmenu.addAction("Open as New Document") 0251 cmenuReference = cmenu.addAction("Place as Reference") 0252 0253 background = qApp.palette().color(QPalette.Window).name().split("#")[1] 0254 cmenuStyleSheet = f"""QMenu {{ background-color: #AA{background}; border: 1px solid #{background}; }}""" 0255 cmenu.setStyleSheet(cmenuStyleSheet) 0256 0257 action = cmenu.exec_(self.mapToGlobal(event.pos())) 0258 if action == cmenuDisplay: 0259 self.SIGNAL_PREVIEW.emit(self.path) 0260 if action == cmenuFavourite: 0261 if self.isFavourite: 0262 self.SIGNAL_UN_FAVOURITE.emit(self.path) 0263 else: 0264 self.SIGNAL_FAVOURITE.emit(self.path) 0265 if action == cmenuOpenNew: 0266 self.SIGNAL_OPEN_NEW.emit(self.path) 0267 if action == cmenuReference: 0268 self.SIGNAL_REFERENCE.emit(self.path) 0269 0270 def setImage(self, path, image): 0271 self.path = path 0272 customSetImage(self, image) 0273 0274 def paintEvent(self, event): 0275 customPaintEvent(self, event)