Ejemplo n.º 1
0
    def __init__(self, initialValueStr, minValue, maxValue, dispDigitNo, tooltipStr):
        assert sorted(LengthEditor.UNITNAMES) == sorted(UsrParams.LENGTH_UNIT_DICT.keys())
        assert sorted(LengthEditor.UNITTITLEDICT.keys()) == sorted(LengthEditor.UNITNAMES)
        assert isfinite(minValue) and isfinite(maxValue)
        assert minValue < maxValue

        r = UsrParams.parseLength(initialValueStr)
        assert r is not None
        initialValue, initialUnitName, initialValueInPx = r
        del r

        self.valueSpinner = None
        self.unitCombo = None

        adj = Gtk.Adjustment(value=initialValue,
                             lower=minValue, upper=maxValue, step_increment=0.1, page_increment=1.0)
        self.valueSpinner = Gtk.SpinButton(adjustment=adj, climb_rate=0.0, digits=dispDigitNo)
        self.valueSpinner.set_numeric(True)
        self.valueSpinner.set_tooltip_text(tooltipStr)
        self.valueSpinner.show()

        self.unitCombo = Gtk.ComboBoxText()
        self.unitCombo.set_tooltip_text(
            u'Note: "px" means "user unit" in SVG terminology.\n'
          + u'Its size is a pixel width at a resolution of 90 dpi.')
        for unitName in LengthEditor.UNITNAMES:
            self.unitCombo.append_text(LengthEditor.UNITTITLEDICT[unitName])
        self.unitCombo.set_active(LengthEditor.UNITNAMES.index(initialUnitName))
        self.unitCombo.show()

        self.hbox = Gtk.HBox()
        self.hbox.pack_start(self.valueSpinner, True, True, 0)
        self.hbox.pack_start(self.unitCombo, False, False, 0)
Ejemplo n.º 2
0
    def addSignalPath(self, pathIndex, verticesList, yScale, startPoint):
        """
        Inserts a signal path element below this node, consisting of line segments
        according to the given vertices.

        verticesList is a (possibly) empty list of vertex lists.
        Each vertex list is a list of at least 2 tuples (x, y) of vertex positions.
        The y-coordinates are inverted (increase: towards the top of the canvas).

        startPoint is None or (startPointX, startPointY).
        If startPoint is None, all vertex positions are calculated
        as (x + startPointX, yScale * y + startPointY).

        If startPoint is not None, the first -- probably invisible -- point of the resulting path
        is startPoint.
        """
        assert self._node is not None
        assert pathIndex >= 0
        assert verticesList is not None
        assert startPoint is None or (isfinite(startPoint[0]) and isfinite(startPoint[1]))

        styleDict = {'stroke': 'black', 'fill': 'none'}
        p = PathElem.addCombinedLines(self._node, verticesList, yScale, startPoint, styleDict, False)
        p.setLabel(SignalGElem._LABEL_SIGNALPATH + str(pathIndex))
        return p
Ejemplo n.º 3
0
 def createRot(aDegree, c):
     cX, cY = c
     t = None
     if isfinite(cX) and isfinite(cY):
         t = PointTransf.createRot0(aDegree)
         t = PointTransf.createConcat(PointTransf.createTransl((cX, cY)), t)
         t = PointTransf.createConcat(t, PointTransf.createTransl(
             (-cX, -cY)))
     return t
Ejemplo n.º 4
0
    def addCombinedLines(parentNode, verticesList, yScale, startPoint, styleDict, doClose):
        """
        Inserts a 'path' element below parentNode, consisting of line segments
        according to the given vertices.

        verticesList is a (possibly empty) list of vertex lists.
        Each vertex list is a list of at least 2 tuples (x, y) of vertex positions.
        The y-coordinates are inverted (increase: towards the top of the canvas).

        startPoint is None or (startPointX, startPointY).
        If startPoint is None, all vertex positions are calculated
        as (x + startPointX, yScale * y + startPointY).

        If startPoint is not None, the first -- probably invisible -- point of the resulting path
        is startPoint.

        If doClose is True, all subpaths (built by element of verticesList) are closed.

        styleDict is a dictionary of properties for the "style" attribute.
        """
        if startPoint is None:
            startPointX, startPointY = (0, 0)
        else:
            startPointX, startPointY = startPoint
        parentNode = Elem(parentNode).getNode()
        assert verticesList is not None
        assert isfinite(yScale)
        assert isfinite(startPointX) and isfinite(startPointY)

        pathSpecs = []
        for vertices in verticesList:
            partPathSpec = None
            for x, y in vertices:
                if partPathSpec is None:
                    partPathSpec = 'M'
                else:
                    partPathSpec = partPathSpec + ' L'
                assert isfinite(x) and isfinite(y)
                partPathSpec = partPathSpec + ' {x},{y}'.format(x=startPointX + x, y=startPointY + yScale * y)
            if startPoint is not None and vertices[0] != (startPointX, startPointY):
                partPathSpec = 'M {x},{y} '.format(x=startPointX, y=startPointY) + partPathSpec
            if doClose:
                partPathSpec = partPathSpec + ' Z'
            pathSpecs.append(partPathSpec)
        pathSpec = ' '.join(pathSpecs)
        del pathSpecs

        attribs = {
            'style': simplestyle.formatStyle(styleDict),
            'd':     pathSpec
        }
        return PathElem(etree.SubElement(parentNode, inkex.addNS('path','svg'), attribs))
Ejemplo n.º 5
0
 def getLengthValue(lengthStr):
     value = float('nan')
     r = UsrParams.parseLength(lengthStr)
     if r is not None:
         x, unitStr, value = r
         assert isfinite(value)
     return value
Ejemplo n.º 6
0
 def buildLength(x, unitStr):
     assert isfinite(x)
     assert unitStr is None or unitStr in UsrParams.LENGTH_UNIT_DICT
     lengthStr = str(x)
     if unitStr is not None:
         lengthStr = lengthStr + unitStr
     return lengthStr
Ejemplo n.º 7
0
 def isValid(self):
     self.unitTimeWidth
     ok = UsrParams.getLengthValue(self.unitTimeWidth) > 0.0
     ok = ok and UsrParams.getLengthValue(self.signalHeight) > 0.0
     ok = ok and UsrParams.getLengthValue(self.edgeTimeWidth) >= 0.0
     ok = ok and UsrParams.getLengthValue(self.breakTimeWidth) > 0.0
     ok = ok and self.placementMethod in (u'homogeneous', u'individual')
     ok = ok and isfinite(UsrParams.getLengthValue(self.originDistY))
     ok = ok and UsrParams.getLengthValue(self.originDistY) > 0.0
     return ok
Ejemplo n.º 8
0
 def createSkewY(aDegree):
     t = None
     try:
         aDegreeMod = PointTransf._mod360Degree(2 * aDegree) / 2
         tanA = math.tan(math.radians(aDegreeMod))
         if isfinite(tanA):
             m = (1, 0, tanA, 1)
             t = PointTransf(m, (0, 0))
     except ValueError:
         pass
     return t
Ejemplo n.º 9
0
    def completeOriginsHomog(incomplSignalOriginDict, n, originDiff):
        """
        Returns a copy of a dictionary of signal origins, extended to a given number of signals.

        The first signal with an known? origin is used as "fix point" (not changed).
        The origins of all other signals are recalculated such that the difference of
        the origin of each signal to tje origin of the preceding signal is
        (originDiffX, originDiffY).

        incomplSignalOriginDict:
          non-empty dictionary (key: signal index 0 .. n - 1, value: signal origin).
          signal origin: (x, y) where x and y are not None.
        n: number of signals.
        (originDiffX, originDiffY):
            used as signal origin difference of adjacent signals,
            if len(incomplSignalOriginDict) < 2.

        Returns:
            signalOriginDict, an extended copy of incomplSignalOriginDict.
            For each signal index i with 0 <= i < n:
              signalOriginDict[i] is the signal origin
        """

        (originDiffX, originDiffY) = originDiff
        assert incomplSignalOriginDict is not None
        assert len(incomplSignalOriginDict) > 0
        assert None not in incomplSignalOriginDict.values()
        assert len(incomplSignalOriginDict) == 0 \
            or (min(incomplSignalOriginDict) >= 0 and max(incomplSignalOriginDict) < n)
        assert isfinite(originDiffX) and isfinite(originDiffY)

        signalOriginDict = dict()

        refSignalIndex = min(incomplSignalOriginDict)
        xR, yR = incomplSignalOriginDict[refSignalIndex]
        for signalIndex in range(0, n):
            di = signalIndex - refSignalIndex
            signalOriginDict[signalIndex] = float(
                di * originDiffX) + xR, float(di * originDiffY) + yR

        return signalOriginDict
Ejemplo n.º 10
0
 def parseLength(lengthStr):
     r = None
     if lengthStr is not None and isinstance(lengthStr, str):
         # http://www.w3.org/TR/2003/REC-SVG11-20030114/types.html
         lengthRegexp = re.compile(
             r'^(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)( *([a-zA-Z]+))?$'
         )
         m = lengthRegexp.match(lengthStr)
         if m is not None:
             try:
                 x = float(m.group(1))
                 if m.group(6) is None:
                     unitStr = u'px'
                 else:
                     unitStr = m.group(6)
                 pxPerUnit = UsrParams.LENGTH_UNIT_DICT[unitStr]
                 valueInPx = x * pxPerUnit
                 if isfinite(valueInPx):
                     r = (x, unitStr, valueInPx)
             except (ValueError, KeyError):
                 pass
     return r
Ejemplo n.º 11
0
    def effect(self):
        """Perform the effect: create/modify Timink object (signal cluster group)."""

        selectedSignalClusterGroup, sg, so = SignalClusterGElem.getSelected(
            self.svg.selected)
        try:
            if len(so) > 0:
                if len(so) == 1:
                    msg = 'Element selected which is not part of a signal cluster.'
                else:
                    msg = 'Elements selected which are not part of a signal cluster.'
                raise UserError(
                    msg,
                    'Do select at most one signal cluster (and nothing else).')
            if len(sg) > 0 and selectedSignalClusterGroup is None:
                raise UserError(
                    'More than one signal cluster selected.',
                    'Do select at most one signal cluster (and nothing else).')
            del so, sg

            signalClusterSpecStr = ''
            versionJoint = None
            usrParams = UsrParams()
            if selectedSignalClusterGroup is not None:
                selectedSignalClusterGroup = SignalClusterGElem(
                    selectedSignalClusterGroup)
                signalClusterSpecStr = selectedSignalClusterGroup.getSignalClusterSpec(
                )
                if signalClusterSpecStr is None:
                    signalClusterSpecStr = ''
                versionJoint = selectedSignalClusterGroup.getVersionJoint()
                r = UsrParams.parseStr(
                    selectedSignalClusterGroup.getUsrParams())
                if r is not None:
                    usrParams, invalidKeys, unsupportedParamKeys = r
                    if len(invalidKeys) > 0:
                        s = ', '.join(
                            map(escapeStringForUser, list(invalidKeys)))
                        printInfo(
                            'Signal cluster (selected): Ignored unsupported attributes:\n'
                            + s)
                    if len(unsupportedParamKeys) > 0:
                        s = ', '.join(
                            map(escapeStringForUser,
                                list(unsupportedParamKeys)))
                        printInfo(
                            'Signal cluster (selected): Ignored attributes with invalid values:\n'
                            + s)

            if selectedSignalClusterGroup is None:
                sgDict = None
                sgInfoDict, signalOriginDict, wasteElemDict = (dict(), dict(),
                                                               dict())
            else:
                sgDict = selectedSignalClusterGroup.getSignalGroups()
                sgInfoDict, signalOriginDict, wasteElemDict = self.analyzeExistingSignalGroups(
                    sgDict)

            r = SignalClusterEditor(signalClusterSpecStr, usrParams,
                                    versionJoint,
                                    len(signalClusterSpecStr) == 0,
                                    len(signalOriginDict) > 1).run()

            if r is not None:

                signalClusterSpecStr, usrParams = r
                signalSpecStrs = SignalClusterSpecValidator.normalize(
                    signalClusterSpecStr).split('\n')
                assert len(signalSpecStrs) > 0

                if selectedSignalClusterGroup is None:
                    # create new signal cluster group
                    scg = SignalClusterGElem.addEmpty(
                        self.svg.get_current_layer(), signalClusterSpecStr,
                        usrParams)
                else:
                    scg = selectedSignalClusterGroup
                    removedAttribs = sorted(
                        list(scg.setAttribs(signalClusterSpecStr, usrParams)))
                    if len(removedAttribs) > 0:
                        s = ', '.join(
                            map(lambda o: escapeStringForUser(o),
                                removedAttribs))
                        printInfo(
                            'Signal cluster (selected): Removed unsupported attributes: '
                            + s)
                        del s
                    sgInfoDict, signalOriginDict, wasteElemDict = \
                        self.cleanupExistingSignalGroups(len(signalSpecStrs), sgDict, sgInfoDict,
                            signalOriginDict, wasteElemDict)
                del sgDict

                # set/complete signal origins
                centerOfView = (round(self.svg.namedview.center[0]),
                                round(self.svg.namedview.center[1]))
                originDistY = UsrParams.getLengthValue(usrParams.originDistY)
                originDistX = UsrParams.getLengthValue(usrParams.originDistX)
                assert isfinite(originDistX) and isfinite(originDistY)
                if len(signalOriginDict) == 0:
                    signalOriginDict[0] = centerOfView
                if len(signalOriginDict
                       ) <= 1 or usrParams.placementMethod == 'homogeneous':
                    signalOriginDict = TiminkEffect.completeOriginsHomog(
                        signalOriginDict, len(signalSpecStrs),
                        (originDistX, originDistY))
                else:
                    signalOriginDict = TiminkEffect.completeOriginsByInterp(
                        signalOriginDict, len(signalSpecStrs))
                del originDistX
                del originDistY

                unitTimeWidth = UsrParams.getLengthValue(
                    usrParams.unitTimeWidth)
                assert isfinite(unitTimeWidth)
                signalHeight = UsrParams.getLengthValue(usrParams.signalHeight)
                assert isfinite(signalHeight)
                edgeTimeWidth = UsrParams.getLengthValue(
                    usrParams.edgeTimeWidth)
                assert isfinite(edgeTimeWidth)
                breakTimeWidth = UsrParams.getLengthValue(
                    usrParams.breakTimeWidth)
                assert isfinite(breakTimeWidth)

                # add / update signal groups according to sgInfoDict, signalOriginDict, signalSpecStrs
                for signalIndex in range(0, len(signalSpecStrs)):
                    signalGroup, signalPaths, shading = sgInfoDict.get(
                        signalIndex, (None, [], None))
                    signalOrigin = signalOriginDict[signalIndex]

                    signalSpec = SignalSpec.createFromStr(
                        signalSpecStrs[signalIndex], unitTimeWidth,
                        breakTimeWidth)
                    assert signalSpec is not None
                    pathFragmentVerticesList, shading01VerticesList = signalSpec.getAllPathVerticesAndShading(
                        edgeTimeWidth)
                    pathNo = len(pathFragmentVerticesList)

                    # remove 'transform' of signal path and shading path
                    hadWasteTransf = False
                    for signalPath in signalPaths:
                        transf = signalPath.getTransform()
                        if transf is None or not transf.isIdentity():
                            signalPath.setTransform(None)
                            hadWasteTransf = True
                    if shading is not None:
                        transf = shading.getTransform()
                        if transf is None or not transf.isIdentity():
                            signalPath.setTransform(None)
                            hadWasteTransf = True
                    if hadWasteTransf:
                        printInfo(
                            'Signal {si}: Removed interfering \'transform\' attribute from \'path\' element.'
                            .format(si=signalIndex))
                    del hadWasteTransf

                    signalPaths = signalPaths + [None] * (pathNo -
                                                          len(signalPaths))
                    assert len(signalPaths) >= pathNo

                    if signalGroup is None:
                        signalGroup = SignalGElem.addEmpty(scg, signalIndex)
                        signalGroup.setTransform(
                            PointTransf.createTransl(signalOrigin))
                    else:
                        transf = signalGroup.getTransform()
                        if transf is None:
                            signalGroup.setTransform(None)
                            printInfo(
                                'Signal {si}: Removed invalid \'transform\' attribute from \'g\' element.'
                                .format(si=signalIndex))
                        else:
                            oldSignalOrigin = transf.applyTo((0, 0))
                            originDiff = (signalOrigin[0] - oldSignalOrigin[0],
                                          signalOrigin[1] - oldSignalOrigin[1])
                            if originDiff != (0.0, 0.0):
                                transf = PointTransf.createConcat(
                                    transf,
                                    PointTransf.createTransl(originDiff))
                                signalGroup.setTransform(transf)

                    # determine signal group, whose style is to be used for a new signal group
                    styleTmplSignalIndex = None
                    if signalIndex > 0:
                        styleTmplSignalIndex = signalIndex - 1
                    elif len(sgInfoDict) > 0:
                        # first existing signal group
                        styleTmplSignalIndex = min(sgInfoDict)
                    assert styleTmplSignalIndex is None or styleTmplSignalIndex in sgInfoDict

                    for pathIndex in range(0, pathNo):
                        pathFragmentVertices = pathFragmentVerticesList[
                            pathIndex]
                        oldSignalPath = signalPaths[pathIndex]
                        if oldSignalPath is None:
                            # no old signal 'path' available -> create new one
                            newSignalPath = signalGroup.addSignalPath(
                                pathIndex, pathFragmentVertices, -signalHeight,
                                (0, 0))
                            if styleTmplSignalIndex is not None:
                                tmplSignalGroup, signalPathsOfTmplSignalGroup, shadingOfTmplSignalGroup \
                                    = sgInfoDict[styleTmplSignalIndex]
                                if pathIndex < len(
                                        signalPathsOfTmplSignalGroup):
                                    # matching path in template signal group
                                    newSignalPath.copyStyleFrom(
                                        signalPathsOfTmplSignalGroup[pathIndex]
                                    )
                                else:
                                    # new matching path in template signal group
                                    # -> copy style from preceding path instead
                                    newSignalPath.copyStyleFrom(
                                        signalPaths[pathIndex - 1])
                                if pathIndex == 0:
                                    # create empty 'path' element to preserve the style
                                    for pi in range(
                                            pathNo,
                                            len(signalPathsOfTmplSignalGroup)):
                                        emptySignalPath = signalGroup.addSignalPath(
                                            pi, [], -signalHeight, (0, 0))
                                        emptySignalPath.copyStyleFrom(
                                            signalPathsOfTmplSignalGroup[pi])
                                        del emptySignalPath
                        else:
                            newSignalPath = signalGroup.addSignalPath(
                                pathIndex, pathFragmentVertices, -signalHeight,
                                (0, 0))
                            if pathIndex == 0:
                                newSignalPath.copyTransformFrom(oldSignalPath)

                            newSignalPath.copyIdFrom(oldSignalPath)
                            newSignalPath.copyStyleFrom(oldSignalPath)
                            # preserve position with respect to non-signal path elements in signal group:
                            oldSignalPath.makeSiblingPredecessorOf(
                                newSignalPath)
                            oldSignalPath.remove()
                            if newSignalPath.removeFill():
                                printInfo(
                                    'Signal {si}: Did reset interfering fill style from \'path\' element to \'none\'.'
                                    .format(si=signalIndex))
                            if newSignalPath.forceVisibleStroke():
                                printInfo(
                                    'Signal {si}: Did reset invisible stroke style from \'path\' element to \'black\'.'
                                    .format(si=signalIndex))
                            if scg.removeStyle():
                                # possible, because assigning a style to a group in Inkscape
                                # sets the style of all contained elements (all levels below)
                                printInfo(
                                    'Signal {si}: Did remove interfering style from \'g\' element.'
                                    .format(si=signalIndex))
                        # replace all transforms by transform of signal path 0
                        if pathIndex > 0:
                            newSignalPath.copyTransformFrom(signalPaths[0])
                        signalPaths[pathIndex] = newSignalPath

                    # remove unused signal paths
                    assert pathNo > 0
                    for pathIndex in range(
                            len(signalPaths) - 1, pathNo - 1, -1):
                        assert pathIndex > 0
                        oldSignalPath = signalPaths[pathIndex]
                        if oldSignalPath is not None:
                            if signalPaths[
                                    pathIndex -
                                    1] is not None and oldSignalPath.compareStyleWith(
                                        signalPaths[pathIndex - 1]):
                                # style can be derived of preceding signal path
                                oldSignalPath.remove()
                                del signalPaths[pathIndex]
                            else:
                                # perserve (otherwise style information is lost)
                                oldSignalPath.copyTransformFrom(signalPaths[0])
                                oldSignalPath.setToEmpty()

                    newShading = signalGroup.addShadingPath(
                        shading01VerticesList, -signalHeight, (0, 0))
                    if shading is not None:
                        newShading.copyStyleFrom(shading)
                        shading.remove()
                    elif styleTmplSignalIndex is not None:
                        tmplSignalGroup, signalPathsOfTmplSignalGroup, shadingOfTmplSignalGroup \
                            = sgInfoDict[styleTmplSignalIndex]
                        if shadingOfTmplSignalGroup is not None:
                            newShading.copyStyleFrom(shadingOfTmplSignalGroup)
                    shading = newShading
                    shading.copyTransformFrom(signalPaths[0])
                    if shading.removeStroke():
                        printInfo(
                            'Signal {si}: Did reset stroke style from shading \'path\' element to \'none\'.'
                            .format(si=signalIndex))

                    # sort signal path elements (drawing order)
                    existingSignalPaths = list(
                        filter(lambda e: e is not None, signalPaths))
                    assert len(existingSignalPaths) > 0
                    for i in range(1, len(existingSignalPaths)):
                        existingSignalPaths[i - 1].makeSiblingPredecessorOf(
                            existingSignalPaths[i])
                    # the order of all other non-signal path elements remains unchanged with
                    # respect to signal path 0 and to all other non-signal path elements

                    # draw shading first (appears as bottom-most)
                    existingSignalPaths[-1].makeSiblingPredecessorOf(shading)

                    assert signalGroup is not None
                    assert len(signalPaths) > 0
                    sgInfoDict[signalIndex] = (signalGroup, signalPaths,
                                               shading)

        except UserError as e:
            showErrorDlg(e.msg, e.hint)
            sys.exit(1)
Ejemplo n.º 12
0
    def parseStr(paramStr):
        r = None

        def decode(s):
            return s

        paramDict = None
        if paramStr is not None:
            try:
                paramDict = dict()
                if paramStr != '':
                    for pair in paramStr.split(';'):
                        k, v = pair.split(
                            ':')  # ValueError, if wrong number of elements
                        if len(k) == 0:
                            raise ValueError
                        paramDict[decode(k)] = decode(v)
            except (UnicodeDecodeError, ValueError):
                paramDict = None

        if paramDict is not None:
            params = UsrParams()
            invalidKeys = set()
            unsupportedParamKeys = set()
            for k, v in paramDict.items():
                valueOk = False
                if k == u'unitTimeWidth':
                    if UsrParams.getLengthValue(v) > 0.0:
                        params.unitTimeWidth = v
                        valueOk = True
                elif k == u'signalHeight':
                    if UsrParams.getLengthValue(v) > 0.0:
                        params.signalHeight = v
                        valueOk = True
                elif k == u'edgeTimeWidth':
                    if UsrParams.getLengthValue(v) >= 0.0:
                        params.edgeTimeWidth = v
                        valueOk = True
                elif k == u'breakTimeWidth':
                    if UsrParams.getLengthValue(v) > 0.0:
                        params.breakTimeWidth = v
                        valueOk = True
                elif k == u'placementMethod':
                    if v in (u'homogeneous', u'individual'):
                        params.placementMethod = v
                        valueOk = True
                elif k == u'originDistX':
                    if isfinite(UsrParams.getLengthValue(v)):
                        params.originDistX = v
                        valueOk = True
                elif k == u'originDistY':
                    if UsrParams.getLengthValue(v) > 0.0:
                        params.originDistY = v
                        valueOk = True
                else:
                    invalidKeys.add(k)
                    valueOk = True
                if not valueOk:
                    unsupportedParamKeys.add(k)

            r = (params, invalidKeys, unsupportedParamKeys)

        return r
Ejemplo n.º 13
0
 def createScale(sx, sy):
     t = None
     if isfinite(sx) and isfinite(sy):
         m = (sx, 0, 0, sy)
         t = PointTransf(m, (0, 0))
     return t
Ejemplo n.º 14
0
 def createTransl(t):
     tx, ty = t
     transf = None
     if isfinite(tx) and isfinite(ty):
         transf = PointTransf((1, 0, 0, 1), (tx, ty))
     return transf