Esempio n. 1
0
    def __init__(self, colors=(0,0,0,0), keepTransparent=True, alpha=True):
#        if not colors: self.colors = alpha
        t = type(colors)
        if t is int:
            self.colors = [rgba(alpha) for i in range(colors)]
        elif t is bool: self.colors = colors
        else:
            if t in (str, pygame.Color) or type(colors[0]) is int:
                colors = colors,
            self.colors = [rgba(i) for i in colors]
        self.n = -1
        self.keep = keepTransparent
Esempio n. 2
0
    def __init__(self, colors=(0,0,0,0), keepTransparent=True, alpha=True):
#        if not colors: self.colors = alpha
        t = type(colors)
        if t is int:
            self.colors = [rgba(alpha) for i in range(colors)]
        elif t is bool: self.colors = colors
        else:
            if t in (str, pygame.Color) or type(colors[0]) is int:
                colors = colors,
            self.colors = [rgba(i) for i in colors]
        self.n = -1
        self.keep = keepTransparent
Esempio n. 3
0
def _tempColor(px, color, *args):
    "Replace one color with a random RGB color"
    c = color
    while c in args:
        c = rgba(False)
    if c != color: px.replace(color, c)
    return c
Esempio n. 4
0
 def onkeydown(self, ev):
     u = ev.unicode.upper()
     if u == '?': self.menu()
     elif u == 'O': self.open()
     elif u == '\t': self["Text"].config(color=rgba(False))
     elif "Video" in self:
         vid = self["Video"]
         if u == 'S': self.saveAs()
         elif u == 'G':
             fn = ask(asksaveasfilename, filetypes=IMAGETYPES)
             if fn: vid[vid.costumeNumber].save(fn)
         elif u == 'F':
             fps = ask(askfloat,
                       title="Frame Rate",
                       prompt="Enter new frame rate:")
             if fps: self.frameRate = max(1.0, fps)
         elif u == ' ':
             vid.costumeTime = 1 - vid.costumeTime
         elif ev.key == K_HOME:
             vid.costumeTime = vid.costumeNumber = 0
         elif u == "N":
             vid.costumeTime = 0
             try:
                 vid.costumeNumber = int(input("Go to frame? "))
             except:
                 pass
         elif ev.key in (K_LEFT, K_RIGHT):
             vid.costumeTime = 0
             n = vid.costumeNumber + (1 if ev.key == K_RIGHT else -1)
             if n < 0: n = len(vid) - 1
             elif n >= len(vid): n = 0
             vid.costumeNumber = n
         elif u in "[]":
             self.clip["[]".index(u)] = vid.costumeNumber
Esempio n. 5
0
 def __init__(self, drops=64, fill=(0, 0, 0, 0)):
     self.fill = rgba(fill)
     self.side = drops > 0
     self.drops = [self.makeDrop() for i in range(abs(drops))]
     n = sum([d[0] for d in self.drops])
     for d in self.drops:
         d[0] /= n
Esempio n. 6
0
class Shape(Graphic):
    _fill = None
    _stroke = rgba((0, 0, 0))
    weight = 1

    @property
    def stroke(self): return self._stroke

    @stroke.setter
    def stroke(self, s): self._stroke = rgba(s) if s else None

    @property
    def fill(self): return self._fill

    @fill.setter
    def fill(self, s): self._fill = rgba(s) if s else None

    @property
    def avgColor(self):
        f = self._fill
        return f if f else self._stroke

    def contains(self, pos):
        "Determine if the point is within the shape, accounting for canvas offset"
        cv = self.canvas
        cvPos = delta(pos, cv.rect.topleft) if cv else pos
        return self.containsPoint(cvPos)
Esempio n. 7
0
    def setup(self):

        # Draw star field
        self.bg = img = Image(self.size, "black")
        img = img.image
        for i in range(150):
            img.set_at(randPixel(self.size), rgba(False))

        # Load high scores
        try:
            with open(JSON) as f:
                self.highScores = json.load(f)
        except:
            self.highScores = []

        # Load images
        Missile.original = Image(self.imgFldr + "/missile.png")
        Asteroid.original = Image(self.imgFldr + "/target.png")
        self.player = Ship(self.imgFldr + "/ship.png").config(wrap=BOTH)

        # Start the game
        self.playerName = None
        self.score = Score()
        self.collisions = Collisions(self)
        self.start()
Esempio n. 8
0
 def pixel(self, n, x, y, c):
     "Calculate pixel color"
     if random() <= n or (self.keep and c & self.alphaMask == 0):
         return c
     c = self.colors
     if type(c) is bool: return rgba(c)
     self.n = (self.n + 1) % len(self.colors)
     return c[self.n]
Esempio n. 9
0
def circles(sk, n=50):
	"Draw random circles for arena floor"
	size = sk.size
	cv = Canvas(size, "white")
	for i in range(n):
		r = randint(10, size[0]/8)
		cv += Circle(r).config(weight=0, fill=rgba(True), pos=randPixel(size))
	return cv.snapshot()
Esempio n. 10
0
 def pixel(self, n, x, y, c):
     "Calculate pixel color"
     if random() <= n or (self.keep and c & self.alphaMask == 0):
         return c
     c = self.colors
     if type(c) is bool: return rgba(c)
     self.n = (self.n + 1) % len(self.colors)
     return c[self.n]
Esempio n. 11
0
 def config(self, **kwargs):
     keys = ("bg", "color", "border", "promptColor", "data", "font",
             "fontSize", "fontStyle", "height", "width", "align", "padding",
             "spacing", "weight")
     if hasAny(kwargs, keys): self.stale = True
     for a in kwargs:
         v = kwargs[a]
         if v and a in keys[:4]: v = rgba(v)
         setattr(self, a, v)
     return self
Esempio n. 12
0
 def axis(self, n=None, ends=None, stroke="black", weight=2):
     "Configure the x- and/or y-axis"
     if n is None:
         for n in range(2): self.axis(n, ends, stroke, weight)
     else:
         attr = ["_xaxis", "_yaxis"][n]
         if not ends: ends = self._coords[2:] if n else self._coords[:2]
         setattr(self, attr, (ends, rgba(stroke), weight))
     self.stale = True
     return self
Esempio n. 13
0
 def config(self, **kwargs):
     keys = ("data", "color", "bg", "font", "fontSize", "fontStyle",
         "height", "width", "align", "padding", "spacing", "weight",
         "border", "promptColor")
     if hasAny(kwargs, keys): self.stale = True
     for a in kwargs:
         v = kwargs[a]
         if v and a in ("bg", "color", "border", "promptColor"): v = rgba(v)
         setattr(self, a, v)
     return self
Esempio n. 14
0
 def axis(self, n=None, ends=None, stroke="black", weight=2):
     "Configure the x- and/or y-axis"
     if n is None:
         for n in range(2):
             self.axis(n, ends, stroke, weight)
     else:
         attr = ["_xaxis", "_yaxis"][n]
         if not ends: ends = self._coords[2:] if n else self._coords[:2]
         setattr(self, attr, (ends, rgba(stroke), weight))
     self.stale = True
     return self
Esempio n. 15
0
 def __init__(self, colors=None):
     img = Image.fromBytes(sc8prData("robot"))
     if colors:  # Replace body and nose colors
         px = pygame.PixelArray(img.image)
         body0, nose0, body, nose = rgba("red", "blue", *colors)
         orig = body0, nose0
         if body in orig or nose in orig:
             colors = body0, nose0, body, nose
             body0 = _tempColor(px, body0, *colors)
             nose0 = _tempColor(px, nose0, *colors)
         if nose != nose0: px.replace(nose0, nose)
         if body != body0: px.replace(body0, body)
     img = img.tiles(2)
     super().__init__(img)
Esempio n. 16
0
 def __init__(self, colors=None):
     img = Image.fromBytes(sc8prData("robot"))
     if colors:  # Replace body and nose colors
         px = pygame.PixelArray(img.image)
         body0, nose0, body, nose = rgba("red", "blue", *colors)
         orig = body0, nose0
         if body in orig or nose in orig:
             colors = body0, nose0, body, nose
             body0 = _tempColor(px, body0, *colors)
             nose0 = _tempColor(px, nose0, *colors)
         if nose != nose0: px.replace(nose0, nose)
         if body != body0: px.replace(body0, body)
     img = img.tiles(2)
     super().__init__(img)
Esempio n. 17
0
 def options(self, options):
     "Convert options to a list of colors or images"
     if options is None: options = OPTIONS
     else:
         t = type(options)
         if t is dict:
             options = [options.get(self.statusName(i)) for i in range(5)]
         elif t is int:
             options = [OPTIONS[i] for i in range(options)]
         elif t is not list: options = list(options)
         while len(options) < 5: options.append(None)
     c = lambda x: rgba(x) if type(x) in (str,list,tuple) else x
     options = [c(i) for i in options]
     if options[1] is None: options[1] = options[0] 
     if options[3] is None: options[3] = options[2]
     self._options = options
Esempio n. 18
0
 def _drawGrid(self, srf, n, cfg):
     "Draw gridlines"
     s = rgba(cfg["stroke"])
     w = cfg["weight"]
     x, x1 = cfg["yends" if n else "xends"]
     y0, y1 = cfg["xends" if n else "yends"]
     dx = cfg["interval"]
     while x <= x1:
         if n:
             p0 = [y0, x]
             p1 = [y1, x]
         else:
             p0 = [x, y0]
             p1 = [x, y1]
         pygame.draw.line(srf, s, self.pixelCoords(p0), self.pixelCoords(p1), w)
         x += dx
Esempio n. 19
0
 def _drawGrid(self, srf, n, cfg):
     "Draw gridlines"
     s = rgba(cfg["stroke"])
     w = cfg["weight"]
     x, x1 = cfg["yends" if n else "xends"]
     y0, y1 = cfg["xends" if n else "yends"]
     dx = cfg["interval"]
     while x <= x1:
         if n:
             p0 = [y0, x]
             p1 = [y1, x]
         else:
             p0 = [x, y0]
             p1 = [x, y1]
         pygame.draw.line(srf, s, self.pixelCoords(p0),
                          self.pixelCoords(p1), w)
         x += dx
Esempio n. 20
0
    def _checkFront(self):
        "Update the front color sensor"

        # Sensor info
        sw = self.sensorWidth
        res = 0.5 * self.sensorResolution
        pos = delta(self.pos, vec2d(-self.radius, self.angle))

        # Distance from sensor to edge of sketch
        obj = prox = None
        sk = self.sketch
        if sk.weight:
            prox = _distToWall(pos, self.angle, self.sensorWidth, *sk.size)
            if prox: obj = sk

        # Find closest object within "sensor cone"
        for gr in self.sensorObjects(sk):
            if gr is not self and gr.avgColor and hasattr(gr, "rect"):
                r = gr.radius
                view = subtend(pos, gr.rect.center, r,
                               None if prox is None else prox + r)
                if view:
                    # Object may be closer than the current closest object
                    sep, direct, half = view
                    if not res or half > res:
                        # Object size meets sensor resolution threshold
                        beta = abs(angleDifference(self.angle, direct)) - sw
                        if beta < half or sep < r:
                            # Object is in sensor cone
                            pr = sep - r
                            if beta > 0:
                                # CLOSEST point is NOT in sensor cone
                                dr = r + sep * (cos(half * DEG) - 1)
                                pr += dr * (beta / half)**2
                            if prox is None or pr < prox:
                                # Object is closest (so far)
                                prox = pr
                                obj = gr

        # Save data
        self.closestObject = obj
        c = rgba(sk.border if obj is sk else obj.avgColor if obj else (0, 0,
                                                                       0))
        self.sensorFront = noise(divAlpha(c), self.sensorNoise, 255)
        self.proximity = None if prox is None else max(0, round(prox))
Esempio n. 21
0
    def _checkFront(self):
        "Update the front color sensor"

        # Sensor info
        sw = self.sensorWidth
        res = 0.5 * self.sensorResolution
        pos = delta(self.pos, vec2d(-self.radius, self.angle))
    
        # Distance from sensor to edge of sketch
        obj = prox = None
        sk = self.sketch
        if sk.weight:
            prox = _distToWall(pos, self.angle, self.sensorWidth, *sk.size)
            if prox: obj = sk

        # Find closest object within "sensor cone"
        for gr in self.sensorObjects(sk):
            if gr is not self and gr.avgColor and hasattr(gr, "rect"):
                r = gr.radius
                view = subtend(pos, gr.rect.center, r, None if prox is None else prox + r)
                if view:
                    # Object may be closer than the current closest object
                    sep, direct, half = view
                    if not res or half > res:
                        # Object size meets sensor resolution threshold
                        beta = abs(angleDifference(self.angle, direct)) - sw
                        if beta < half or sep < r:
                            # Object is in sensor cone
                            pr = sep - r
                            if beta > 0:
                                # CLOSEST point is NOT in sensor cone
                                dr = r + sep * (cos(half * DEG) - 1)
                                pr += dr * (beta / half) ** 2
                            if prox is None or pr < prox:
                                # Object is closest (so far)
                                prox = pr
                                obj = gr

        # Save data
        self.closestObject = obj
        c = rgba(sk.border if obj is sk else obj.avgColor if obj else (0,0,0))
        self.sensorFront = noise(divAlpha(c), self.sensorNoise, 255)
        self.proximity = None if prox is None else max(0, round(prox))
Esempio n. 22
0
    def draw(self, srf, transform):
        "Plot one data series onto a surface"

        # Plot stroke
        pts = [transform(p) for p in self.pointGen()]
        s, w = self.stroke, self.weight
        if s and w: pygame.draw.lines(srf, rgba(s), False, pts, w)

        # Plot markers
        marker = self.marker
        if marker:
            i = 0
            for p in pts:
                if isinstance(marker, Graphic): img = marker
                else:
                    img = marker[i]
                    i += 1
                if img.canvas: img.remove()
                img.pos = p
                sz = img.size
                if img.angle: sz = rotatedSize(*sz, img.angle)
                pos = img.blitPosition((0, 0), sz)
                srf.blit(img.image, pos)
Esempio n. 23
0
    def draw(self, srf, transform):
        "Plot one data series onto a surface"

        # Plot stroke
        pts = [transform(p) for p in self.pointGen()]
        s, w = self.stroke, self.weight
        if s and w: pygame.draw.lines(srf, rgba(s), False, pts, w)

        # Plot markers
        marker = self.marker
        if marker:
            i = 0
            for p in pts:
                if isinstance(marker, Graphic): img = marker
                else:
                    img = marker[i]
                    i += 1
                if img.canvas: img.remove()
                img.pos = p
                sz = img.size
                if img.angle: sz = rotatedSize(*sz, img.angle)
                pos = img.blitPosition((0,0), sz)
                srf.blit(img.image, pos)
Esempio n. 24
0
# "sc8pr" is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with "sc8pr".  If not, see <http://www.gnu.org/licenses/>.


from sc8pr.image import Image
from sc8pr.util import rgba, CENTER, EAST, NORTH, WEST, SOUTH, NE, NW
from sc8pr.geom import locus, arrow, add
import pygame


BLACK, WHITE, GREY = rgba("black", "white", "grey")


class Plot(Image):

    def __init__(self, img, xrange, yrange=None, margin=0):
        "Encapsulate an Image with an associated coordinate system"
        super().__init__(img)
        w, h = self.size
        xmin, xmax = xrange
        if type(margin) is int:
            margin = [margin for i in range(4)]
        mx1, mx2, my2, my1 = margin
        xscale = (w - 1 - (mx1 + mx2)) / (xmax - xmin)
        if yrange is None or type(yrange) in (int, float):
            yscale = -xscale
Esempio n. 25
0
 def __init__(self, drops=64, fill=(0,0,0,0)):
     self.fill = rgba(fill)
     self.side = drops > 0
     self.drops = [self.makeDrop() for i in range(abs(drops))]
     n = sum([d[0] for d in self.drops])
     for d in self.drops: d[0] /= n
Esempio n. 26
0
    def fill(self, s): self._fill = rgba(s) if s else None

    @property
Esempio n. 27
0
    def stroke(self, s): self._stroke = rgba(s) if s else None

    @property
Esempio n. 28
0
 def __init__(self, color=(255,255,255,0)):
     self.color = rgba(color)
Esempio n. 29
0
class Text(Renderable):
    font = None
    fontSize = 24
    fontStyle = 0
    bg = None
    color = border = rgba("black")
    weight = 0
    padding = 0
    spacing = 0
    align = LEFT

    def __init__(self, data=""):
        self.data = data

    def __iadd__(self, v):
        self.data += v
        self.stale = True
        return self

    def config(self, **kwargs):
        keys = ("bg", "color", "border", "promptColor", "data", "font",
                "fontSize", "fontStyle", "height", "width", "align", "padding",
                "spacing", "weight")
        if hasAny(kwargs, keys): self.stale = True
        for a in kwargs:
            v = kwargs[a]
            if v and a in keys[:4]: v = rgba(v)
            setattr(self, a, v)
        return self

    def render(self):
        "Render the text as an Image"
        font = Font.get(self.font, self.fontSize, self.fontStyle)
        text = str(self.data).split("\n")
        srfs = [font.render(t, True, self.color) for t in text]
        return self._joinLines(srfs)

    def _joinLines(self, srfs):
        "Join the lines of text into a single surface"

        # Calculate total size
        wMax, hMax = 0, 0
        n = len(srfs)
        for s in srfs:
            w, h = s.get_size()
            if w > wMax: wMax = w
            if h > hMax: hMax = h
        y = self.padding
        w = wMax + 2 * y
        h = n * hMax + (n - 1) * self.spacing + 2 * y

        # Blit lines to final image
        wt = self.weight
        dx = 2 * wt
        y += wt
        srf = Image((w + dx, h + dx), self.bg).image
        a = self.color.a
        for s in srfs:
            if a < 255: setAlpha(s, a)
            x = self.padding + wt
            if self.align != LEFT:
                dx = wMax - s.get_size()[0]
                x += dx if self.align == RIGHT else dx // 2
            srf.blit(s, (x, y))
            y += hMax + self.spacing
        if wt: drawBorder(srf, self.border, wt)
        return srf

    def resize(self, size):
        self.fontSize *= size[1] / self.height
        self.stale = True
Esempio n. 30
0
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"A demonstration of some of sc8pr 2.0's GUI controls"

from sc8pr import Sketch, Canvas, Image, TOPLEFT, TOPRIGHT, CENTER, TOP
from sc8pr.util import rgba, nothing, sc8prData
from sc8pr.text import BOLD, Font
from sc8pr.gui.textinput import TextInput
from sc8pr.gui.radio import Radio, Options
from sc8pr.gui.slider import Slider
from sc8pr.gui.button import Button
from sc8pr.gui.menu import Menu, R_TRIANGLE

GREY, BLUE = rgba("#ececec", "blue")
FONT = Font.sans()

def buttons(cfg):
    "Create a canvas containing two buttons"
    cv = Canvas((256, 48))

    # Selectable button
    btn1 = Button((120, 48)).textIcon("Selectable\nButton", True)
    cv["Selectable"] = btn1.config(anchor=TOPLEFT).bind(onaction=buttonClick)

    # Non-selectable button
    btn2 = Button(btn1.size, 2).textIcon("Popup Menu").bind(onaction=buttonClick)
    cv["Popup"] = btn2.config(pos=(255, 0), anchor=TOPRIGHT)

    # Configure button text
Esempio n. 31
0
 def pen(self, p):
     if p and len(p) == 2:
         p = p + (self._pen[2] if self._pen else None, )
     if p: p = (rgba(p[0]), ) + p[1:]
     self._pen = p
Esempio n. 32
0
    def stroke(self, s): self._stroke = rgba(s) if s else None

    @property
Esempio n. 33
0
    def fill(self, s): self._fill = rgba(s) if s else None

    @property
Esempio n. 34
0
 def __init__(self, slope=False, above=True, fill=(0,0,0,0)):
     self.slope = slope
     self.above = above
     self.fill = rgba(fill)
Esempio n. 35
0
 def __init__(self, clockwise=True, fill=(0, 0, 0, 0)):
     self.fill = rgba(fill)
     self.cw = clockwise
Esempio n. 36
0
 def __init__(self, color, replace=(0,0,0,0), dist=0.0):
     self.color1 = rgba(color)
     self.color2 = rgba(replace)
     self.dist = dist
Esempio n. 37
0
class TextInput(Text):
    """Editable text GUI control:
    handles ondraw, onclick, ondrag, onkeydown, onblur;
    triggers onchange, onaction"""
    focusable = True
    cursorTime = 1.0
    cursorOn = 0.35
    promptColor = rgba("#d0d0d0")
    padding = 4
    allowButton = 1,
    blurAction = True
    _cursorX = 0
    _scrollX = 0
    _selection = None
    _highlight = None
    _submit = False

    def __init__(self, data="", prompt=None):
        super().__init__(str(data).split("\n")[0])
        self.cursor = len(self.data)
        self.cursorStatus = False
        self.prompt = prompt

    @property
    def highlight(self):
        if self._highlight: return self._highlight
        c = self.color
        return pygame.Color(c.r, c.g, c.b, 48)

    @highlight.setter
    def highlight(self, c): self._highlight = rgba(c)

    def _startCursor(self):
        self.stale = True
        self.cursorStatus = True
        self.cursorStart = self.sketch.frameCount

    def draw(self, srf):
        if self.focussed:
            sk = self.sketch
            try: n = (sk.frameCount - self.cursorStart) / sk.frameRate
            except: n = None
            if n is None or n > self.cursorTime: self._startCursor()
            else:
                c =  n < self.cursorOn
                if c is not self.cursorStatus:
                    self.cursorStatus = c
                    self.stale = True
        elif self.cursorStatus:
            self.cursorStatus = False
            self.stale = True
        return super().draw(srf)

    def render(self):
        "Render the text as an Image"
        font = Font.get(self.font, self.fontSize, self.fontStyle)
        try: focus = self is self.sketch.evMgr.focus
        except: focus = False
        prompt = self.prompt and not self.data and not focus
        if prompt:
            color = self.promptColor
            text = self.prompt
        else:
            color = self.color
            text = self.data
        try: srf = font.render(text, True, color)
        except:
            text = "[Unable to render!]"
            srf = font.render(text, True, color)
            if prompt: self.prompt = text
            else:
                self.data = text
                self.cursor = 0
        srf = style(srf, self.bg, self.border, self.weight, self.padding)

        # Highlight selection and draw cursor
        c = self.cursor
        if self.data:
            p0 = text[c-1:c] if c else text[0]
            p1 = text[c:c+1] if c < len(self.data) else text[-1]
            self._scrollPad = [font.size(p)[0] for p in (p0, p1)]
        else:
            self._scrollPad = 0, 0
        x = font.size(text[:c])[0]
        p = self.padding
        x += p
        self._cursorX = x
        h = srf.get_height()
        s = self._selection
        if s not in (None, self.cursor):
            x0 = font.size(text[:s])[0] + p
            w = abs(x - x0)
            s = pygame.Surface((w, h - 2 * p), pygame.SRCALPHA)
            s.fill(self.highlight)
            srf.blit(s, (min(x, x0), p))
        if self.cursorStatus:
            pygame.draw.line(srf, self.color, (x,p), (x,h-1-p), 2)
        return srf

    def _paste(self, data):
        "Paste the clipboard contents at the cursor location"
        clip = clipboardGet()
        if clip:
            for c in "\n\r\t": clip = clip.replace(c, "")
            c = self.cursor
            data = data[:c] + clip + data[c:]
            self.config(data=data)
            self.cursor += len(clip)
            return True

    def _selectRange(self):
        c = self.cursor
        s = self._selection
        if s is None: s = c
        else:
            tmp = max(s, c)
            c = min(s, c)
            s = tmp
        return c, s
        
    def deleteSelection(self):
        c, s = self._selectRange()
        if c == s: return False
        self.stale = True
        self.data = self.data[:c] + self.data[s:]
        self._selection = None
        self.cursor = c
        return True

    def onkeydown(self, ev):

        # Process 'submit' action
        u = ev.unicode
        if u in ("\n", "\r"): #, "\t"):
            self._submit = True
            self.blur(True)
            self._submit = False
            return

        # Ignore keys with Ctrl or Alt modifier (except Ctrl+[ACVX])
        k = ev.key
        acvx = [ord(c) for c in "acvxACVX"]
        if (ev.mod & KMOD_ALT or (ev.mod & KMOD_CTRL and k not in acvx)):
            return

        # Mark rendering as stale
        self.stale = True
        self._startCursor()
        cursor = self.cursor
        data = self.data
        n = len(data)

        # Process Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X
        if ev.mod & KMOD_CTRL:
            acvx = acvx.index(k) % 4
            if acvx % 2:
                c, s =  self._selectRange()
                if c != s: clipboardPut(data[c:s])
            if acvx == 0:
                self._selection = 0
                self.cursor = n
            elif acvx > 1:
                change = self.deleteSelection()
                if acvx == 2:
                    if self._paste(self.data): change = True
                if change: self.bubble("onchange", ev)
            return

        # Arrow keys
        if k in (K_LEFT, K_RIGHT, K_HOME, K_END):
            if ev.mod & KMOD_SHIFT:
                if self._selection is None: self._selection = cursor
            else: self._selection = None
            if cursor:
                if k == K_LEFT: cursor -= 1
                elif k == K_HOME: cursor = 0
            if cursor < n:
                if k == K_RIGHT: cursor += 1
                elif k == K_END: cursor = n
            self.cursor = cursor
            return

        # Backspace and delete
        if k in (K_BACKSPACE, K_DELETE):
            if self.deleteSelection(): cursor = self.cursor
            elif cursor and k == K_BACKSPACE:
                self.data = data[:cursor-1] + data[cursor:]
                cursor -= 1
            elif cursor < n and k == K_DELETE:
                self.data = data[:cursor] + data[cursor+1:]

        # Character keys
        if k >= 32 and k < 127:
            if self.deleteSelection():
                cursor = self.cursor
                data = self.data
            self.data = data[:cursor] + u + data[cursor:]
            cursor += 1

        # Finish up
        self.cursor = cursor
        if self.data != data:
            self._selection = None
            self.bubble("onchange", ev)

    def _widthTo(self, i):
        font = Font.get(self.font, self.fontSize, self.fontStyle)
        d = self.data
        return (font.size(d[:i])[0] + font.size(d[:i+1])[0]) // 2

    def onclick(self, ev):
        drag = ev.handler == "ondrag" 
        if drag or ev.button in self.allowButton:
            self._startCursor()
            x = self.relXY(ev.pos)[0] - self.padding
            n = len(self.data)
            i = 0
            while i < n and x > self._widthTo(i): i += 1
            k = self.sketch.key
            if drag or k and k.type == KEYDOWN and k.key in (K_LSHIFT, K_RSHIFT):
                if self._selection is None:
                    self._selection = self.cursor
            else: self._selection = None
            self.cursor = i
            self.stale = True
        elif not hasattr(self, "cursorStart"): self.blur()

    ondrag = onclick

    def onblur(self, ev):
        self._selection = None
        if not self.data: self.stale = True
        if hasattr(self, "cursorStart"): del self.cursorStart
        cv = self.canvas
        if (self._submit or self.blurAction) and not (ev.focus is cv and isinstance(cv, TextInputCanvas) and cv.ti is self):
            self.bubble("onaction", ev)

    def _scrollCalc(self, a):
        """Calculate how many pixels to scroll to keep the
           text insertion point visible within the canvas"""
        if a not in (0, 90): raise ValueError(_ANGLE_ERROR)
        if a: a = 1
        cv = self.canvas
        width = cv.size[a]
        if self.width < width: return 0, False
        pad = self.padding
        x = self.rect.topleft[a] + self._cursorX - cv.rect.topleft[a]
        p0, p1 = self._scrollPad
        c = self.cursor
        if c == 0: p0 = 0
        if c == len(self.data): p1 = 0
        if x < pad + p0: pix = pad + p0 - x
        else:
            pad += p1
            width -= pad + 1
            if x > width: pix = width - x
            else: pix = 0
        return pix, True

    def scroll(self, pix=None, rel=True):
        # Calculate scroll when not specified
        a = self.angle
        if pix is None: pix = self.focussed and a in (0, 90)
        if pix is False: pix, rel = 0, False
        elif pix is True: pix, rel = self._scrollCalc(a)

        # Set scrolling attributes
        if pix or not rel:
            if rel: self._scrollX += pix
            else:
                tmp = pix
                pix -= self._scrollX
                self._scrollX = tmp
            if pix:
                if a == 90: self.pos = self.pos[0], self.pos[1] + pix
                else: self.pos = sigma(self.pos, vec2d(pix, a))
        return self

    ondraw = scroll
Esempio n. 38
0
class Canvas(Graphic):
    _border = rgba("black")
    _scroll = 0, 0
    clipArea = None
    weight = 0
    resizeContent = True
    iconSize = 32, 32

    @staticmethod
    def _px(x):
        return x

    _cs = _px

    def __init__(self, image, bg=None):
        mode = 0 if type(image) is str else 1 if isinstance(image,
                                                            Image) else 2
        if mode == 2:  # tuple or list
            size = image
        elif bg:
            bg = Image(image, bg)
            size = bg.size
        else:  # str or Image
            bg = image if mode else Image(image)
            size = bg.size
        self._size = size
        self._items = []
        self.icons = []  # !!!
        self.bg = bg

    @property
    def clockwise(self):
        return True

    @property
    def units(self):
        return 1, 1

    @property
    def unit(self):
        return 1

    def px(self, *pt):
        return delta(self._px(pt), self._scroll)

    def cs(self, *pt):
        return self._cs(sigma(pt, self._scroll))

    def call(self, methodname, seq, *args, **kwargs):
        "Call the specified method on the canvas contents"
        if type(seq) is bool:
            seq = self.everything() if seq else self
        for obj in seq:
            fn = getattr(obj, methodname, None)
            if fn: fn(*args, **kwargs)

    @property
    def border(self):
        return self._border

    @border.setter
    def border(self, color):
        self._border = rgba(color)

    @property
    def clipRect(self):
        "Calculate the clipping rect so as not to draw outside of the canvas"
        cv = self.canvas
        r = self.rect
        if self.clipArea: r = r.clip(self.clipArea.move(*r.topleft))
        return r.clip(cv.clipRect) if cv else r

    @property
    def angle(self):
        return 0

    @property
    def bg(self):
        return self._bg

    @bg.setter
    def bg(self, bg):
        self._setBg(bg)

    def _setBg(self, bg):
        t = type(bg)
        if t is str: bg = pygame.Color(bg)
        elif t in (tuple, list): bg = pygame.Color(*bg)
        self._bg = bg

    @property
    def avgColor(self):
        bg = self.bg
        return bg.avgColor if isinstance(bg, Image) else bg

    def _paint(self, p1, p2, c=(255, 0, 0), w=4):
        try:
            cs = self.bg._srf
        except AttributeError:
            msg = "painting on canvas requires a background image"
            raise AttributeError(msg)
        key, scaled = cs.scaled
        if scaled is cs.original:
            scaled = scaled.copy()
            cs.scaled = key, scaled
        pygame.draw.line(scaled, c, p1, p2, w)

    def __len__(self):
        return len(self._items)

    def __contains__(self, i):
        for gr in self._items:
            if gr is i or getattr(gr, "_name", None) == i: return True
        return False

    def __getitem__(self, i):
        if type(i) in (int, slice): return self._items[i]
        if i:
            for gr in self._items:
                if getattr(gr, "_name", None) == i: return gr
        raise KeyError("{} contains no items with key '{}'".format(self, i))

    def __setitem__(self, key, gr):
        t = type(key)
        if not key.__hash__:
            raise KeyError("Type '{}' cannot be used as a key".format(
                t.__name__))
        elif t is slice:
            raise KeyError("Assignment by layer is not supported")
        if gr not in self:
            if t is int:
                n = key
                key = None
            gr.setCanvas(self, key)
            if t is int: gr.config(layer=n)

    def __iadd__(self, gr):
        "Add a Graphics instance(s) to the Canvas"
        if isinstance(gr, Graphic): gr.setCanvas(self)
        else:
            for g in gr:
                g.setCanvas(self)
        return self

    def __isub__(self, gr):
        "Remove item(s) from the canvas"
        if isinstance(gr, Graphic):
            if gr in self: gr.remove()
            else: raise ValueError("Cannot remove {} from {}".format(gr, self))
        else:
            for g in gr:
                self -= g
        return self

    append = __iadd__

    def purge(self, recursive=False):
        "Remove all content"
        while len(self._items):
            gr = self[-1]
            if recursive and isinstance(gr, Canvas): gr.purge()
            gr.remove()

    def shiftContents(self, offset, *args, resize=True):
        "Move contents and (optionally) adjust canvas size"
        dx, dy = offset
        for gr in self:
            if gr not in args:
                x, y = gr.pos
                gr.pos = x + dx, y + dy
        if resize:
            self._size = self._size[0] + dx, self._size[1] + dy
        return self

    def resize(self, size, resizeContent=None):
        "Resize the canvas contents"
        size = max(1, round(size[0])), max(1, round(size[1]))
        fx, fy = size[0] / self._size[0], size[1] / self._size[1]
        self._size = size

        # Resize content
        if resizeContent is None: resizeContent = self.resizeContent
        if resizeContent:
            for g in self:
                if g.autoPositionOnResize: g.scaleVectors(fx, fy)
                w, h = g.size
                g.resize((w * fx, h * fy))

    def draw(self, srf=None, mode=3):
        "Draw the canvas to a surface"

        # Calculate blit rectangle
        if srf is None: srf = self.image
        self.rect = r = self.calcBlitRect(self.size)

        # Draw background
        isSketch = isinstance(self, Sketch)
        if mode & 1:
            srf.set_clip(self.clipRect)
            if isinstance(self._bg, Image):
                self._bg.config(size=self._size)
                if isSketch and self.dirtyRegions:
                    self._drawDirtyRegions(srf)
                else:
                    srf.blit(self._bg.image, r.topleft)
            elif self._bg:
                srf.fill(self._bg)

        # Draw objects
        if mode & 2:
            br = isSketch and self.dirtyRegions is not None
            if br: self.dirtyRegions = []
            ondrawList = self.sketch.ondrawList
            for g in list(self):
                srf.set_clip(self.clipRect)
                if not hasattr(g, "image") and g.effects:
                    img = g.snapshot()
                    for a in ["pos", "anchor", "canvas", "effects"]:
                        setattr(img, a, getattr(g, a))
                    grect = img.draw(srf)
                else:
                    grect = g.draw(srf)
                g.rect = grect
                if br: self.dirtyRegions.append(grect)
                if g.ondraw: ondrawList.append(g)  # g.ondraw()

        # Draw border
        if mode & 1 and self.weight:
            drawBorder(srf, self.border, self.weight, r)

        srf.set_clip(None)
        return r

    def snapshot(self):
        "Capture the canvas as an Image instance"
        srf = pygame.Surface(self.size, pygame.SRCALPHA)

        # Draw background
        if isinstance(self._bg, Image):
            self._bg.config(size=self._size)
            srf.blit(self._bg.image, (0, 0))
        elif self._bg:
            srf.fill(self._bg)

        # Draw objects
        for g in self:
            if g.snapshot is not None:
                img = g.snapshot().image
                srf.blit(img, g.blitPosition((0, 0), img.get_size()))


#                 xy = g.blitPosition((0,0), g.size)
#                 srf.blit(g.snapshot().image, xy)
            else:
                g.draw(srf, snapshot=True)

        # Draw border
        if self.weight: drawBorder(srf, self.border, self.weight)
        return Image(srf)

    def flatten(self, keep=()):
        "Draw graphics onto background and remove"
        if isinstance(keep, Graphic): keep = (keep, )
        keep = [(gr.name, gr) for gr in keep]
        for gr in keep:
            gr[1].remove()
        self.config(bg=self.snapshot()).purge()
        for name, gr in keep:
            if name: self[name] = gr
            else: self += gr
        return self

    def objectAt(self, pos, includeAll=False):
        obj = self
        for g in self:
            try:  # Objects added but not yet blitted have no rect
                if (includeAll or g.hoverable) and g.contains(pos):
                    obj = g.objectAt(pos) if isinstance(g, Canvas) else g
            except:
                pass
        return obj

    def instOf(self, cls):
        "Yield all instance of the specified Graphics class"
        for g in self:
            if isinstance(g, cls): yield g

    def sprites(self):
        return self.instOf(BaseSprite)

    def everything(self):
        "Iterate through all Graphics recursively"
        for gr in self:
            yield gr
            if isinstance(gr, Canvas):
                for i in gr.everything():
                    yield i

    def find(self, criteria, recursive=False):
        "Yield all Graphics that meet the criteria"
        for gr in (self.everything() if recursive else self):
            if criteria(gr): yield gr

    def scroll(self, dx=0, dy=0):
        raise NotImplementedError("Use PCanvas class to scroll.")

    def cover(self):
        return Image(self.size, "#ffffffc0").config(anchor=TOPLEFT)
Esempio n. 39
0
    def highlight(self, c): self._highlight = rgba(c)

    def _startCursor(self):
Esempio n. 40
0
 def __init__(self, noise=0.15, fill=(0, 0, 0, 0)):  #, eqn=None):
     self.fill = rgba(fill)
     self.above = noise > 0
     self.noise = abs(noise)
Esempio n. 41
0
    def stroke(self, s): self._stroke = rgba(s) if s else None

    def __init__(self, x, y=None, param=None):
Esempio n. 42
0
from sc8pr import Sketch, Canvas, Image, TOPLEFT, TOPRIGHT, CENTER, TOP
from sc8pr.util import rgba, nothing, sc8prData
from sc8pr.text import BOLD, Font
from sc8pr.gui.textinput import TextInput
from sc8pr.gui.radio import Radio, Options
from sc8pr.gui.slider import Slider
from sc8pr.gui.button import Button
from sc8pr.gui.menu import Menu, R_TRIANGLE

try:  # v2.2
    from sc8pr.gui.textinput import TextInputCanvas
except:  # v2.0-2.1
    TextInputCanvas = None

GREY, BLUE = rgba("#ececec", "blue")
FONT = Font.sans()


def setup(sk):
    # Create a Canvas as a GUI dialog
    cv = Canvas((384, 256)).config(bg="#f0f0ff", weight=1)

    # Vertical positioning 16 pixels below last item added
    down = lambda cv: 16 + cv[-1].height

    text = dict(color=BLUE, font=FONT, fontStyle=BOLD, padding=4)
    if TextInputCanvas:  # v2.2.dev
        ti = TextInputCanvas(336, "", "Type Some Text...", **text)
    else:  # v2.0-2.1
        ti = TextInput("", "Type Some Text...").config(**text)
Esempio n. 43
0
 def border(self, color):
     self._border = rgba(color)
Esempio n. 44
0
def _tempColor(px, color, *args):
    "Replace one color with a random RGB color"
    c = color
    while c in args: c = rgba(False)
    if c != color: px.replace(color, c)
    return c
Esempio n. 45
0
 def __init__(self, color=(255, 255, 255, 0)):
     self.color = rgba(color)
Esempio n. 46
0
 def __init__(self, clockwise=True, fill=(0,0,0,0)):
     self.fill = rgba(fill)
     self.cw = clockwise
Esempio n. 47
0
 def __init__(self, slope=False, above=True, fill=(0, 0, 0, 0)):
     self.slope = slope
     self.above = above
     self.fill = rgba(fill)
Esempio n. 48
0
class Series:
    "Represents a single data series within the plot"
    _stroke = rgba((0, 0, 0))
    weight = 0
    marker = None

    @property
    def stroke(self):
        return self._stroke

    @stroke.setter
    def stroke(self, s):
        self._stroke = rgba(s) if s else None

    def __init__(self, x, y=None, param=None):
        self._data = x if y is None else list(zip(x, y))
        self.param = param
        self.vars = {}

    def __getitem__(self, i):
        return self._data[i]

    def __setitem__(self, i, pt):
        self._data[i] = pt

    config = Graphic.config

    def pointGen(self):
        "Iterable sequence of points"
        data = self._data
        return data if type(data) in (list, tuple) else locus(
            data, self.param, **self.vars)

    @property
    def pointList(self):
        "Return data as a new list"
        return list(self.pointGen())

    def dataGen(self, n):
        "Generate values from x or y column of data table"
        for pt in self.pointGen():
            yield pt[n]

    @property
    def x(self):
        return list(self.dataGen(0))

    @property
    def y(self):
        return list(self.dataGen(1))

    def regression(self, model=leastSq):
        return model(*[list(self.dataGen(i)) for i in (0, 1)])

    def transform(self, **kwargs):
        "Apply a transformation to the data points"
        try:
            self._data = list(transform2dGen(self._data, **kwargs))
        except:
            raise TypeError(
                "Series.transform cannot be applied to an equation")
        return self

    def draw(self, srf, transform):
        "Plot one data series onto a surface"

        # Plot stroke
        pts = [transform(p) for p in self.pointGen()]
        s, w = self.stroke, self.weight
        if s and w: pygame.draw.lines(srf, rgba(s), False, pts, w)

        # Plot markers
        marker = self.marker
        if marker:
            i = 0
            for p in pts:
                if isinstance(marker, Graphic): img = marker
                else:
                    img = marker[i]
                    i += 1
                if img.canvas: img.remove()
                img.pos = p
                sz = img.size
                if img.angle: sz = rotatedSize(*sz, img.angle)
                pos = img.blitPosition((0, 0), sz)
                srf.blit(img.image, pos)

    @staticmethod
    def _lattice(x=0, y=0):
        "Generate a lattice of points"
        num = int, float
        x = (x, ) if type(x) in num else rangef(*x)
        y = (y, ) if type(y) in num else list(rangef(*y))
        for i in x:
            for j in y:
                yield i, j

    @staticmethod
    def _tick(param, marker=9, y=False, **kwargs):
        if type(marker) is int: marker = ((9, 1) if y else (1, 9), "black")
        label = type(marker) is str
        if not (label or isinstance(marker, Graphic)):
            marker = Image(*marker)
        s = list(Series._lattice(0, param) if y else Series._lattice(param, 0))
        if label:
            isZero = (lambda x: _isZero(x, marker)) if kwargs.get("omitZero")\
                else (lambda x: False)
            i = 1 if y else 0
            text = list(marker.format(x[i]) for x in s)
            marker = [
                Text("" if isZero(x) else x).config(**kwargs) for x in text
            ]
        return Series(s).config(marker=marker)

    def scaleMarkers(self, s):
        marker = self.marker
        if isinstance(marker, Graphic): marker = [marker]
        if marker:
            for gr in marker:
                gr.height *= s
Esempio n. 49
0
 def pen(self, p):
     if p and len(p) == 2:
         p = p + (self._pen[2] if self._pen else None,)
     if p: p = (rgba(p[0]),) + p[1:]
     self._pen = p
Esempio n. 50
0
    def border(self, color): self._border = rgba(color)

    @property
Esempio n. 51
0
 def __init__(self, color, replace=(0, 0, 0, 0), dist=0.0):
     self.color1 = rgba(color)
     self.color2 = rgba(replace)
     self.dist = dist
Esempio n. 52
0
 def __init__(self, noise=0.15, fill=(0,0,0,0)):#, eqn=None):
     self.fill = rgba(fill)
     self.above = noise > 0
     self.noise = abs(noise)