From 95903addc2703a928de38e99b4274a5d3da44aa2 Mon Sep 17 00:00:00 2001 From: Matthias Kramm Date: Tue, 11 Aug 2009 21:14:25 +0200 Subject: [PATCH] started spec editor --- spec/edit_spec.py | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 2 +- 2 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 spec/edit_spec.py diff --git a/spec/edit_spec.py b/spec/edit_spec.py new file mode 100644 index 0000000..2ede754 --- /dev/null +++ b/spec/edit_spec.py @@ -0,0 +1,299 @@ +import wx +import wx.lib.scrolledpanel as scrolled +import os +import re +import sys +import time +import thread +import traceback +import math + +class Check: + def __init__(self, x,y): + self.x = x + self.y = y + def left(self): + return "pixel at (%d,%d)" % (self.x,self.y) + def right(self): + return "" + +class PixelColorCheck(Check): + def __init__(self, x,y, color): + Check.__init__(self,x,y) + self.color = color + def right(self): + return "is of color 0x%06x" % self.color + +class TwoPixelCheck(Check): + def __init__(self, x,y, x2,y2): + Check.__init__(self,x,y) + self.x2,self.y2 = x2,y2 + def right(self): + return "pixel at (%d,%d)" % (self.x2,self.y2) + +class PixelBrighterThan(TwoPixelCheck): + pass + +class PixelDarkerThan(TwoPixelCheck): + pass + +class PixelEqualTo(TwoPixelCheck): + pass + +class AreaCheck(Check): + def __init__(self, x,y, x2,y2): + Check.__init__(self,x,y) + self.x2,self.y2 = x2,y2 + def left(self): + return "area at (%d,%d,%d,%d)" % (self.x,self.y,self.x2,self.y2) + +class AreaPlain(AreaCheck): + pass + +class AreaNotPlain(AreaCheck): + pass + +class Model: + def __init__(self, filename, checks): + self.filename = filename + self.checks = checks + + @staticmethod + def load(filename): + path = os.path.splitext(filename)[0]+".rb" + fi = open(path, "rb") + r_file = re.compile(r"^convert_file \"([^\"]*)\"") + r_pixelcolor = re.compile(r"^pixel_at\(([0-9]+),([0-9]+)\).should_be_of_color (0x[0-9a-fA-F]+)") + r_pixelbrighter = re.compile(r"^pixel_at\(([0-9]+),([0-9]+)\).should_be_brighter_than pixel_at\(([0-9]+),([0-9]+)\)") + r_pixeldarker = re.compile(r"^pixel_at\(([0-9]+),([0-9]+)\).should_be_darker_than pixel_at\(([0-9]+),([0-9]+)\)") + r_pixelequalto = re.compile(r"^pixel_at\(([0-9]+),([0-9]+)\).should_be_the_same_as pixel_at\(([0-9]+),([0-9]+)\)") + r_areaplain = re.compile(r"^area_at\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\).should_be_plain_colored") + r_areanotplain = re.compile(r"^area_at\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\).should_not_be_plain_colored") + r_width = re.compile(r"^width.should be ([0-9]+)") + r_height = re.compile(r"^height.should be ([0-9]+)") + r_describe = re.compile(r"^describe \"pdf conversion\"") + r_header = re.compile(r"^require File.dirname") + r_end = re.compile(r"^end$") + filename = None + checks = [] + for nr,line in enumerate(fi.readlines()): + line = line.strip() + if not line: + continue + m = r_file.match(line) + if m: + if filename: + raise Exception("can't load multi-file specs (in line %d)" % (nr+1)) + filename = m.group(1); + continue + m = r_pixelcolor.match(line) + if m: checks += [PixelColorCheck(int(m.group(1)),int(m.group(2)),int(m.group(3),16))];continue + m = r_pixelbrighter.match(line) + if m: checks += [PixelBrighterThan(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)))];continue + m = r_pixeldarker.match(line) + if m: checks += [PixelDarkerThan(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)))];continue + m = r_pixelequalto.match(line) + if m: checks += [PixelEqualTo(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)))];continue + m = r_areaplain.match(line) + if m: checks += [AreaPlain(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)))];continue + m = r_areanotplain.match(line) + if m: checks += [AreaNotPlain(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)))];continue + if r_width.match(line) or r_height.match(line): + continue # compatibility + if r_describe.match(line) or r_end.match(line) or r_header.match(line): + continue + print line + raise Exception("invalid file format: can't load this file (in line %d)" % (nr+1)) + + fi.close() + return Model(filename, checks) + + def save(self): + path = os.path.splitext(self.filename)[0]+".rb" + fi = open(path, "wb") + fi.write("require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe \"pdf conversion\" do\n") + fi.write(" convert_file \"%s\" do\n" % self.filename) + for check in self.checks: + c = check.__class__ + if c == PixelColorCheck: + fi.write(" pixel_at(%d,%d).should_be_of_color 0x%06x\n" % (check.x,check.y,check.color)) + elif c == PixelBrighterThan: + fi.write(" pixel_at(%d,%d).should_be_brighter_than pixel_at(%d,%d)\n" % (check.x,check.y,check.x2,check.y2)) + elif c == PixelDarkerThan: + fi.write(" pixel_at(%d,%d).should_be_darker_than pixel_at(%d,%d)\n" % (check.x,check.y,check.x2,check.y2)) + elif c == PixelEqualTo: + fi.write(" pixel_at(%d,%d).should_be_the_same_as pixel_at(%d,%d)\n" % (check.x,check.y,check.x2,check.y2)) + elif c == AreaPlain: + fi.write(" area_at(%d,%d,%d,%d).should_be_plain_colored\n" % (check.x,check.y,check.x2,check.y2)) + elif c == AreaNotPlain: + fi.write(" area_at(%d,%d,%d,%d).should_not_be_plain_colored\n" % (check.x,check.y,check.x2,check.y2)) + fi.write(" end\n") + fi.write("end\n") + fi.close() + + +class ImageFrame(wx.Frame): + def __init__(self, application, model): + wx.Frame.__init__(self, None, -1, style = wx.DEFAULT_FRAME_STYLE, pos=(50,50)) + self.application = application + self.model = model + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) + self.bitmap = wx.Bitmap(model.filename) + self.width = self.bitmap.GetWidth() + self.height = self.bitmap.GetHeight() + self.bitmap_x = 500 + self.bitmap_y = 32 + self.SetSize((self.width+self.bitmap_x+32, max(self.height+self.bitmap_y, 15*32))) + self.image = wx.ImageFromBitmap(self.bitmap) + self.x = 0 + self.y = 0 + self.createToolbar() + + def createToolbar(self): + tsize = (16,16) + self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) + self.toolbar.AddSimpleTool(wx.ID_OPEN, + wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize), + "Open") + self.toolbar.AddSimpleTool(wx.ID_SAVE, + wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, tsize), + "Save selected pages") + self.toolbar.AddSimpleTool(wx.ID_PREFERENCES, + wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR, tsize), + "Options") + #self.toolbar.AddSeparator() + self.toolbar.Realize() + + def OnMouseClick(self, event): + x = min(max(event.X - self.bitmap_x, 0), self.width-1) + y = min(max(event.Y - self.bitmap_y, 0), self.height-1) + if y not in self.model.pixels: + self.model.pixels[y] = {} + if y in self.model.pixels and x in self.model.pixels[y]: + del self.model.pixels[y][x] + else: + color = self.image.GetRed(x,y)<<16 | self.image.GetGreen(x,y)<<8 | self.image.GetBlue(x,y) + self.model.pixels[y][x] = color + self.Refresh() + + def OnMouse(self, event): + if event.LeftIsDown(): + return self.OnMouseClick(event) + lastx = self.x + lasty = self.y + self.x = min(max(event.X - self.bitmap_x, 0), self.width-1) + self.y = min(max(event.Y - self.bitmap_y, 0), self.height-1) + if lastx!=self.x or lasty!=self.y: + self.Refresh() + + def OnPaint(self, event): + dc = wx.PaintDC(self) + self.Draw(dc) + + def Draw(self,dc=None): + if not dc: + dc = wx.ClientDC(self) + + dc.SetBackground(wx.Brush((0,0,0))) + dc.DrawBitmap(self.bitmap, self.bitmap_x, self.bitmap_y, False) + + for yy,row in self.model.pixels.items(): + for xx in row.keys(): + x = xx+self.bitmap_x + y = yy+self.bitmap_y + l = 0 + for r in range(10): + r = (r+1)*3.141526/5 + dc.DrawLine(x+10*math.sin(l), y+10*math.cos(l), x+10*math.sin(r), y+10*math.cos(r)) + l = r + dc.DrawLine(x,y,x+1,y) + + color = (0,255,0) + for yy in range(15): + y = self.y+yy-8 + marked = self.model.pixels.get(y, {}) + for xx in range(15): + x = self.x+xx-8 + if 0<=x gray2 or raise PixelError.new(self,"is not brighter than",pixel) end - def should_be_less_bright_than(pixel) + def should_be_darker_than(pixel) gray1 = @rgb.inject(0) {|sum,e| sum+e} gray2 = pixel.rgb.inject(0) {|sum,e| sum+e} gray1 < gray2 or raise PixelError.new(self,"is not less bright than",pixel) -- 1.7.10.4