blackpiboard/piboard.py

316 lines
12 KiB
Python
Executable File

#!/usr/bin/env python2
# -*- coding: utf8 -*-
# Code modified by Phyks
# Date: December 2013
# License:
# ========
# I don't give a damn to anything you can do using this code (but please, tell
# me if you do something cool :).
# It would just be nice to quote where the original code comes from.
# Original code written by: QuantumPhysics
# Found here: http://compsci.ca/v3/viewtopic.php?t=32343
# Date Written: 10/06/12
import wx
import os
def int_of_string(s):
try:
return int(s)
except ValueError:
return 0
def next_filename():
return ("boards/"+str(max([int_of_string(i.strip(".jpg")) for i in
os.listdir('boards/') or ['0'] if not os.path.isdir(i)]
) + 1)+".jpg")
class PaintWindow(wx.Window):
# array of colors available to draw
colours = ['Black', 'White', 'Yellow', 'Red', 'Green', 'Blue', 'Purple',
'Brown', 'Aquamarine', 'Forest Green', 'Light Blue', 'Goldenrod',
'Cyan', 'Orange', 'Navy', 'Light Grey', 'ClearScreen']
# color quantity
thicknesses = [1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128]
def __init__(self, parent):
# creates paint window
super(PaintWindow, self).__init__(parent,
style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.initDrawing()
self.makeMenu()
# binds key_down and up events
self.bindEvents()
self.initBuffer()
size = parent.GetSize()
self.button_exit = wx.Button(self, id=-1, label='Exit',
pos=(size[0]-125, size[1]-75),
size=(100, 50))
self.button_exit.Bind(wx.EVT_BUTTON, self.button_exit_handle)
self.button_exit.SetToolTip(wx.ToolTip("Click to exit"))
self.button_clear = wx.Button(self, id=-1, label='Clear',
pos=(size[0]-125, 25),
size=(100, 50))
self.button_clear.Bind(wx.EVT_BUTTON, self.button_clear_handle)
self.button_clear.SetToolTip(wx.ToolTip("Click to clear"))
self.button_save = wx.Button(self, id=-1, label='Save',
pos=(size[0]-250, 25),
size=(100, 50))
self.button_save.Bind(wx.EVT_BUTTON, self.button_save_handle)
self.button_save.SetToolTip(wx.ToolTip("Click to save"))
def initDrawing(self):
self.SetBackgroundColour('WHITE')
self.currentThickness = self.thicknesses[0]
self.currentColour = self.colours[0]
self.lines = []
self.previousPosition = (0, 0)
def bindEvents(self):
pnl = wx.Panel(self)
pnl.Bind(wx.EVT_KEY_DOWN, self.onKeyPress)
pnl.SetSize((0, 0))
pnl.SetFocus()
for event, handler in [
# creates bind event for left button down
(wx.EVT_LEFT_DOWN, self.onLeftDown),
# creates bind event once left button is released
(wx.EVT_LEFT_UP, self.onLeftUp),
# creates bind event for drawing (moving cursor)
(wx.EVT_MOTION, self.onMotion),
# creates bind event for right button up
(wx.EVT_RIGHT_UP, self.onRightUp),
(wx.EVT_SIZE, self.onSize),
(wx.EVT_IDLE, self.onIdle),
(wx.EVT_PAINT, self.onPaint)]:
self.Bind(event, handler)
def initBuffer(self):
# gets size of window
size = self.GetClientSize()
# sets window to empty canvas .bmp x-width, y-height
self.buffer = wx.EmptyBitmap(size.width, size.height)
dc = wx.BufferedDC(None, self.buffer)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
self.drawLines(dc, *self.lines)
self.reInitBuffer = False
def makeMenu(self):
# creates menu on right click
self.menu = wx.Menu()
# sets selection for items (colors) in the runtime window on right click
self.idToColourMap = self.addCheckableMenuItems(self.menu,
self.colours)
# updates screen once a new color is selected
self.bindMenuEvents(menuHandler=self.onMenuSetColour,
updateUIHandler=self.onCheckMenuColours,
ids=self.idToColourMap.keys())
self.menu.Break()
self.idToThicknessMap = self.addCheckableMenuItems(self.menu,
self.thicknesses)
self.bindMenuEvents(menuHandler=self.onMenuSetThickness,
updateUIHandler=self.onCheckMenuThickness,
ids=self.idToThicknessMap.keys())
# adds a static surpressor to conditions
@staticmethod
def addCheckableMenuItems(menu, items):
idToItemMapping = {}
for item in items:
menuId = wx.NewId()
idToItemMapping[menuId] = item
menu.Append(menuId, str(item), kind=wx.ITEM_CHECK)
return idToItemMapping
def bindMenuEvents(self, menuHandler, updateUIHandler, ids):
sortedIds = sorted(ids)
firstId, lastId = sortedIds[0], sortedIds[-1]
for event, handler in \
[(wx.EVT_MENU_RANGE, menuHandler),
(wx.EVT_UPDATE_UI_RANGE, updateUIHandler)]:
self.Bind(event, handler, id=firstId, id2=lastId)
def button_exit_handle(self, event):
self.menu.Destroy()
self.Destroy()
wx.App.ExitMainLoop(app)
def button_clear_handle(self, event):
self.button_exit.Destroy()
self.button_clear.Destroy()
self.button_save.Destroy()
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
dc.Clear()
size = self.GetSize()
self.button_exit = wx.Button(self, id=-1, label='Exit',
pos=(size[0]-125, size[1]-75),
size=(100, 50))
self.button_exit.Bind(wx.EVT_BUTTON, self.button_exit_handle)
self.button_exit.SetToolTip(wx.ToolTip("Click to exit"))
self.button_clear = wx.Button(self, id=-1, label='Clear',
pos=(size[0]-125, 25),
size=(100, 50))
self.button_clear.Bind(wx.EVT_BUTTON, self.button_clear_handle)
self.button_clear.SetToolTip(wx.ToolTip("Click to clear"))
self.button_save = wx.Button(self, id=-1, label='Save',
pos=(size[0]-250, 25),
size=(100, 50))
self.button_save.Bind(wx.EVT_BUTTON, self.button_save_handle)
self.button_save.SetToolTip(wx.ToolTip("Click to save"))
def button_save_handle(self, event):
self.button_exit.Destroy()
self.button_clear.Destroy()
self.button_save.Destroy()
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
image = dc.GetAsBitmap()
image.SaveFile(next_filename(), wx.BITMAP_TYPE_JPEG)
size = self.GetSize()
self.button_exit = wx.Button(self, id=-1, label='Exit',
pos=(size[0]-125, size[1]-75),
size=(100, 50))
self.button_exit.Bind(wx.EVT_BUTTON, self.button_exit_handle)
self.button_exit.SetToolTip(wx.ToolTip("Click to exit"))
self.button_clear = wx.Button(self, id=-1, label='Clear',
pos=(size[0]-125, 25),
size=(100, 50))
self.button_clear.Bind(wx.EVT_BUTTON, self.button_clear_handle)
self.button_clear.SetToolTip(wx.ToolTip("Click to clear"))
self.button_save = wx.Button(self, id=-1, label='Save',
pos=(size[0]-250, 25),
size=(100, 50))
self.button_save.Bind(wx.EVT_BUTTON, self.button_save_handle)
self.button_save.SetToolTip(wx.ToolTip("Click to save"))
def onLeftDown(self, event):
# draw line
self.currentLine = []
self.previousPosition = event.GetPositionTuple()
self.CaptureMouse()
self.button_exit.Destroy()
self.button_clear.Destroy()
self.button_save.Destroy()
def onLeftUp(self, event):
# close motion, stop drawing, wait for event
if self.HasCapture():
self.lines.append((self.currentColour, self.currentThickness,
self.currentLine))
self.currentLine = []
self.ReleaseMouse()
size = self.GetSize()
self.button_exit = wx.Button(self, id=-1, label='Exit',
pos=(size[0]-125, size[1]-75),
size=(100, 50))
self.button_exit.Bind(wx.EVT_BUTTON, self.button_exit_handle)
self.button_exit.SetToolTip(wx.ToolTip("Click to exit"))
self.button_clear = wx.Button(self, id=-1, label='Clear',
pos=(size[0]-125, 25),
size=(100, 50))
self.button_clear.Bind(wx.EVT_BUTTON, self.button_clear_handle)
self.button_clear.SetToolTip(wx.ToolTip("Click to clear"))
self.button_save = wx.Button(self, id=-1, label='Save',
pos=(size[0]-250, 25),
size=(100, 50))
self.button_save.Bind(wx.EVT_BUTTON, self.button_save_handle)
self.button_save.SetToolTip(wx.ToolTip("Click to save"))
def onKeyPress(self, event):
# If q key is pressed, exit
keycode = event.GetKeyCode()
if event.GetKeyCode() == wx.WXK_ESCAPE:
ret = wx.MessageBox('Are you sure to quit?', 'Question',
wx.YES_NO | wx.NO_DEFAULT, self)
if ret == wx.YES:
self.menu.Destroy()
self.Destroy()
wx.App.ExitMainLoop(app)
else:
event.Skip()
def onRightUp(self, event):
# if right button is clicked then make wx.menu to select colors
self.PopupMenu(self.menu)
def onMotion(self, event):
if event.Dragging() and event.LeftIsDown():
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
currentPosition = event.GetPositionTuple()
lineSegment = self.previousPosition + currentPosition
self.drawLines(dc, (self.currentColour, self.currentThickness,
[lineSegment]))
self.currentLine.append(lineSegment)
self.previousPosition = currentPosition
def onSize(self, event):
self.reInitBuffer = True
def onIdle(self, event):
if self.reInitBuffer:
self.initBuffer()
self.Refresh(False)
def onPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer)
def onCheckMenuColours(self, event):
colour = self.idToColourMap[event.GetId()]
event.Check(colour == self.currentColour)
def onCheckMenuThickness(self, event):
thickness = self.idToThicknessMap[event.GetId()]
event.Check(thickness == self.currentThickness)
def onMenuSetColour(self, event):
self.currentColour = self.idToColourMap[event.GetId()]
def onMenuSetThickness(self, event):
self.currentThickness = self.idToThicknessMap[event.GetId()]
@staticmethod
def drawLines(dc, *lines):
dc.BeginDrawing()
for colour, thickness, lineSegments in lines:
pen = wx.Pen(wx.NamedColour(colour), thickness, wx.SOLID)
dc.SetPen(pen)
for lineSegment in lineSegments:
dc.DrawLine(*lineSegment)
dc.EndDrawing()
class PaintFrame(wx.Frame):
def __init__(self, parent=None):
size = wx.GetDisplaySize()
super(PaintFrame, self).__init__(parent, title="Black PiBoard",
size=size,
style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
doodle = PaintWindow(self)
if __name__ == '__main__':
app = wx.App()
frame = PaintFrame()
frame.Show()
frame.ShowFullScreen(True, wx.FULLSCREEN_ALL)
cursor = wx.StockCursor(wx.CURSOR_PENCIL)
frame.SetCursor(cursor)
app.MainLoop()