added ability to set forground of background color for the grid

This commit is contained in:
grimsace
2026-05-19 11:02:10 -05:00
parent b392d9028a
commit 84312dc07e
9 changed files with 89 additions and 81 deletions
+1 -6
View File
@@ -1,6 +1 @@
from krita import Krita
from .grid_generator import GridGenerator
# Create the plugin instance and add it to Krita
Krita.instance().addExtension(GridGenerator(Krita.instance()))
from .grid_docker import *
@@ -1,31 +1,34 @@
import math
from krita import Krita, ManagedColor
from krita import DockWidget, DockWidgetFactory, DockWidgetFactoryBase, Krita
from PyQt5.QtCore import QPointF
from PyQt5.QtWidgets import (
QCheckBox,
QComboBox,
QDialog,
QDoubleSpinBox,
QHBoxLayout,
QLabel,
QPushButton,
QVBoxLayout,
QWidget,
)
DOCKER_ID = "grid_generator_docker"
class GridDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
class GridDocker(DockWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Grid Generator")
self.setup_ui()
def setup_ui(self):
layout = QVBoxLayout(self)
main_widget = QWidget()
layout = QVBoxLayout(main_widget)
# Thickness
thickness_layout = QHBoxLayout()
thickness_layout.addWidget(QLabel("Line Thickness (px):"))
thickness_layout.addWidget(QLabel("Thickness (px):"))
self.thickness_spin = QDoubleSpinBox()
self.thickness_spin.setRange(0.1, 1000.0)
self.thickness_spin.setValue(2.0)
@@ -34,7 +37,7 @@ class GridDialog(QDialog):
# Width
width_layout = QHBoxLayout()
width_layout.addWidget(QLabel("Grid Width (px):"))
width_layout.addWidget(QLabel("Width (px):"))
self.width_spin = QDoubleSpinBox()
self.width_spin.setRange(1.0, 10000.0)
self.width_spin.setValue(100.0)
@@ -44,7 +47,7 @@ class GridDialog(QDialog):
# Height
height_layout = QHBoxLayout()
height_layout.addWidget(QLabel("Grid Height (px):"))
height_layout.addWidget(QLabel("Height (px):"))
self.height_spin = QDoubleSpinBox()
self.height_spin.setRange(1.0, 10000.0)
self.height_spin.setValue(100.0)
@@ -59,7 +62,7 @@ class GridDialog(QDialog):
# Grid Type
type_layout = QHBoxLayout()
type_layout.addWidget(QLabel("Grid Type:"))
type_layout.addWidget(QLabel("Type:"))
self.type_combo = QComboBox()
self.type_combo.addItems(["Square", "Hexagon"])
type_layout.addWidget(self.type_combo)
@@ -67,21 +70,27 @@ class GridDialog(QDialog):
# Layer Option
layer_layout = QHBoxLayout()
layer_layout.addWidget(QLabel("Generate on:"))
layer_layout.addWidget(QLabel("On:"))
self.layer_combo = QComboBox()
self.layer_combo.addItems(["New Layer", "Current Layer"])
layer_layout.addWidget(self.layer_combo)
layout.addLayout(layer_layout)
# Color Option
color_layout = QHBoxLayout()
color_layout.addWidget(QLabel("Color:"))
self.color_combo = QComboBox()
self.color_combo.addItems(["Foreground", "Background"])
color_layout.addWidget(self.color_combo)
layout.addLayout(color_layout)
# Buttons
button_layout = QHBoxLayout()
self.ok_button = QPushButton("Generate")
self.ok_button.clicked.connect(self.generate)
self.cancel_button = QPushButton("Cancel")
self.cancel_button.clicked.connect(self.reject)
button_layout.addWidget(self.ok_button)
button_layout.addWidget(self.cancel_button)
layout.addLayout(button_layout)
layout.addWidget(self.ok_button)
layout.addStretch()
self.setWidget(main_widget)
def on_width_changed(self, value):
if self.lock_check.isChecked():
@@ -95,89 +104,109 @@ class GridDialog(QDialog):
self.width_spin.setValue(value)
self.width_spin.blockSignals(False)
def canvasChanged(self, canvas):
pass
def get_color_hex(self):
app = Krita.instance()
window = app.activeWindow()
if not window:
return "#000000"
view = window.activeView()
if not view:
return "#000000"
color = None
if self.color_combo.currentText() == "Foreground":
color = view.foregroundColor()
else:
color = view.backgroundColor()
# Ensure the color is in RGBA U8 sRGB for easy extraction
# setColorSpace signature: (colorModelId, bitDepthId, profileName)
color.setColorSpace("RGBA", "U8", "sRGB built-in")
# componentsOrdered returns normalized floats [R, G, B, A]
comps = color.componentsOrdered()
r = int(max(0, min(1, comps[0])) * 255)
g = int(max(0, min(1, comps[1])) * 255)
b = int(max(0, min(1, comps[2])) * 255)
return f"#{r:02x}{g:02x}{b:02x}"
def generate(self):
app = Krita.instance()
doc = app.activeDocument()
if not doc:
return
window = app.activeWindow()
if not window:
return
thickness = self.thickness_spin.value()
width = self.width_spin.value()
height = self.height_spin.value()
grid_type = self.type_combo.currentText()
layer_option = self.layer_combo.currentText()
color_hex = self.get_color_hex()
# Determine target layer
target_node = None
if layer_option == "New Layer":
target_node = doc.createNode("grid", "vectorlayer")
target_node = doc.createVectorLayer("grid")
doc.rootNode().addChildNode(target_node, None)
else:
target_node = doc.activeNode()
# If current layer is not a vector layer, we should probably create one above it
# because SVG drawing only works on vector layers in Krita's API.
if target_node and target_node.type() != "vectorlayer":
parent = target_node.parentNode()
new_vector = doc.createNode("grid", "vectorlayer")
new_vector = doc.createVectorLayer("grid")
parent.addChildNode(new_vector, target_node)
target_node = new_vector
if not target_node:
target_node = doc.createNode("grid", "vectorlayer")
target_node = doc.createVectorLayer("grid")
doc.rootNode().addChildNode(target_node, None)
self.draw_grid(target_node, doc, thickness, width, height, grid_type)
doc.refreshProjection()
self.accept()
def draw_grid(self, node, doc, thickness, width, height, grid_type):
if grid_type == "Square":
self.draw_square_grid(node, doc, thickness, width, height)
if hasattr(target_node, "addShapesFromSvg"):
self.draw_grid(
target_node, doc, thickness, width, height, grid_type, color_hex
)
else:
self.draw_hexagon_grid(node, doc, thickness, width, height)
print(
"Error: Target node does not support SVG shapes. Please ensure you are using Krita 5.0+ and a Vector Layer."
)
def draw_square_grid(self, node, doc, thickness, width, height):
svg = f'<svg><g fill="none" stroke="black" stroke-width="{thickness}">'
doc.refreshProjection()
# Vertical lines
def draw_grid(self, node, doc, thickness, width, height, grid_type, color_hex):
if grid_type == "Square":
self.draw_square_grid(node, doc, thickness, width, height, color_hex)
else:
self.draw_hexagon_grid(node, doc, thickness, width, height, color_hex)
def draw_square_grid(self, node, doc, thickness, width, height, color_hex):
svg = f'<svg><g fill="none" stroke="{color_hex}" stroke-width="{thickness}">'
x = 0
while x <= doc.width():
svg += f'<line x1="{x}" y1="0" x2="{x}" y2="{doc.height()}" />'
x += width
# Horizontal lines
y = 0
while y <= doc.height():
svg += f'<line x1="0" y1="{y}" x2="{doc.width()}" y2="{y}" />'
y += height
svg += "</g></svg>"
node.addShapesFromSvg(svg)
def draw_hexagon_grid(self, node, doc, thickness, width, height):
# Pointy topped hex grid
# Horizontal spacing = width
# Vertical spacing = height * 0.75
svg = f'<svg><g fill="none" stroke="black" stroke-width="{thickness}">'
def draw_hexagon_grid(self, node, doc, thickness, width, height, color_hex):
svg = f'<svg><g fill="none" stroke="{color_hex}" stroke-width="{thickness}">'
v_spacing = height * 0.75
h_spacing = width
rows = int(doc.height() / v_spacing) + 2
cols = int(doc.width() / h_spacing) + 2
for r in range(rows):
offset_x = (width / 2) if (r % 2 == 1) else 0
for c in range(cols):
cx = c * h_spacing + offset_x
cy = r * v_spacing
# Vertices for pointy-topped hex
v = [
(cx, cy - height / 2),
(cx + width / 2, cy - height / 4),
@@ -186,9 +215,13 @@ class GridDialog(QDialog):
(cx - width / 2, cy + height / 4),
(cx - width / 2, cy - height / 4),
]
points = " ".join([f"{px},{py}" for px, py in v])
svg += f'<polygon points="{points}" />'
svg += "</g></svg>"
node.addShapesFromSvg(svg)
# Register the docker
Krita.instance().addDockWidgetFactory(
DockWidgetFactory(DOCKER_ID, DockWidgetFactoryBase.DockRight, GridDocker)
)
-21
View File
@@ -1,21 +0,0 @@
from krita import Extension
from .grid_dialog import GridDialog
class GridGenerator(Extension):
def __init__(self, parent):
super().__init__(parent)
def setup(self):
pass
def createActions(self, window):
action = window.createAction(
"grid_generator", "Grid Generator...", "tools/scripts"
)
action.triggered.connect(self.show_dialog)
def show_dialog(self):
dialog = GridDialog()
dialog.exec_()