11import sys
22from random import randint
3-
4- from PyQt5 .QtCore import QPoint , Qt
3+ from PyQt5 .QtCore import QPoint , Qt , QThread , pyqtSignal
54from PyQt5 .QtGui import (QColor , QCursor , QIcon , QImage , QPainter ,
6- QPen , QPixmap , QBrush )
5+ QPen , QPixmap )
76from PyQt5 .QtWidgets import (QAction , QApplication , QFileDialog ,
87 QMainWindow , QPushButton ,)
98
@@ -19,6 +18,15 @@ def paintEvent(self, event):
1918 # do normal stuff ...
2019"""
2120
21+ SoundEffects = {
22+ 'pen break' : r'Sounds/pen break.mp3' ,
23+ 'pen write' : r'Sounds/pen writing.wav' ,
24+ 'fill bucket' : r'Sounds/fill bucket.mp3' ,
25+ 'empty bucket' : r'Sounds/empty bucket.mp3' ,
26+ 'solid hitting' : r'Sounds/solidified hitting.m4a' ,
27+ 'straggly brush' : r'Sounds/straggly brushing.m4a'
28+ }
29+
2230
2331class ColorBox (QMainWindow ):
2432 """ This window holds all the color pallettes"""
@@ -28,8 +36,8 @@ def __init__(self, parent=None):
2836 super ().__init__ (parent )
2937 ColorBox .objs .append (self )
3038 self .toolsX = 5
31- self .toolsY = 0
32- self .tools_holder = 1
39+ self .toolsY = 5
40+ self .tools_holder = 0
3341 self .exists = True
3442 self .Setup ()
3543 # TODO MINOR: can open as many windows as one desires
@@ -39,16 +47,15 @@ def Setup(self):
3947 self .setWindowTitle ('Colorbox' )
4048 self .setFixedSize (150 , 300 )
4149
42- # TODO EXTRA: make this into one vertical line of colors
4350 def addPallette (self , pallet ):
4451 pallet .setGeometry (self .toolsX , self .toolsY , 40 , 40 )
4552 self .layout ().addWidget (pallet )
4653 self .toolsX += 50
4754 self .tools_holder += 1
48- if self .tools_holder == 4 :
55+ if self .tools_holder == 3 :
4956 self .toolsX = 5
5057 self .toolsY += 50
51- self .tools_holder = 1
58+ self .tools_holder = 0
5259
5360 def showColorBox (self ):
5461 self .show ()
@@ -114,7 +121,7 @@ def create_button(self):
114121 tool_btn .setShortcut (self .shortcut )
115122 tool_btn .setStatusTip (self .statusTip )
116123 tool_btn .triggered .connect (
117- lambda : self .PaintBoard .connectTool (self )
124+ lambda : self .PaintBoard .connectTool (self , curisDipped = self . isDipped )
118125 )
119126 self .PaintBoard .toolbar .addAction (tool_btn )
120127
@@ -132,7 +139,6 @@ def __init__(self, parentBtn):
132139 self .timesToUse = randint (10 , 20 )
133140 # TODO: pallette will become empty after being used X amount of times
134141
135-
136142 def mixColor (self , tool ):
137143 """Mixes colors from tool holding the color
138144 NO COLOR IN TOOL: Pick up color pallette color
@@ -154,7 +160,7 @@ def mixColor(self, tool):
154160 ]
155161 )
156162
157- if ( colorSum and tool .color .alpha () and self .alpha ) :
163+ if colorSum and tool .color .alpha () and self .alpha :
158164 # self.alpha so that color pallette is not empty
159165 self .r = (self .r + tool .color .red ()) // 2
160166 self .g = (self .g + tool .color .green ()) // 2
@@ -163,17 +169,18 @@ def mixColor(self, tool):
163169 self .r = (self .r + tool .color .red ()) // 4
164170 self .g = (self .g + tool .color .green ()) // 4
165171 self .b = (self .b + tool .color .blue ()) // 4
166- elif not sum ((self .r , self .g , self .b , self .alpha )): pass
172+ elif not sum ((self .r , self .g , self .b , self .alpha )):
173+ pass
167174
168175 self .palletteColor = (self .r , self .g , self .b , self .alpha )
169176 tool .color = QColor (self .r , self .g , self .b , self .alpha )
170177
171- if tool .toolName in ["Straggly PaintBrush" ,
172- "Solid Brush" ]:
178+ if tool .toolName == "Straggly PaintBrush" or "Solid Brush" :
173179 tool .opacityDuration = 1
174180 tool .isDipped = True
175- elif "A bucket" in tool . toolName and self .alpha :
181+ elif tool . toolName == "A bucket" and self .alpha :
176182 """The pallette gets emptied """
183+ print ('bucket selected' )
177184 self .r = 0
178185 self .g = 0
179186 self .b = 0
@@ -205,7 +212,7 @@ def Setup(self):
205212 self .connectTool ()
206213 self .painter = QPainter (self .canvas )
207214
208- ## MENUBARS ##
215+ # MENUBARS
209216 mainMenu = self .menuBar ()
210217
211218 fileMenu = mainMenu .addMenu ('File' )
@@ -238,7 +245,7 @@ def Setup(self):
238245 save_file_action .triggered .connect (self .saveFile )
239246 exit_action .triggered .connect (self .exit )
240247
241- ## TOOLBAR AND WITH TOOL ICONS ##
248+ # TOOLBAR AND WITH TOOL ICONS
242249
243250 self .toolbar = self .addToolBar ("Toolbar" )
244251 self .toolbar .setStyleSheet ('background-color: white' )
@@ -279,25 +286,27 @@ def Setup(self):
279286 )
280287
281288 self .sunbathing_eraser = Tool ("Sunbathing Eraser" , 10 , Qt .white ,
282- [0 , 0 , 0 , 0.0 ], self , "Design/icons/Sunbathing Eraser" ,
289+ [0 , 0 , 0 , 0.0 ], self , "Design/icons/Sunbathing Eraser" ,
283290 "Ctrl+F" ,
284- "Erase Your Mistakes, Kid!" ,
285- (99999 , 99999 )) # infinte duration
291+ "Erase Your Mistakes, Kid!" ,
292+ (99999 , 99999 )) # infinte duration
286293
287294 self .show ()
288295
289296 self .drawing = False
290297 self .lastPoint = QPoint ()
291298
292- def connectTool (self , curTool = None ):
299+ def connectTool (self , curTool = None , curisDipped = False ):
293300
294301 self .currentTool = curTool
295302
296303 try :
297304 self .currentTool .duration
305+ self .currentTool .isDipped
298306 except AttributeError :
299307 pass
300308 else :
309+ self .currentTool .isDipped = curisDipped
301310 if self .currentTool .toolName == "Pointy Pen" :
302311 self .currentTool .duration = randint (0 ,
303312 self .currentTool .constDuration )
@@ -309,7 +318,12 @@ def connectTool(self, curTool=None):
309318 else None
310319 )
311320 )))
312-
321+ if self .currentTool is not None :
322+ if self .currentTool .toolName != "Pointy Pen" or "A bucket" or "Sunbathing Eraser" \
323+ and self .currentTool .isDipped :
324+ self .dripper = DripperEffect (self .currentTool .color , self .currentTool .brushSize )
325+ self .dripper .drip .connect (self .DripperHandler )
326+ self .dripper .start ()
313327
314328 def colorBoxRun (self ):
315329
@@ -319,7 +333,10 @@ def colorBoxRun(self):
319333 geo .moveLeft (geo .right ()) # moves window right
320334 self .colorBox .setGeometry (geo )
321335
322- p1 , p2 , p3 , p4 , p5 , p6 ,p7 ,p8 ,p9 ,p10 ,p11 ,p12 = (QPushButton () for _ in range (12 ))
336+ p1 , p2 , p3 , p4 , p5 ,\
337+ p6 , p7 , p8 , p9 , p10 ,\
338+ p11 , p12 , p13 , p14 ,\
339+ p15 , p16 , p17 , p18 = (QPushButton () for _ in range (18 ))
323340
324341 c1 = PalletteButton (p1 )
325342 c2 = PalletteButton (p2 )
@@ -333,6 +350,12 @@ def colorBoxRun(self):
333350 c10 = PalletteButton (p10 )
334351 c11 = PalletteButton (p11 )
335352 c12 = PalletteButton (p12 )
353+ c13 = PalletteButton (p13 )
354+ c14 = PalletteButton (p14 )
355+ c15 = PalletteButton (p15 )
356+ c16 = PalletteButton (p16 )
357+ c17 = PalletteButton (p17 )
358+ c18 = PalletteButton (p18 )
336359
337360 p1 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
338361 .format (c1 .palletteColor ))
@@ -382,32 +405,57 @@ def colorBoxRun(self):
382405 .format (c12 .palletteColor ))
383406 p12 .clicked .connect (lambda : c12 .mixColor (self .currentTool ))
384407 self .colorBox .addPallette (p12 )
385-
408+ p13 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
409+ .format (c13 .palletteColor ))
410+ p13 .clicked .connect (lambda : c13 .mixColor (self .currentTool ))
411+ self .colorBox .addPallette (p13 )
412+ p14 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
413+ .format (c14 .palletteColor ))
414+ p14 .clicked .connect (lambda : c14 .mixColor (self .currentTool ))
415+ self .colorBox .addPallette (p14 )
416+ p15 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
417+ .format (c15 .palletteColor ))
418+ p15 .clicked .connect (lambda : c15 .mixColor (self .currentTool ))
419+ self .colorBox .addPallette (p15 )
420+ p16 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
421+ .format (c16 .palletteColor ))
422+ p16 .clicked .connect (lambda : c16 .mixColor (self .currentTool ))
423+ self .colorBox .addPallette (p16 )
424+ p17 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
425+ .format (c17 .palletteColor ))
426+ p17 .clicked .connect (lambda : c17 .mixColor (self .currentTool ))
427+ self .colorBox .addPallette (p17 )
428+ p18 .setStyleSheet ("background-color: rgba{0}; border-radius:20px"
429+ .format (c18 .palletteColor ))
430+ p18 .clicked .connect (lambda : c18 .mixColor (self .currentTool ))
431+ self .colorBox .addPallette (p18 )
386432
387433 # showing toolBox
388434 self .colorBox .showColorBox ()
389435
436+ def DripperHandler (self , result ):
437+ Dripper = result
438+ print ('drip' )
439+ self .painter .setPen (Dripper )
440+ self .painter .drawLine (self .lastPoint , self .lastPoint )
441+
390442 def mousePressEvent (self , event ):
391443 if event .button () == Qt .LeftButton and \
392444 self .currentTool is not None :
393445 self .drawing = True
394446 if self .currentTool .toolName == "A bucket filled" \
395447 and self .currentTool .duration >= 0 :
396- Pen = QPen (self .currentTool .color )
448+ print (self .currentTool .toolName )
449+ Pen = QPen ()
450+ Pen .setColor (self .currentTool .color )
397451 Pen .setWidth (self .currentTool .brushSize )
398452 self .painter .setPen (Pen )
399453 self .painter .drawEllipse (event .pos (), 100 , 150 )
400454 self .currentTool .duration -= 1
401455 self .currentTool .toolName = "A bucket"
402- self .currentTool .color = QColor (0 ,0 , 0 , 0 )
456+ self .currentTool .color = QColor (0 , 0 , 0 , 0 )
403457 self .connectTool (self .currentTool )
404- elif self .currentTool .toolName == "Solid Brush" \
405- and self .currentTool .duration >= 0 :
406- Pen = QPen (self .currentTool .color )
407- Pen .setWidth (self .currentTool .brushSize )
408- self .painter .setPen (Pen ) #TODO: doesn't work properly
409- self .painter .drawRect (event .pos (), 25 , 10 )
410- self .currentTool .duration -= 1
458+ print ('used bucket' )
411459
412460 self .lastPoint = event .pos ()
413461 self .update ()
@@ -426,20 +474,34 @@ def mouseMoveEvent(self, event):
426474 else :
427475 self .currentTool .duration -= 0.1
428476 if "Brush" in self .currentTool .toolName :
429- self .currentTool .opacityDuration -= 0.0125
430- #TODO EXTRA: find more fitting duration time
477+ self .currentTool .opacityDuration -= 0.0125
478+ # TODO EXTRA: find more fitting duration time
431479 # perhaps divide in class object
432480
481+ # this here is to add more realism to the point when its breaking
482+ if self .currentTool .duration <= 0.5 and self .currentTool .toolName == "Pointy Pen" :
483+ broken_pen = QPen ()
484+ broken_pen .setCapStyle (Qt .RoundCap )
485+ broken_pen .setJoinStyle (Qt .MiterJoin )
486+ broken_pen .setWidth (1 )
487+ broken_pen .setColor (self .currentTool .color )
488+ broken_pen .setDashPattern ([25 , 50 , 25 , 50 ])
489+ broken_pen .setStyle (Qt .DashDotDotLine )
490+ self .painter .setPen (broken_pen )
491+ self .painter .drawLine (self .lastPoint + QPoint (randint (10 , 15 ), randint (1 , 5 )),
492+ self .lastPoint + QPoint (randint (5 , 10 ), randint (1 , 10 )))
493+
433494 if self .currentTool .toolName == "Pointy Pen" :
495+ # QSound(SoundEffects['pen write']).play()
434496 Pen .setCapStyle (Qt .RoundCap )
435497 Pen .setJoinStyle (Qt .MiterJoin )
436- elif "Brush" in self .currentTool .toolName :
437- if self .currentTool .toolName == "Straggly Paintbrush" :
438- # TODO: this should more be like a brush
498+ elif self .currentTool .toolName == 'Straggly Paintbrush' or 'Solid Brush' :
499+ if self .currentTool .toolName == "Solid Brush" :
500+ Pen .setCapStyle (Qt .RoundCap )
501+ Pen .setJoinStyle (Qt .BevelJoin )
502+ else :
439503 Pen .setCapStyle (Qt .SquareCap )
440504 Pen .setJoinStyle (Qt .MiterJoin )
441- else :
442- pass
443505 Pen .setColor (self .currentTool .color )
444506 Pen .setWidth (self .currentTool .brushSize )
445507
@@ -449,11 +511,11 @@ def mouseMoveEvent(self, event):
449511 if self .currentTool .toolName == "Pointy Pen" :
450512 self .setCursor (QCursor (
451513 QPixmap ("Design/icons/Pointy Pen Broken.png" )))
514+ # QSound(SoundEffects['pen break']).play()
452515
453516 self .painter .drawLine (self .lastPoint , event .pos ())
454517 self .lastPoint = event .pos ()
455- self .update ()
456-
518+ self .update ()
457519 else :
458520 return None
459521
@@ -507,6 +569,28 @@ def exit(self):
507569 raise SystemExit
508570
509571
572+ class DripperEffect (QThread ):
573+ drip = pyqtSignal (object )
574+
575+ def __init__ (self , color , size ):
576+ QThread .__init__ (self )
577+ self .color = color
578+ self .size = size
579+
580+ def run (self ):
581+ drip_chance = randint (0 , 1 )
582+ if drip_chance == 1 :
583+ Drip = QPen ()
584+ Drip .setWidth (self .size )
585+ Drip .setStyle (Qt .DotLine )
586+ Drip .setColor (self .color )
587+ Drip .setJoinStyle (Qt .RoundJoin )
588+ Drip .setCapStyle (Qt .RoundCap )
589+ self .drip .emit (Drip )
590+ else :
591+ pass
592+
593+
510594if __name__ == '__main__' :
511595 app = QApplication (sys .argv )
512596 app .setStyleSheet ("QMainWindow{background-color:white}" )
0 commit comments