box_generator_extension.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. pts_per_mm = 300 / 25.4
  80. length = length_mm * pts_per_mm
  81. height = height_mm * pts_per_mm
  82. width = width_mm * pts_per_mm
  83. # Create outline using SVG.
  84. if self.boxTypeInput.currentIndex() == 0: # Tuckbox
  85. total_length = length * 2 + height * 3
  86. total_width = width + height * 3
  87. leeway = pts_per_mm / 2 # Make certain flaps shorter by 0.5mm to account for paper thickness.
  88. stringy = f"""<svg style="stroke:black; fill:none; stroke-width:1">
  89. <path d="
  90. m {pts_per_mm+height*1.66}
  91. h {length-height*2*0.66}
  92. a {height*0.66} {height*0.66} 0 0 1 {height*0.66} {height*0.66}
  93. v {height}
  94. l {height*0.1} -{height}
  95. h {height*0.4}
  96. a {height*0.5} {height} 0 0 1 {height*0.5} {height}
  97. h {length+height-leeway}
  98. v {width}
  99. h -{height-leeway}
  100. v {height-leeway}
  101. h -{length}
  102. v -{height-leeway}
  103. l -{height*0.1} {height}
  104. h -{height*0.8}
  105. l -{height*0.1} -{height}
  106. v {height}
  107. h -{length}
  108. v -{height}
  109. l -{height*0.1} {height}
  110. h -{height*0.8}
  111. l -{height*0.1} -{height}
  112. v -{width}
  113. a {height*0.5} {height} 0 0 1 {height*0.5} -{height}
  114. h {height*0.4}
  115. l {height*0.1} {height}
  116. v -{height}
  117. a {height*0.66} {height*0.66} 0 0 1 {height*0.66} -{height*0.66}
  118. z
  119. "></path>
  120. <path d="
  121. M {pts_per_mm+height} {height*0.66}
  122. h -{pts_per_mm}
  123. M {pts_per_mm+height+length} {height*0.66}
  124. h {pts_per_mm}
  125. M 0 {height*1.66}
  126. h {pts_per_mm}
  127. M 0 {height*1.66+width}
  128. h {pts_per_mm}
  129. M {pts_per_mm+height*2+length*2} {height*1.66}
  130. v -{pts_per_mm}
  131. "></path>
  132. </svg>"""
  133. else: # Telescopic
  134. total_length = length + 5 * height
  135. total_width = width + 5 * height
  136. stringy = f"""<svg width="{total_length}" height="{total_width}" style="stroke:black; fill:none; stroke-width:1">
  137. <path d="
  138. m {height*3}
  139. h {length-height}
  140. l {height/2} {height/2}
  141. v {height}
  142. a {height} {height} 0 0 1 {height} {height}
  143. h {height}
  144. l {height/2} {height/2}
  145. v {width-height}
  146. l -{height/2} {height/2}
  147. h -{height}
  148. a {height} {height} 0 0 1 -{height} {height}
  149. v {height}
  150. l -{height/2} {height/2}
  151. h -{length-height}
  152. l -{height/2} -{height/2}
  153. v -{height}
  154. a {height} {height} 0 0 1 -{height} -{height}
  155. h -{height}
  156. l -{height/2} -{height/2}
  157. v -{width-height}
  158. l {height/2} -{height/2}
  159. h {height}
  160. a {height} {height} 0 0 1 {height} -{height}
  161. v -{height}
  162. Z
  163. "></path>
  164. </svg>"""
  165. layer.addShapesFromSvg(stringy)