Changeset View
Changeset View
Standalone View
Standalone View
plugins/python/quick_settings_docker/quick_settings_docker.py
1 | ''' | 1 | # By Wolthera(originally) | ||
---|---|---|---|---|---|
2 | Description: A Python based docker for quickly choosing the brushsize like similar dockers in other drawing programs. | | |||
3 | 2 | | |||
4 | By Wolthera(originally) | 3 | # This script is licensed CC 0 1.0, so that you can learn from it. | ||
5 | 4 | | |||
6 | This script is licensed CC 0 1.0, so that you can learn from it. | 5 | # ------ CC 0 1.0 --------------- | ||
7 | 6 | | |||
8 | ------ CC 0 1.0 --------------- | 7 | # The person who associated a work with this deed has dedicated the | ||
8 | # work to the public domain by waiving all of his or her rights to the | ||||
9 | # work worldwide under copyright law, including all related and | ||||
10 | # neighboring rights, to the extent allowed by law. | ||||
9 | 11 | | |||
10 | The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. | 12 | # You can copy, modify, distribute and perform the work, even for | ||
13 | # commercial purposes, all without asking permission. | ||||
11 | 14 | | |||
12 | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. | 15 | # https://creativecommons.org/publicdomain/zero/1.0/legalcode | ||
13 | 16 | | |||
14 | https://creativecommons.org/publicdomain/zero/1.0/legalcode | 17 | '''A Python based docker for quickly choosing the brushsize like | ||
18 | similar dockers in other drawing programs. | ||||
15 | 19 | | |||
16 | @package quick_settings_docker | 20 | @package quick_settings_docker | ||
21 | | ||||
17 | ''' | 22 | ''' | ||
18 | 23 | | |||
19 | # Importing the relevant dependencies: | 24 | # Importing the relevant dependencies: | ||
20 | import sys | | |||
21 | from PyQt5.QtCore import pyqtSlot, Qt, QPointF | 25 | from PyQt5.QtCore import pyqtSlot, Qt, QPointF | ||
22 | from PyQt5.QtGui import QStandardItem, QStandardItemModel, QPainter, QPalette, QPixmap, QImage, QBrush, QPen, QIcon | 26 | from PyQt5.QtGui import (QStandardItem, QStandardItemModel, QPainter, QPalette, | ||
27 | QPixmap, QImage, QBrush, QPen, QIcon) | ||||
23 | from PyQt5.QtWidgets import QWidget, QTabWidget, QListView, QVBoxLayout | 28 | from PyQt5.QtWidgets import QWidget, QTabWidget, QListView, QVBoxLayout | ||
24 | from krita import * | 29 | from krita import DockWidget | ||
25 | 30 | | |||
26 | 31 | | |||
27 | class QuickSettingsDocker(DockWidget): | 32 | class QuickSettingsDocker(DockWidget): | ||
28 | # Init the docker | 33 | # Init the docker | ||
29 | 34 | | |||
30 | def __init__(self): | 35 | def __init__(self): | ||
31 | super(QuickSettingsDocker, self).__init__() | 36 | super(QuickSettingsDocker, self).__init__() | ||
32 | # make base-widget and layout | 37 | # make base-widget and layout | ||
Show All 27 Lines | |||||
60 | tabWidget.addTab(self.brushSizeTableView, i18n("Size")) | 65 | tabWidget.addTab(self.brushSizeTableView, i18n("Size")) | ||
61 | tabWidget.addTab(self.brushOpacityTableView, i18n("Opacity")) | 66 | tabWidget.addTab(self.brushOpacityTableView, i18n("Opacity")) | ||
62 | tabWidget.addTab(self.brushFlowTableView, i18n("Flow")) | 67 | tabWidget.addTab(self.brushFlowTableView, i18n("Flow")) | ||
63 | layout.addWidget(tabWidget) | 68 | layout.addWidget(tabWidget) | ||
64 | self.setWidget(widget) # Add the widget to the docker. | 69 | self.setWidget(widget) # Add the widget to the docker. | ||
65 | 70 | | |||
66 | # amount of columns in each row for all the tables. | 71 | # amount of columns in each row for all the tables. | ||
67 | 72 | | |||
68 | # We want a grid with possible options to select. | 73 | # We want a grid with possible options to select. To do this, | ||
69 | # To do this, we'll make a ListView widget and use a standarditemmodel for the entries. | 74 | # we'll make a ListView widget and use a standarditemmodel for | ||
70 | # The entries are filled out based on the sizes and opacity lists. | 75 | # the entries. The entries are filled out based on the sizes | ||
71 | 76 | # and opacity lists. | |||
72 | # Sizes and opacity lists. The former is half-way copied from ptsai, the latter is based on personal experience of useful opacities. | 77 | | ||
73 | self.sizesList = [0.7, 1.0, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 20, 25, 30, 35, 40, 50, 60, 70, 80, 100, 120, 160, 200, 250, 300, 350, 400, 450, 500] | 78 | # Sizes and opacity lists. The former is half-way copied from | ||
74 | self.opacityList = [0.1, 0.5, 1, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100] | 79 | # ptsai, the latter is based on personal experience of useful | ||
80 | # opacities. | ||||
81 | self.sizesList = [ | ||||
82 | 0.7, 1.0, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, | ||||
83 | 20, 25, 30, 35, 40, 50, 60, 70, 80, 100, 120, 160, 200, 250, 300, | ||||
84 | 350, 400, 450, 500] | ||||
85 | self.opacityList = [ | ||||
86 | 0.1, 0.5, 1, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100] | ||||
75 | self.brushSizeModel = QStandardItemModel() | 87 | self.brushSizeModel = QStandardItemModel() | ||
76 | self.brushOpacityModel = QStandardItemModel() | 88 | self.brushOpacityModel = QStandardItemModel() | ||
77 | self.brushFlowModel = QStandardItemModel() | 89 | self.brushFlowModel = QStandardItemModel() | ||
78 | self.fillSizesModel() | 90 | self.fillSizesModel() | ||
79 | self.fillOpacityModel() | 91 | self.fillOpacityModel() | ||
80 | 92 | | |||
81 | # Now we're done filling out our tables, we connect the views to the functions that'll change the settings. | 93 | # Now we're done filling out our tables, we connect the views | ||
94 | # to the functions that'll change the settings. | ||||
82 | self.brushSizeTableView.clicked.connect(self.setBrushSize) | 95 | self.brushSizeTableView.clicked.connect(self.setBrushSize) | ||
83 | self.brushOpacityTableView.clicked.connect(self.setBrushOpacity) | 96 | self.brushOpacityTableView.clicked.connect(self.setBrushOpacity) | ||
84 | self.brushFlowTableView.clicked.connect(self.setBrushFlow) | 97 | self.brushFlowTableView.clicked.connect(self.setBrushFlow) | ||
85 | 98 | | |||
86 | def fillSizesModel(self): | 99 | def fillSizesModel(self): | ||
87 | # First we empty the old model. We might wanna use this function in the future to fill it with the brushmask of the selected brush, but there's currently no API for recognising changes in the current brush nor is there a way to get its brushmask. | 100 | # First we empty the old model. We might wanna use this | ||
101 | # function in the future to fill it with the brushmask of the | ||||
102 | # selected brush, but there's currently no API for recognising | ||||
103 | # changes in the current brush nor is there a way to get its | ||||
104 | # brushmask. | ||||
88 | self.brushSizeModel.clear() | 105 | self.brushSizeModel.clear() | ||
89 | for s in range(len(self.sizesList)): | 106 | for s in range(len(self.sizesList)): | ||
90 | # we're gonna iterate over our list, and make a new item for each entry. | 107 | # we're gonna iterate over our list, and make a new item | ||
91 | # We need to disable a bunch of stuff to make sure people won't do funny things to our entries. | 108 | # for each entry. We need to disable a bunch of stuff to | ||
109 | # make sure people won't do funny things to our entries. | ||||
92 | item = QStandardItem() | 110 | item = QStandardItem() | ||
93 | item.setCheckable(False) | 111 | item.setCheckable(False) | ||
94 | item.setEditable(False) | 112 | item.setEditable(False) | ||
95 | item.setDragEnabled(False) | 113 | item.setDragEnabled(False) | ||
96 | item.setText(str(self.sizesList[s])+" px") | 114 | item.setText(str(self.sizesList[s])+" px") | ||
97 | # And from here on we'll make an icon. | 115 | # And from here on we'll make an icon. | ||
98 | brushImage = QPixmap(64, 64) | 116 | brushImage = QPixmap(64, 64) | ||
99 | img = QImage(64, 64, QImage.Format_RGBA8888) | 117 | img = QImage(64, 64, QImage.Format_RGBA8888) | ||
100 | circlePainter = QPainter() | 118 | circlePainter = QPainter() | ||
101 | img.fill(Qt.transparent) | 119 | img.fill(Qt.transparent) | ||
102 | circlePainter.begin(img) | 120 | circlePainter.begin(img) | ||
103 | brush = QBrush(Qt.SolidPattern) | 121 | brush = QBrush(Qt.SolidPattern) | ||
104 | brush.setColor(self.brushSizeTableView.palette().color(QPalette.Text)) | 122 | brush.setColor( | ||
123 | self.brushSizeTableView.palette().color(QPalette.Text)) | ||||
105 | circlePainter.setBrush(brush) | 124 | circlePainter.setBrush(brush) | ||
106 | circlePainter.setPen(QPen(QBrush(Qt.transparent), 0)) | 125 | circlePainter.setPen(QPen(QBrush(Qt.transparent), 0)) | ||
107 | brushSize = max(min(self.sizesList[s], 64), 1) | 126 | brushSize = max(min(self.sizesList[s], 64), 1) | ||
108 | brushSize = brushSize * 0.5 | 127 | brushSize = brushSize * 0.5 | ||
109 | circlePainter.drawEllipse(QPointF(32, 32), brushSize, brushSize) | 128 | circlePainter.drawEllipse(QPointF(32, 32), brushSize, brushSize) | ||
110 | circlePainter.end() | 129 | circlePainter.end() | ||
111 | brushImage = QPixmap.fromImage(img) | 130 | brushImage = QPixmap.fromImage(img) | ||
112 | # now we're done with drawing the icon, so we set it on the item. | 131 | # now we're done with drawing the icon, so we set it on the item. | ||
113 | item.setIcon(QIcon(brushImage)) | 132 | item.setIcon(QIcon(brushImage)) | ||
114 | self.brushSizeModel.appendRow(item) | 133 | self.brushSizeModel.appendRow(item) | ||
115 | self.brushSizeTableView.setModel(self.brushSizeModel) | 134 | self.brushSizeTableView.setModel(self.brushSizeModel) | ||
116 | 135 | | |||
117 | def fillOpacityModel(self): | 136 | def fillOpacityModel(self): | ||
118 | self.brushOpacityModel.clear() | 137 | self.brushOpacityModel.clear() | ||
119 | self.brushFlowModel.clear() | 138 | self.brushFlowModel.clear() | ||
120 | for s in range(len(self.opacityList)): | 139 | for s in range(len(self.opacityList)): | ||
121 | # we're gonna iterate over our list, and make a new item for each entry. | 140 | # we're gonna iterate over our list, and make a new item | ||
141 | # for each entry. | ||||
122 | item = QStandardItem() | 142 | item = QStandardItem() | ||
123 | item.setCheckable(False) | 143 | item.setCheckable(False) | ||
124 | item.setEditable(False) | 144 | item.setEditable(False) | ||
125 | item.setDragEnabled(False) | 145 | item.setDragEnabled(False) | ||
126 | item.setText(str(self.opacityList[s])+" %") | 146 | item.setText(str(self.opacityList[s])+" %") | ||
127 | brushImage = QPixmap(64, 64) | 147 | brushImage = QPixmap(64, 64) | ||
128 | img = QImage(64, 64, QImage.Format_RGBA8888) | 148 | img = QImage(64, 64, QImage.Format_RGBA8888) | ||
129 | circlePainter = QPainter() | 149 | circlePainter = QPainter() | ||
130 | img.fill(Qt.transparent) | 150 | img.fill(Qt.transparent) | ||
131 | circlePainter.begin(img) | 151 | circlePainter.begin(img) | ||
132 | brush = QBrush(Qt.SolidPattern) | 152 | brush = QBrush(Qt.SolidPattern) | ||
133 | brush.setColor(self.brushSizeTableView.palette().color(QPalette.Text)) | 153 | brush.setColor( | ||
154 | self.brushSizeTableView.palette().color(QPalette.Text)) | ||||
134 | circlePainter.setBrush(brush) | 155 | circlePainter.setBrush(brush) | ||
135 | circlePainter.setPen(QPen(QBrush(Qt.transparent), 0)) | 156 | circlePainter.setPen(QPen(QBrush(Qt.transparent), 0)) | ||
136 | circlePainter.setOpacity(float(self.opacityList[s]) / 100.0) | 157 | circlePainter.setOpacity(float(self.opacityList[s]) / 100.0) | ||
137 | circlePainter.drawEllipse(QPointF(32, 32), 32, 32) | 158 | circlePainter.drawEllipse(QPointF(32, 32), 32, 32) | ||
138 | circlePainter.end() | 159 | circlePainter.end() | ||
139 | brushImage = QPixmap.fromImage(img) | 160 | brushImage = QPixmap.fromImage(img) | ||
140 | item.setIcon(QIcon(brushImage)) | 161 | item.setIcon(QIcon(brushImage)) | ||
141 | # the flow and opacity models will use virtually the same items, but Qt would like us to make sure we understand | 162 | # the flow and opacity models will use virtually the same | ||
163 | # items, but Qt would like us to make sure we understand | ||||
142 | # these are not really the same items, so hence the clone. | 164 | # these are not really the same items, so hence the clone. | ||
143 | itemFlow = item.clone() | 165 | itemFlow = item.clone() | ||
144 | self.brushOpacityModel.appendRow(item) | 166 | self.brushOpacityModel.appendRow(item) | ||
145 | self.brushFlowModel.appendRow(itemFlow) | 167 | self.brushFlowModel.appendRow(itemFlow) | ||
146 | self.brushOpacityTableView.setModel(self.brushOpacityModel) | 168 | self.brushOpacityTableView.setModel(self.brushOpacityModel) | ||
147 | self.brushFlowTableView.setModel(self.brushFlowModel) | 169 | self.brushFlowTableView.setModel(self.brushFlowModel) | ||
148 | 170 | | |||
149 | def canvasChanged(self, canvas): | 171 | def canvasChanged(self, canvas): | ||
150 | pass | 172 | pass | ||
151 | 173 | | |||
152 | @pyqtSlot('QModelIndex') | 174 | @pyqtSlot('QModelIndex') | ||
153 | def setBrushSize(self, index): | 175 | def setBrushSize(self, index): | ||
154 | i = index.row() | 176 | i = index.row() | ||
155 | brushSize = self.sizesList[i] | 177 | brushSize = self.sizesList[i] | ||
156 | if Application.activeWindow() and len(Application.activeWindow().views()) > 0: | 178 | window = Application.activeWindow() | ||
157 | Application.activeWindow().views()[0].setBrushSize(brushSize) | 179 | if window and window.views(): | ||
180 | window.views()[0].setBrushSize(brushSize) | ||||
158 | 181 | | |||
159 | @pyqtSlot('QModelIndex') | 182 | @pyqtSlot('QModelIndex') | ||
160 | def setBrushOpacity(self, index): | 183 | def setBrushOpacity(self, index): | ||
161 | i = index.row() | 184 | i = index.row() | ||
162 | brushOpacity = float(self.opacityList[i]) / 100.0 | 185 | brushOpacity = float(self.opacityList[i]) / 100.0 | ||
163 | if Application.activeWindow() and len(Application.activeWindow().views()) > 0: | 186 | window = Application.activeWindow() | ||
164 | Application.activeWindow().views()[0].setPaintingOpacity(brushOpacity) | 187 | if window and window.views(): | ||
188 | window.views()[0].setPaintingOpacity(brushOpacity) | ||||
165 | 189 | | |||
166 | @pyqtSlot('QModelIndex') | 190 | @pyqtSlot('QModelIndex') | ||
167 | def setBrushFlow(self, index): | 191 | def setBrushFlow(self, index): | ||
168 | i = index.row() | 192 | i = index.row() | ||
169 | brushOpacity = float(self.opacityList[i]) / 100.0 | 193 | brushOpacity = float(self.opacityList[i]) / 100.0 | ||
170 | if Application.activeWindow() and len(Application.activeWindow().views()) > 0: | 194 | window = Application.activeWindow() | ||
171 | Application.activeWindow().views()[0].setPaintingFlow(brushOpacity) | 195 | if window and window.views(): | ||
172 | 196 | window.views()[0].setPaintingFlow(brushOpacity) | |||
173 | | ||||
174 | # Add docker to the application :) | | |||
175 | Application.addDockWidgetFactory(DockWidgetFactory("quick_settings_docker", DockWidgetFactoryBase.DockRight, QuickSettingsDocker)) | |