box_generator_extension.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. from krita import *
  2. from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton
  3. from PyQt5.QtCore import *
  4. class BoxGenerator(Extension):
  5. def __init__(self, parent):
  6. super().__init__(parent)
  7. # Krita.instance() exists, so do any setup work
  8. def setup(self):
  9. pass
  10. # called after setup(self)
  11. def createActions(self, window):
  12. # Create menu item in Tools > Scripts.
  13. action = window.createAction("boxgen", "Box Generator")
  14. action.triggered.connect(self.box_generator)
  15. def box_generator(self):
  16. # Get the current selected layer, called a 'node'
  17. self.doc = Krita.instance().activeDocument()
  18. if not self.doc:
  19. # Create and show a new document (A4 300ppi).
  20. self.doc = Krita.instance().createDocument(3508, 2480, "", "RGBA", "U8", "", 300.0)
  21. Krita.instance().activeWindow().addView(self.doc)
  22. # Dialog creation.
  23. newDialog = QDialog()
  24. newDialog.setWindowTitle("Box Generator")
  25. # Description row.
  26. desc = QLabel('Creates outlines for a foldable box with lid.')
  27. desc.setAlignment(Qt.AlignCenter)
  28. row0 = QHBoxLayout()
  29. row0.addWidget(desc)
  30. # Dimension row.
  31. self.lengthInput = QLineEdit('67')
  32. self.widthInput = QLineEdit('93')
  33. self.heightInput = QLineEdit('20')
  34. self.unitInput = QComboBox()
  35. self.unitInput.addItems( ['mm', 'inch', 'px'] )
  36. row1 = QHBoxLayout()
  37. row1.addWidget(QLabel('Dimensions: L:'))
  38. row1.addWidget(self.lengthInput)
  39. row1.addWidget(QLabel(' x W:'))
  40. row1.addWidget(self.widthInput)
  41. row1.addWidget(QLabel(' x H:'))
  42. row1.addWidget(self.heightInput)
  43. row1.addWidget(self.unitInput)
  44. # Decision row.
  45. self.boxTypeInput = QComboBox()
  46. self.boxTypeInput.addItems( ['Tuckbox', 'Telescopic'] )
  47. row2 = QHBoxLayout()
  48. row2.addWidget(QLabel('Box Type:'))
  49. row2.addWidget(self.boxTypeInput)
  50. # Do It row.
  51. goButton = QPushButton("Create Box")
  52. goButton.setIcon( Krita.instance().icon('animation_play') )
  53. row3 = QHBoxLayout()
  54. row3.addWidget(goButton)
  55. layoutMain = QVBoxLayout()
  56. layoutMain.addLayout(row0)
  57. layoutMain.addLayout(row1)
  58. layoutMain.addLayout(row2)
  59. layoutMain.addLayout(row3)
  60. newDialog.setLayout(layoutMain)
  61. # hook up the actions.
  62. goButton.clicked.connect( self.generateBox )
  63. # self.unitInput.currentIndexChanged.connect( self.convertCount )
  64. # show the dialog.
  65. newDialog.exec_()
  66. ##########
  67. # Slots
  68. ##########
  69. # Actually generates the box!
  70. def generateBox(self, e):
  71. length_text = self.lengthInput.text()
  72. width_text = self.widthInput.text()
  73. height_text = self.heightInput.text()
  74. # Box dimensions in pixels.
  75. doc_ppi = self.doc.resolution()
  76. mm = doc_ppi/25.4
  77. multiplier = 1
  78. if self.unitInput.currentText() == "inch":
  79. multiplier = doc_ppi
  80. if self.unitInput.currentText() == "mm":
  81. multiplier = mm
  82. length = float(length_text) * multiplier
  83. height = float(height_text) * multiplier
  84. width = float(width_text) * multiplier
  85. layer = self.doc.createVectorLayer(f"""Box {length_text}x{width_text}x{height_text}""")
  86. root = self.doc.rootNode()
  87. root.addChildNode(layer, None)
  88. # Create outline using SVG (starts from top left corner).
  89. if self.boxTypeInput.currentIndex() == 0: # Tuckbox
  90. stringy = f"""<svg style="stroke:black; fill:none; stroke-width:1">
  91. <path d="
  92. m {1*mm+height*1.66}
  93. h {length-height*2*0.66}
  94. a {height*0.7} {height*0.7} 0 0 1 {height*0.66 - 0.7*mm} {height*0.66 - 0.25*mm}
  95. h -{4*mm}
  96. v {0.5*mm}
  97. h {4.7*mm}
  98. v {height - 0.25*mm}
  99. l {height*0.1} -{height}
  100. h {height*0.4}
  101. a {height*0.5} {height} 0 0 1 {height*0.5-0.25*mm} {height-3.5*mm}
  102. h {0.6*mm}
  103. v {3.5*mm}
  104. h {length*0.5-0.35*mm - 7*mm}
  105. a {7.3*mm} {7.3*mm} 0 0 0 {14*mm} 0
  106. h {length*0.5 - 7*mm}
  107. h {height-0.25*mm}
  108. v {width-0.25*mm}
  109. h -{height-0.25*mm}
  110. v {height-0.25*mm}
  111. h -{length}
  112. v -{height-0.5*mm}
  113. l -{height*0.1} {height}
  114. h -{height*0.8}
  115. l -{height*0.1} -{height}
  116. v {height}
  117. h -{length}
  118. v -{height}
  119. l -{height*0.1} {height}
  120. h -{height*0.8}
  121. l -{height*0.1} -{height}
  122. v -{width}
  123. h -{0.25*mm}
  124. v -{3.5*mm}
  125. h {0.5*mm}
  126. a {height*0.5} {height} 0 0 1 {height*0.5-0.25*mm} -{height-3.5*mm}
  127. h {height*0.4}
  128. l {height*0.1} {height}
  129. v -{height - 0.25*mm}
  130. h {4.7*mm}
  131. v -{0.5*mm}
  132. h -{4*mm}
  133. a {height*0.7} {height*0.7} 0 0 1 {height*0.66 - 0.7*mm} -{height*0.66 - 0.25*mm}
  134. z
  135. "></path>
  136. <path d="
  137. M {1*mm+height} {height*0.66 + 0.25*mm}
  138. h -{1*mm}
  139. M {1*mm+height+length} {height*0.66 + 0.25*mm}
  140. h {1*mm}
  141. M 0 {height*1.66}
  142. h {1*mm}
  143. M 0 {height*1.66+width}
  144. h {1*mm}
  145. M {1*mm+height*2+length*2} {height*1.66}
  146. v -{1*mm}
  147. M {1*mm+height*2+length*2} {height*1.66+width}
  148. h {1*mm}
  149. M {1*mm} {height*1.66 - 3.5*mm}
  150. v -{1*mm}
  151. M {1*mm+height*2+length} {height*1.66 - 3.5*mm}
  152. v -{1*mm}
  153. M {1*mm+height*2+length} {height*1.66}
  154. h {0.35*mm}
  155. "></path>
  156. <rect x="{1*mm+height*2+length+2.5*mm}"
  157. y="{height*1.66+width+2.5*mm}" width="{length-5*mm}" height="{height-0.5*mm - 3*mm}"></rect>
  158. <rect x="{1*mm+height*2+length*2+2.5*mm}" y="{height*1.66+2.5*mm}" width="{height-0.25*mm - 3*mm}" height="{width-5*mm}"></rect>
  159. </svg>"""
  160. else: # Telescopic
  161. total_length = length + 5 * height
  162. total_width = width + 5 * height
  163. stringy = f"""<svg width="{total_length}" height="{total_width}" style="stroke:black; fill:none; stroke-width:1">
  164. <path d="
  165. m {height*3}
  166. h {length-height}
  167. l {height/2} {height/2}
  168. v {height}
  169. a {height} {height} 0 0 1 {height} {height}
  170. h {height}
  171. l {height/2} {height/2}
  172. v {width-height}
  173. l -{height/2} {height/2}
  174. h -{height}
  175. a {height} {height} 0 0 1 -{height} {height}
  176. v {height}
  177. l -{height/2} {height/2}
  178. h -{length-height}
  179. l -{height/2} -{height/2}
  180. v -{height}
  181. a {height} {height} 0 0 1 -{height} -{height}
  182. h -{height}
  183. l -{height/2} -{height/2}
  184. v -{width-height}
  185. l {height/2} -{height/2}
  186. h {height}
  187. a {height} {height} 0 0 1 {height} -{height}
  188. v -{height}
  189. Z
  190. "></path>
  191. </svg>"""
  192. layer.addShapesFromSvg(stringy)