From: Neil Brown Date: Sun, 24 Aug 2008 03:33:58 +0000 (+1000) Subject: Initial commit X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=5bb2d2f4785061216e0212a71837cabb021ad146;p=scribble.git Initial commit Just before writing recognition. --- 5bb2d2f4785061216e0212a71837cabb021ad146 diff --git a/scribble.png b/scribble.png new file mode 100644 index 0000000..a5b9cbc Binary files /dev/null and b/scribble.png differ diff --git a/scribble.py b/scribble.py new file mode 100755 index 0000000..486088c --- /dev/null +++ b/scribble.py @@ -0,0 +1,333 @@ +#!/usr/bin/env python + +import pygtk +import gtk +import os + +def page_cmp(a,b): + if a < b: + return -1 + if a > b: + return 1 + return 0 + +def inc_name(a): + l = len(a) + while l > 0 and a[l-1] >= '0' and a[l-1] <= '9': + l -= 1 + # a[l:] is the last number + if l == len(a): + # there is no number + return a + ".1" + num = 0 + int(a[l:]) + return a[0:l] + ("%d" % (num+1)) + +class ScribblePad: + + def __init__(self): + window = gtk.Window(gtk.WINDOW_TOPLEVEL) + window.connect("destroy", self.close_application) + window.set_title("ScribblePad") + #window.set_size_request(480,640) + + vb = gtk.VBox() + window.add(vb) + vb.show() + + bar = gtk.HBox() + vb.add(bar) + bar.show() + + page = gtk.DrawingArea() + page.set_size_request(480,540) + vb.add(page) + page.show() + + # Now the widgets: + # < > R u r A D C name + #back = gtk.Button(stock = gtk.STOCK_GO_BACK) ; back.show() + #fore = gtk.Button(stock = gtk.STOCK_GO_FORWARD) ; fore.show() + #red = gtk.ToggleButton("red"); red.show() + #undo = gtk.Button(stock = gtk.STOCK_UNDO) ; undo.show() + #redo = gtk.Button(stock = gtk.STOCK_REDO) ; redo.show() + #add = gtk.Button(stock = gtk.STOCK_ADD) ; add.show() + #delete = gtk.Button(stock = gtk.STOCK_REMOVE) ; delete.show() + #clear = gtk.Button(stock = gtk.STOCK_CLEAR) ; clear.show() + #name = gtk.Label("1.2.3.4.5") ; name.show() + + back = gtk.Button("<") ; back.show() + fore = gtk.Button(">") ; fore.show() + red = gtk.ToggleButton("red"); red.show() + undo = gtk.Button("u") ; undo.show() + redo = gtk.Button("r") ; redo.show() + add = gtk.Button("+") ; add.show() + delete = gtk.Button("-") ; delete.show() + clear = gtk.Button("C") ; clear.show() + name = gtk.Label("1.2.3.4.5") ; name.show() + + bar.add(back) + bar.add(fore) + bar.add(red) + bar.add(undo) + bar.add(redo) + bar.add(add) + bar.add(delete) + bar.add(clear) + bar.add(name) + + back.connect("clicked", self.back) + fore.connect("clicked", self.fore) + red.connect("toggled", self.colour_change) + undo.connect("clicked", self.undo) + redo.connect("clicked", self.redo) + add.connect("clicked", self.add) + delete.connect("clicked", self.delete) + clear.connect("clicked", self.clear) + self.name = name + self.page = page + self.line = None + self.lines = [] + self.hist = [] # undo history + + + page.connect("button_press_event", self.press) + page.connect("button_release_event", self.release) + page.connect("motion_notify_event", self.motion) + page.connect("expose-event", self.refresh) + page.set_events(gtk.gdk.EXPOSURE_MASK + | gtk.gdk.BUTTON_PRESS_MASK + | gtk.gdk.BUTTON_RELEASE_MASK + | gtk.gdk.POINTER_MOTION_MASK + | gtk.gdk.POINTER_MOTION_HINT_MASK) + + window.show() + colourmap = page.get_colormap() + black = gtk.gdk.color_parse("black") + red = gtk.gdk.color_parse("red") + self.colour_black = page.window.new_gc() + self.colour_black.line_width = 2 + self.colour_black.set_foreground(colourmap.alloc_color(black)) + + self.colour_red = page.window.new_gc() + self.colour_red.line_width = 2 + self.colour_red.set_foreground(colourmap.alloc_color(red)) + + self.colour = self.colour_black + self.colourname = "black" + self.bg = page.get_style().bg_gc[gtk.STATE_NORMAL] + + self.page_dir = os.environ['HOME'] + '/Pages' + self.load_pages() + + window.show() + + def close_application(self, widget): + self.save_page() + gtk.main_quit() + + def load_pages(self): + try: + os.mkdir(self.page_dir) + except: + pass + self.names = os.listdir(self.page_dir) + if len(self.names) == 0: + self.names.append("1") + self.names.sort(page_cmp) + self.pages = {} + self.pagenum = 0 + self.load_page() + return + + def press(self, c, ev): + # Start a new line + + self.line = [ self.colourname, [int(ev.x), int(ev.y)] ] + return + def release(self, c, ev): + #FIXME ignore line if only one dot. + if self.line: + self.lines.append(self.line) + self.line = None + return + def motion(self, c, ev): + if self.line: + if ev.is_hint: + x, y, state = ev.window.get_pointer() + else: + x = ev.x + y = ev.y + x = int(x) + y = int(y) + prev = self.line[-1] + c.window.draw_line(self.colour, prev[0],prev[1],x,y) + self.line.append([x,y]) + return + + def refresh(self, area, ev): + self.redraw() + def redraw(self): + self.name.set_text(self.names[self.pagenum]) + self.page.window.draw_rectangle(self.bg, True, 0, 0, + 480,640) + for l in self.lines: + if l[0] == "red": + col = self.colour_red + else: + col = self.colour_black + st = l[1] + for p in l[2:]: + self.page.window.draw_line(col, st[0], st[1], + p[0],p[1]) + st = p + return + + def back(self,b): + self.save_page() + if self.pagenum <= 0: + return + self.pagenum -= 1 + self.load_page() + self.redraw() + return + def fore(self,b): + if self.pagenum >= len(self.names)-1: + return self.add(b) + self.save_page() + self.pagenum += 1 + self.load_page() + self.redraw() + + return + def colour_change(self,t): + if t.get_active(): + self.colour = self.colour_red + self.colourname = "red" + else: + self.colour = self.colour_black + self.colourname = "black" + return + def undo(self,b): + if len(self.lines) == 0: + return + self.hist.append(self.lines.pop()) + self.redraw() + return + def redo(self,b): + if len(self.hist) == 0: + return + self.lines.append(self.hist.pop()) + self.redraw() + return + def add(self,b): + # New name is either + # - take last number and increment it + # - add .1 + if len(self.lines) == 0: + # don't add after a blank page + return + self.save_page() + newname = self.names[self.pagenum] + while newname in self.pages: + new2 = inc_name(newname) + if new2 not in self.pages: + newname = new2 + elif (newname + ".1") not in self.pages: + newname = newname + ".1" + else: + newname = newname + ".0.1" + + self.names = self.names[0:self.pagenum+1] + [ newname ] + \ + self.names[self.pagenum+1:] + self.pagenum += 1; + self.lines = [] + self.redraw() + return + def delete(self,b): + if len(self.names) <= 1: + return + if len(self.lines) > 0: + return + self.save_page() + nm = self.names[self.pagenum] + if nm in self.pages: + del self.pages[nm] + self.names = self.names[0:self.pagenum] + self.names[self.pagenum+1:] + if self.pagenum >= len(self.names): + self.pagenum -= 1 + self.load_page() + self.redraw() + + return + def clear(self,b): + while len(self.lines) > 0: + self.hist.append(self.lines.pop()) + self.redraw() + return + + def parseline(self, l): + # string in "", or num,num. ':' separates words + words = l.strip().split(':') + line = [] + for w in words: + if w[0] == '"': + w = w[1:-1] + elif w.find(',') >= 0: + n = w.find(',') + x = int(w[:n]) + y = int(w[n+1:]) + w = [x,y] + line.append(w) + return line + + def load_page(self): + nm = self.names[self.pagenum] + if nm in self.pages: + if self.names[self.pagenum] in self.pages: + self.lines = self.pages[self.names[self.pagenum]] + return + self.lines = []; + try: + f = open(self.page_dir + "/" + self.names[self.pagenum], "r") + except: + f = None + if f: + l = f.readline() + while len(l) > 0: + self.lines.append(self.parseline(l)) + l = f.readline() + f.close() + return + + def save_page(self): + self.pages[self.names[self.pagenum]] = self.lines + fn = self.page_dir + "/" + self.names[self.pagenum] + if len(self.lines) == 0: + try: + os.unlink(fn) + except: + pass + return + f = open(fn, "w") + for l in self.lines: + start = True + if not l: + continue + for w in l: + if not start: + f.write(":") + start = False + if isinstance(w, str): + f.write('"%s"' % w) + elif isinstance(w, list): + f.write("%d,%d" %( w[0],w[1])) + f.write("\n") + f.close() + +def main(): + gtk.main() + return 0 +if __name__ == "__main__": + ScribblePad() + main() +