#-------------------------------------------------------------------- # # PyGUI - Canvas - Win32 # #-------------------------------------------------------------------- from math import sin, cos, pi import sys import win32con as wc, win32ui as ui, win32gui as gui from win32con import PS_SOLID, BS_SOLID, RGN_AND #from win32ui import CreatePen, CreateBrush #from win32gui import CloseFigure, PathToRegion, AngleArc from GUI import export import GUI.GDIPlus as gdip from GUI.StdColors import black, white from GUI.StdFonts import application_font from GUI.WinUtils import win_null_brush from GUI.GCanvases import Canvas as GCanvas deg = pi / 180 def ir(x, i = int, r = round): return i(r(x)) def irr(rect, ir = ir): l, t, r, b = rect return (ir(l), ir(t), ir(r), ir(b)) #-------------------------------------------------------------------- class GState(object): pencolor = black fillcolor = black textcolor = black backcolor = white pensize = 1 font = application_font win_pen = gdip.Pen(pencolor._win_argb, 1) win_fill_brush = gdip.SolidBrush(fillcolor._win_argb) win_text_brush = gdip.SolidBrush(textcolor._win_argb) win_bg_brush = gdip.SolidBrush(backcolor._win_argb) def __init__(self, clone = None): if clone: self.__dict__.update(clone.__dict__) #-------------------------------------------------------------------- class Canvas(GCanvas): _current_point = None # def __init__(self, win_graphics, dc = None): # if not dc: # print "Canvas.__init__: before get dc: clip bounds =", win_graphics.GetClipBounds() ### # dc = ui.CreateDCFromHandle(win_graphics.GetHDC()) # print "Canvas.__init__: after get dc: clip bounds =", win_graphics.GetClipBounds() ### # dc.SetBkMode(wc.TRANSPARENT) # dc.SetTextAlign(wc.TA_LEFT | wc.TA_BASELINE | wc.TA_UPDATECP) # print "Canvas.__init__: clip bounds =", win_graphics.GetClipBounds() ### # self._win_graphics = win_graphics # self._win_dc = dc # self._win_hdc = dc.GetHandleOutput() # self._win_path = gdip.GraphicsPath() # self._state = GState() # self._stack = [] def __init__(self, win_graphics, for_printing = False): self._win_graphics = win_graphics self._win_path = gdip.GraphicsPath() self._state = GState() self._stack = [] if for_printing: unit = gdip.UnitPoint win_graphics.SetPageUnit(unit) #else: # unit = gdip.UnitPixel # dpix = win_graphics.GetDpiX() # dpiy = win_graphics.GetDpiY() # print "Canvas: dpi =", dpix, dpiy ### # win_graphics.SetPageUnit(gdip.UnitPoint) # if not for_printing: # sx = 72.0 / dpix # sy = 72.0 / dpiy # self.scale(sx, sy) def _from_win_dc(cls, dc): return cls._from_win_hdc(dc.GetSafeHdc()) _from_win_dc = classmethod(_from_win_dc) def _from_win_hdc(cls, hdc, **kwds): win_graphics = gdip.Graphics.from_hdc(hdc) return cls(win_graphics, **kwds) _from_win_hdc = classmethod(_from_win_hdc) def _from_win_image(cls, win_image): win_graphics = gdip.Graphics.from_image(win_image) #print "Canvas._from_win_image: win_graphics =", win_graphics ### #print "... clip bounds =", win_graphics.GetClipBounds() ### return cls(win_graphics) _from_win_image = classmethod(_from_win_image) def get_pencolor(self): return self._state.pencolor def set_pencolor(self, c): state = self._state state.pencolor = c state.win_pen = gdip.Pen(c._win_argb, state.pensize) def get_fillcolor(self): return self._state.fillcolor def set_fillcolor(self, c): state = self._state state.fillcolor = c if self.fillcolor.image: tb = gdip.TextureBrush(self.fillcolor.image) state.win_fill_brush = tb else: state.win_fill_brush = gdip.SolidBrush(c._win_argb) def get_textcolor(self): return self._state.textcolor def set_textcolor(self, c): state = self._state state.textcolor = c state.win_text_brush = gdip.SolidBrush(c._win_argb) def get_backcolor(self): return self._state.backcolor def set_backcolor(self, c): state = self._state state.backcolor = c state.win_bg_brush = gdip.SolidBrush(c._win_argb) def get_pensize(self): return self._state.pensize def set_pensize(self, x): state = self._state state.pensize = x state.win_pen = gdip.Pen(state.pencolor._win_argb, x) def get_current_point(self): return self._current_point def get_font(self): return self._state.font def set_font(self, f): self._state.font = f def newpath(self): self._win_path.Reset() self.minx = sys.maxint self.miny = sys.maxint self.maxx = -sys.maxint/2 self.maxy = -sys.maxint/2 def moveto(self, x, y): p = (x, y) try: self.minx = min(self.minx, x) self.miny = min(self.miny, y) self.maxx = max(self.maxx, x) self.maxy = max(self.maxy, y) except AttributeError: self.minx = x self.miny = y self.maxx = x self.maxy = y self._current_point = p self._win_path.StartFigure() def lineto(self, x, y): x0, y0 = self._current_point self.minx = min(self.minx, x) self.miny = min(self.miny, y) self.maxx = max(self.maxx, x) self.maxy = max(self.maxy, y) self._win_path.AddLine_4f(x0, y0, x, y) self._current_point = (x, y) def curveto(self, p1, p2, p3): p0 = self._current_point self.minx = min(self.minx, p1[0], p2[0], p3[0]) self.miny = min(self.miny, p1[1], p2[1], p3[1]) self.maxx = max(self.maxx, p1[0], p2[0], p3[0]) self.maxy = max(self.maxy, p1[1], p2[1], p3[1]) self._win_path.AddBezier_4p(p0, p1, p2, p3) self._current_point = p3 def arc(self, c, r, a0, a1): g = self._win_path g.AddArc_p3f(c, r, a0, a1) self._current_point = g.GetLastPoint() def closepath(self): self._win_path.CloseFigure() self._current_point = None def fill(self): if self.fillcolor.image: self.gsave() self._win_graphics.Scale_2f((self.maxx-self.minx)*1.0/self.fillcolor.image.GetWidth(), (self.maxy-self.miny)*1.0/self.fillcolor.image.GetHeight()) self._win_graphics.FillPath(self._state.win_fill_brush, self._win_path) self.grestore() else: self._win_graphics.FillPath(self._state.win_fill_brush, self._win_path) def stroke(self): self._win_graphics.DrawPath(self._state.win_pen, self._win_path) def erase(self): g = self._win_graphics g.SetSourceCopyMode() g.FillPath(self._state.win_bg_brush, self._win_path) g.SetSourceOverMode() def show_text(self, text): font = self._state.font gf = font._win_gdip_font x, y = self._current_point brush = self._state.win_text_brush g = self._win_graphics w = g.DrawAndMeasureStringWidth_2f(text, gf, x, y, brush) self._current_point = x + w, y ## ## GDI+ screws up some fonts (e.g. Times) for some reason. ## Using plain GDI to draw text for now. ## # def show_text(self, text): # state = self._state # x, y = self._current_point # dc = self._win_dc # dc.SelectObject(state.font._win_font) # dc.SetTextColor(state.textcolor._win_color) # dc.MoveTo(ir(x), ir(y)) # dc.TextOut(20, 20, text) # self._current_point = dc.GetCurrentPosition() def clip(self): self._win_graphics.SetClip_PI(self._win_path) def rectclip(self, rect): self._win_graphics.SetClip_rI(rect) def gsave(self): old_state = self._state old_state.win_state = self._win_graphics.Save() self._stack.append(old_state) self._state = GState(old_state) def grestore(self): old_state = self._stack.pop() self._win_graphics.Restore(old_state.win_state) self._state = old_state # Rectangles def rect(self, rect): self._win_path.AddRectangle_r(rect) self._current_point = None def fill_rect(self, rect): self._win_graphics.FillRectangle_r(self._state.win_fill_brush, rect) def stroke_rect(self, rect): self._win_graphics.DrawRectangle_r(self._state.win_pen, rect) def erase_rect(self, rect): self._win_graphics.FillRectangle_r(self._state.win_bg_brush, rect) # Ovals def oval(self, rect): self._win_path.AddEllipse_r(rect) self._current_point = None def fill_oval(self, rect): self._win_graphics.FillEllipse_r(self._state.win_fill_brush, rect) def stroke_oval(self, rect): self._win_graphics.DrawEllipse_r(self._state.win_pen, rect) def erase_oval(self, rect): self._win_graphics.FillEllipse_r(self._state.win_bg_brush, rect) # Arcs def stroke_arc(self, c, r, a0, a1): self._win_graphics.DrawArc_3pf(self._state.win_pen, c, r, a0, a1) # Wedges def wedge(self, c, r, a0, a1): self._win_path.AddPie_p3f(c, r, a0, a1) self._current_point = None def stroke_wedge(self, c, r, a0, a1): self._win_graphics.DrawPie_p3f(self._state.win_pen, c, r, a0, a1) def fill_wedge(self, c, r, a0, a1): self._win_graphics.FillPie_p3f(self._state.win_fill_brush, c, r, a0, a1) def erase_wedge(self, c, r, a0, a1): self._win_graphics.FillPie_p3f(self._state.win_bg_brush, c, r, a0, a1) # Polylines def lines(self, points): self._win_path.AddLines_pv(points) self._current_point = points[-1] def linesto(self, points): self.lines([self._current_point] + points) def stroke_lines(self, points): self._win_graphics.DrawLines_pv(self._state.win_pen, points) # Polygons def poly(self, points): self._win_path.AddPolygon_pv(points) self._current_point = None def stroke_poly(self, points): self._win_graphics.DrawPolygon_pv(self._state.win_pen, points) def fill_poly(self, points): self._win_graphics.FillPolygon_pv(self._state.win_fill_brush, points) def erase_poly(self, points): self._win_graphics.FillPolygon_pv(self._state.win_bg_brush, points) # Polycurves def curves(self, points): self._win_path.AddBeziers_pv(points) self._current_point = points[-1] def curvesto(self, points): self.curves([self._current_point] + points) def stroke_curves(self, points): self._win_graphics.DrawBeziers_pv(self._state.win_pen, points) # Transformations def translate(self, dx, dy): self._win_graphics.Translate_2f(dx, dy) def scale(self, sx, sy): self._win_graphics.Scale_2f(sx, sy) def rotate(self, rotation): self._win_graphics.Rotate_1f(rotation) export(Canvas)