370 lines
11 KiB
Python
370 lines
11 KiB
Python
#--------------------------------------------------------------------
|
|
#
|
|
# 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)
|