box_generator_extension.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. layer = self.doc.createVectorLayer("Box")
  72. root = self.doc.rootNode()
  73. root.addChildNode(layer, None)
  74. # Get dimensions in points. Points to mm conversion depends on document DPI.
  75. length_mm = float(self.lengthInput.text())
  76. width_mm = float(self.widthInput.text())
  77. height_mm = float(self.heightInput.text())
  78. # Assume input is in mm.
  79. mm = 300 / 25.4
  80. length = length_mm * mm
  81. height = height_mm * mm
  82. width = width_mm * mm
  83. # Create outline using SVG (starts from top left corner).
  84. if self.boxTypeInput.currentIndex() == 0: # Tuckbox
  85. stringy = f"""<svg style="stroke:black; fill:none; stroke-width:1">
  86. <path d="
  87. m {1*mm+height*1.66}
  88. h {length-height*2*0.66}
  89. a {height*0.7} {height*0.7} 0 0 1 {height*0.66 - 0.7*mm} {height*0.66 - 0.25*mm}
  90. h -{4*mm}
  91. v {0.5*mm}
  92. h {4.7*mm}
  93. v {height - 0.25*mm}
  94. l {height*0.1} -{height}
  95. h {height*0.4}
  96. a {height*0.5} {height} 0 0 1 {height*0.5-0.25*mm} {height-3.5*mm}
  97. h {0.5*mm}
  98. v {3.5*mm}
  99. h {length+height-0.5*mm}
  100. v {width-0.25*mm}
  101. h -{height-0.25*mm}
  102. v {height-0.25*mm}
  103. h -{length}
  104. v -{height-0.5*mm}
  105. l -{height*0.1} {height}
  106. h -{height*0.8}
  107. l -{height*0.1} -{height}
  108. v {height}
  109. h -{length}
  110. v -{height}
  111. l -{height*0.1} {height}
  112. h -{height*0.8}
  113. l -{height*0.1} -{height}
  114. v -{width}
  115. h -{0.25*mm}
  116. v -{3.5*mm}
  117. h {0.5*mm}
  118. a {height*0.5} {height} 0 0 1 {height*0.5-0.25*mm} -{height-3.5*mm}
  119. h {height*0.4}
  120. l {height*0.1} {height}
  121. v -{height - 0.25*mm}
  122. h {4.7*mm}
  123. v -{0.5*mm}
  124. h -{4*mm}
  125. a {height*0.7} {height*0.7} 0 0 1 {height*0.66 - 0.7*mm} -{height*0.66 - 0.25*mm}
  126. z
  127. "></path>
  128. <path d="
  129. M {1*mm+height} {height*0.66 + 0.25*mm}
  130. h -{1*mm}
  131. M {1*mm+height+length} {height*0.66 + 0.25*mm}
  132. h {1*mm}
  133. M 0 {height*1.66}
  134. h {1*mm}
  135. M 0 {height*1.66+width}
  136. h {1*mm}
  137. M {1*mm+height*2+length*2} {height*1.66}
  138. v -{1*mm}
  139. M {1*mm+height*2+length*2} {height*1.66+width}
  140. h {1*mm}
  141. M {1*mm} {height*1.66 - 3.5*mm}
  142. v -{1*mm}
  143. M {1*mm+height*2+length} {height*1.66 - 3.5*mm}
  144. v -{1*mm}
  145. M {1*mm+height*2+length} {height*1.66}
  146. h {0.25*mm}
  147. "></path>
  148. </svg>"""
  149. else: # Telescopic
  150. total_length = length + 5 * height
  151. total_width = width + 5 * height
  152. stringy = f"""<svg width="{total_length}" height="{total_width}" style="stroke:black; fill:none; stroke-width:1">
  153. <path d="
  154. m {height*3}
  155. h {length-height}
  156. l {height/2} {height/2}
  157. v {height}
  158. a {height} {height} 0 0 1 {height} {height}
  159. h {height}
  160. l {height/2} {height/2}
  161. v {width-height}
  162. l -{height/2} {height/2}
  163. h -{height}
  164. a {height} {height} 0 0 1 -{height} {height}
  165. v {height}
  166. l -{height/2} {height/2}
  167. h -{length-height}
  168. l -{height/2} -{height/2}
  169. v -{height}
  170. a {height} {height} 0 0 1 -{height} -{height}
  171. h -{height}
  172. l -{height/2} -{height/2}
  173. v -{width-height}
  174. l {height/2} -{height/2}
  175. h {height}
  176. a {height} {height} 0 0 1 {height} -{height}
  177. v -{height}
  178. Z
  179. "></path>
  180. </svg>"""
  181. layer.addShapesFromSvg(stringy)