Esempio n. 1
0
    def __init__(self,
                 x=None,
                 y=None,
                 w=None,
                 h=None,
                 name=None,
                 template=None,
                 fill=None,
                 stroke=None,
                 strokeWidth=0,
                 pt=None,
                 pr=None,
                 pb=None,
                 pl=None):
        self.x = x or 0  # (x, y) position of the element from bottom left of parent.
        self.y = y or 0
        self.w = w  # Width and height of the element bounding box
        self.h = h
        self.fill = color(fill)  # Default is drawing a black rectangle.
        self.stroke = color(stroke)  # Default is drawing no stroke frame
        self.strokeWidth = strokeWidth
        self.padding = pt, pr, pb, pl  # Initialize the padding
        self.elements = []  # Storage in case there are child elements

        # Optional name, e.g. for template or element finding. Defaults to class name.
        self.name = name or self.__class__.__name__
        self.template = template  # Optional template function for this element.

        # Allow elements, pages and templates to initialize themselves
        # by implementing the self.initialize method.
        self.initialize()
Esempio n. 2
0
    def _extractColor(self, layer):
        fillColor = noColor
        if layer.style.fills:
            fill = layer.style.fills[0]
            if fill.isEnabled:  # In Sketch colors can be defined, and still be disabled.
                sketchColor = fill.color
                fillColor = color(r=sketchColor.red,
                                  g=sketchColor.green,
                                  b=sketchColor.blue,
                                  a=sketchColor.alpha)

        strokeColor = noColor
        strokeWidth = 0
        sketchBorders = layer.style.borders
        if sketchBorders:
            # TODO: Extract element border info here too
            sketchBorder = sketchBorders[0]
            if sketchBorder.isEnabled:  # In Sketch colors can be defined, and still be disabled.
                sketchColor = sketchBorder.color
                strokeColor = color(r=sketchColor.red,
                                    g=sketchColor.green,
                                    b=sketchColor.blue,
                                    a=sketchColor.alpha)
                strokeWidth = pt(sketchBorder.thickness)

        return fillColor, strokeColor, strokeWidth
Esempio n. 3
0
    def textColor(self, base, shade):
        """Answer the shade of base color that words best as text foreground
        on the `shade` color.

        >>> from pagebotnano.themes import BackToTheCity
        >>> theme = BackToTheCity()
        >>> theme.textColor(3, 0).name
        'black'
        """
        c = self.colors[base][shade]
        if c.averageRgb < 0.4:
            return color(1)
        return color(0)
Esempio n. 4
0
    def fromBabelString(self, bs):
        """

        >>> bs = BabelString('abcd', style=dict(font='Roboto-Regular', fontSize=pt(18)))
        >>> context = SketchContext()
        >>> sas1 = context.fromBabelString(bs)
        >>> sas1
        <SketchAttributedString>
        >>> sas2 = context.fromBabelString(bs)
        >>> sas1 == sas2
        True
        """
        assert isinstance(bs, BabelString)
        ALIGNMENTS = {LEFT: 0, RIGHT: 1, CENTER: 2, JUSTIFIED: None}
        cIndex = 0
        sas = SketchAttributedString()
        sas.string = ''
        style = None
        attrs = sas.attributes
        for run in bs.runs:
            if style is None or run.style is not None:
                style = run.style
            ssa = SketchStringAttribute()
            ssa.location = cIndex
            ssa.length = len(run.s)
            sas.string += run.s
            cIndex += ssa.length

            ssa.attributes.MSAttributedStringFontAttribute = SketchFontDescriptor(
            )
            fd = ssa.attributes.MSAttributedStringFontAttribute.attributes
            fontName = run.style.get('fontName')
            font = run.style.get('font')
            if fontName is None:
                if isinstance(font, str):
                    fontName = font
                elif isinstance(font, Font):
                    fontName = font.name
            if fontName is None:
                fontName = DEFAULT_FONT
            fd.name = fontName
            fd.size = upt(run.style.get('fontSize', 12))
            tc = run.style.get('textFill', color(0))

            # Leading is a special thing in Sketch!
            ssa.attributes = SketchAttributes()
            ssa.attributes.kerning = upt(style.get('tracking', 0),
                                         base=fd.size)
            ssa.attributes.textStyleVerticalAlignmentKey = 0  # ???
            ssa.attributes.paragraphStyle = SketchParagraphStyle()
            ssa.attributes.paragraphStyle.alignment = ALIGNMENTS.get(
                style.get('xAlign', JUSTIFIED))

            ssa.attributes.MSAttributedStringColorAttribute = SketchColor(
                red=tc.r, green=tc.g, blue=tc.b, alpha=tc.a)
            attrs.append(ssa)
        return sas
Esempio n. 5
0
    def compose(self, doc, parent=None):
        """Compose the cell as background color, with recipes text block on top.

        """
        label = self._getLabel()

        if self.layout == SPOTSAMPLE:
            # Mark approximated color recipes by parenthesis.
            # They are not an exact match, but closest known value for this color.

            bs = BabelString(label, self.style)
            tw, th = bs.textSize

            # Used padding-bottom (self.pb) also as gutter between color rectangle and labels
            e = Rect(x=self.pl, y=th+self.pb, w=self.pw, h=self.h-th-self.pb, fill=self.c)
            self.addElement(e)

            e = Text(bs, x=self.w/2, y=th-self.style.get('fontSize') + self.pb, w=self.w, h=self.h)
            self.addElement(e)

        else: # Default layout is OVERLAY. 
            # Check the text color to be enough contrast with the background.
            # Otherwise flip between black and white.
            style = copy(self.style) # Copy as we are going to alter it
            if self.c.gray < 0.33: # Dark color?
                labelText = color(1) # White label text
            else:
                labelText = color(0) # Black label text
            style['fill'] = labelText
            bs = BabelString(label, style)
            tw, th = bs.textSize

            e = Rect(x=self.pl, y=self.pb, w=self.pw, h=self.ph, fill=self.c)
            self.addElement(e)

            e = Text(bs, x=self.w/2, y=th-self.style.get('fontSize')*2/3 + self.pb, w=self.w, h=self.h)
            self.addElement(e)
Esempio n. 6
0
class HappyHolidays(BaseTheme):
    NAME = 'Happy Holidays'
    BASE_COLORS = dict(
        base0=color(1, 0, 0.2),
        base1=color(0.7, 0.1, 0.2),
        base2=color(0.9, 0, 0.3),
        base3=color(0.5, 0.96, 0.2),
        base4=color(0, 1, 0),
        base5=color(0.55, 0.5, 0.5),
    )
Esempio n. 7
0
    def fill(self, c):
        """Set the fill mode of the context. `c` can be None, a number,
        a name or a Color instance. 

        >>> context = DrawBotContext()
        >>> context.fill(None)
        >>> context.fill('red')
        >>> context.fill((1, 0, 0))
        >>> context.fill(Color(1, 0, 0))
        >>> context.fill(0.5)
        """
        if c is None:
            drawBot.fill(None)
        else:  # Make sure is it a Color instance.
            if not isinstance(c, Color):
                c = color(c)
            r, g, b, a = c.rgba
            drawBot.fill(r, g, b, a)
Esempio n. 8
0
    def stroke(self, c, strokeWidth=None):
        """Set the stroke mode of the context. `c` can be None, a number,
        a name or a Color instance. 

        >>> context = DrawBotContext()
        >>> context.stroke(None)
        >>> context.stroke('red')
        >>> context.stroke((1, 0, 0))
        >>> context.stroke(Color(1, 0, 0))
        >>> context.stroke(0.5, 1)
        """
        if strokeWidth is not None:
            self.strokeWidth(strokeWidth)
        if c is None:
            drawBot.stroke(None)
        else:  # Make sure it is a Color instance.
            if not isinstance(c, Color):
                c = color(c)
            r, g, b, a = c.rgba
            drawBot.stroke(r, g, b, a)
Esempio n. 9
0
    def asBabelString(self, sas):
        """Convert the SketchAttributedString skText into a generic BabelString.

        * https://developer.apple.com/documentation/foundation/nsattributedstring
        * https://developer.apple.com/documentation/coretext/ctframesetter-2eg

        >>> import pysketch
        >>> from pysketch.sketchapi import SketchApi
        >>> path = getResourcesPath() + '/sketch/TemplateText.sketch'
        >>> context = SketchContext(path)
        >>> skTextBox = context.b.artboards[0].layers[0] # Find the Sketch text box
        >>> sas = skTextBox.attributedString # SketchText inside the box
        >>> sas
        <SketchAttributedString>
        >>> len(sas.attributes)
        3
        >>> bs = context.asBabelString(sas) # Convert to generic BabelString
        >>> len(bs.runs) # We originally had 3 typographic parameter runs
        3
        >>> bs # Represented by joining text strings of all runs
        $Type & sty...$
        >>> bs.runs[0].s, bs.runs[0].style['font'], bs.runs[0].style['fontSize']
        ('Type ', <Font PageBot-Book>, 90)
        >>> bs.runs[1].s, bs.runs[1].style['font'], bs.runs[1].style['fontSize']
        ('&', <Font PageBot-Book>, 200)
        """

        """
        >>> sas2 = context.fromBabelString(bs) # New conversion
        >>> #sas == sas2 # Bi-directional conversion works
        True
        >>> # Now change the BabelString
        >>> bs.runs[0].style['font'] = 'Verdana-Bold'
        >>> bs.runs[1].style['font'] = 'Verdana-Italic'
        >>> bs.runs[1].style['textFill'] = color(1, 0, 0)
        >>> bs.runs[2].style['textFill'] = color(1, 0, 0.5)
        >>> bs.runs[2].s = ' changed' # Change text of the run
        >>> sas2 = context.fromBabelString(bs) # New conversion
        >>> skTextBox.attributedString = sas2
        >>> from pagebot.filepaths import getExportPath
        >>> context.save('%s/TemplateTextChanged.sketch' % getExportPath()) # Save as other document
        >>> bs2 = context.asBabelString(sas2) # Convert back to pbs
        >>> bs == bs2 # This should be identical, after bi-directional conversion.
        True
        """
        assert isinstance(sas, SketchAttributedString), "%s.asBabelString: @sas has class %s" % (
            self.__class__.__name__, sas.__class__.__name__)
        ALIGNMENTS = {0: LEFT, 1: RIGHT, 2: CENTER, None: JUSTIFIED}
        bs = None
        for attrs in sas.attributes:
            # Font, fontSize and tracking are easy to extract.
            # More difficult is the leading, as Skype does not really keep
            # runs with styles and leading.
            fd = attrs.attributes.MSAttributedStringFontAttribute.attributes
            font = findFont(fd.name)
            if font is None: # If not found (e.g. OSX name, then keep the name)
                print('### Font not found or not supported type (.ttc) "%s", using "%s" instead' % (fd.name, DEFAULT_FONT))
                font = findFont(DEFAULT_FONT)
            fontSize = fd.size
            tracking = em(attrs.attributes.kerning/fontSize) # Wrong Sketch name for tracking

            #print('----', attrs)
            # attrs = SketchStringAttribute
            #   location
            #   length
            #   attributes = SketchAttributes
            #     MSAttributedStringFontAttribute
            #     MSAttributedStringColorAttribute
            #     textStyleVerticalAlignmentKey
            #     kerning
            #     paragraphStyle = SketchParagraphStyle
            #         alignment
            #         minimumLineHeight
            #         maximumLineHeight
            #         paragraphSpacing
            #print('----', sas.string[attrs.location:attrs.location+attrs.length])
            #print('fontSize:', fd.name, fd.size)
            #print('minimumLineHeight:', attrs.attributes.paragraphStyle.minimumLineHeight)
            #print('maximumLineHeight:', attrs.attributes.paragraphStyle.maximumLineHeight)
            #print('paragraphSpacing:', attrs.attributes.paragraphStyle.paragraphSpacing)
            #print('...')

            #print('--d-d-d-', verticalAlignment)
            #paragraphStyle.maximumLineHeight)
            #print('3-3-3-', paragraphStyle.alignment)

            paragraphStyle = attrs.attributes.paragraphStyle
            leading = em(paragraphStyle.maximumLineHeight/fontSize)
            #minLeading = paragraphStyle.minimumLineHeight
            #maxLeading = paragraphStyle.maximumLineHeight
            #paragraphSpacing = paragraphStyle.paragraphSpacing

            #print('vvvvvv', font, fontSize, leading, paragraphStyle, tracking)
            #print('xxxxxx', minLeading, maxLeading, paragraphSpacing)
            # Fill color of the this run.
            cc = attrs.attributes.MSAttributedStringColorAttribute
            textFill = color(r=cc.red, g=cc.green, b=cc.blue, a=cc.alpha)
            # 0 = TOP,
            verticalAlignment = attrs.attributes.textStyleVerticalAlignmentKey
            # Construct the run style from the extracted parameters.
            style = dict(font=font, fontSize=fontSize, textFill=textFill,
                tracking=tracking, yAlign=BASELINE, leading=leading,
                xAlign=ALIGNMENTS.get('alignment', LEFT)
            )
            # Get the string, using the location and length in the full string.
            s = sas.string[attrs.location:attrs.location+attrs.length]
            if bs is None:
                bs = self.newString(s, style)
            else:
                bs.add(s, style)

            #bs.MIN = paragraphStyle.minimumLineHeight
            #bs.MAX = paragraphStyle.maximumLineHeight
        return bs