#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
import cairo

class App(Gtk.Window):
    def __init__(self):
        super().__init__(title='Sketch Pad')
        self.set_default_size(700, 560)
        self.drawing = False
        self.last_x = self.last_y = 0
        self.color = (0, 0, 0)
        self.brush = 3.0
        self.surface = None
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
        vbox.set_margin_top(4); vbox.set_margin_bottom(4)
        vbox.set_margin_start(4); vbox.set_margin_end(4)
        self.add(vbox)
        toolbar = Gtk.Box(spacing=8)
        # color button
        self.color_btn = Gtk.ColorButton()
        self.color_btn.set_rgba(Gdk.RGBA(0,0,0,1))
        self.color_btn.connect('color-set', self.set_color)
        toolbar.pack_start(self.color_btn, False, False, 0)
        # brush size
        toolbar.add(Gtk.Label(label='Brush:'))
        self.brush_spin = Gtk.SpinButton.new_with_range(1, 50, 1)
        self.brush_spin.set_value(3)
        self.brush_spin.connect('value-changed', lambda s: setattr(self, 'brush', s.get_value()))
        toolbar.pack_start(self.brush_spin, False, False, 0)
        # clear
        clear = Gtk.Button(label='Clear')
        clear.connect('clicked', self.clear)
        toolbar.pack_start(clear, False, False, 0)
        vbox.pack_start(toolbar, False, False, 0)
        self.da = Gtk.DrawingArea()
        self.da.connect('draw', self.draw)
        self.da.connect('button-press-event', self.press)
        self.da.connect('button-release-event', self.release)
        self.da.connect('motion-notify-event', self.motion)
        self.da.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
                           Gdk.EventMask.BUTTON_RELEASE_MASK |
                           Gdk.EventMask.POINTER_MOTION_MASK)
        vbox.pack_start(self.da, True, True, 0)
    def set_color(self, btn):
        rgba = btn.get_rgba()
        self.color = (rgba.red, rgba.green, rgba.blue)
    def ensure_surface(self):
        if not self.surface:
            alloc = self.da.get_allocation()
            self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, alloc.width, alloc.height)
            cr = cairo.Context(self.surface)
            cr.set_source_rgb(1,1,1); cr.paint()
    def press(self, w, e):
        self.ensure_surface()
        self.drawing = True; self.last_x = e.x; self.last_y = e.y
    def release(self, w, e): self.drawing = False
    def motion(self, w, e):
        if not self.drawing or not self.surface: return
        cr = cairo.Context(self.surface)
        cr.set_source_rgb(*self.color)
        cr.set_line_width(self.brush)
        cr.set_line_cap(cairo.LINE_CAP_ROUND)
        cr.move_to(self.last_x, self.last_y)
        cr.line_to(e.x, e.y)
        cr.stroke()
        self.last_x = e.x; self.last_y = e.y
        self.da.queue_draw()
    def draw(self, w, cr):
        self.ensure_surface()
        cr.set_source_surface(self.surface, 0, 0)
        cr.paint()
    def clear(self, *_):
        if self.surface:
            cr = cairo.Context(self.surface)
            cr.set_source_rgb(1,1,1); cr.paint()
            self.da.queue_draw()

win = App()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
