Example #1
0
    def open(self):
        reg = CellTypeRegistrar.get()
        self.amOpen = True
        self.space.pushDims()
        self.space.setDim(self.space.X, ".ds.submit")
        self.space.setDim(self.space.Y, ".ds.entry")
        self.space.setDim(self.space.Z, ".ds.nil")

        self.entryCell = self.space.makeTransientCell(reg.fromName("text"), "")
        self.submitCell = self.space.makeTransientCell(
            reg.fromName("prog"), ("Submit", self.createDim, ()))
        # link up entry cell
        self.space.link(self.attachCell, self.space.POS, self.space.Y,
                        self.entryCell)
        # link up submit button
        self.space.link(self.entryCell, self.space.POS, self.space.X,
                        self.submitCell)
        # We want return to submit, just like a normal text entry
        self.entryCell.execute = self.createDim
        self.space.redraw()
Example #2
0
	def open(self):
		reg = CellTypeRegistrar.get()
		self.amOpen = True
		self.space.pushDims()
		self.space.setDim(self.space.X, ".ds.submit")
		self.space.setDim(self.space.Y, ".ds.entry")
		self.space.setDim(self.space.Z, ".ds.nil")

		self.entryCell = self.space.makeTransientCell(reg.fromName("text"), 
					"")
		self.submitCell = self.space.makeTransientCell(reg.fromName("prog"),
				("Submit", self.createDim, ()))
		# link up entry cell
		self.space.link(self.attachCell, self.space.POS, 
				self.space.Y, self.entryCell)
		# link up submit button
		self.space.link(self.entryCell, self.space.POS,
				self.space.X, self.submitCell)
		# We want return to submit, just like a normal text entry
		self.entryCell.execute = self.createDim
		self.space.redraw()
Example #3
0
	def open(self):
		reg = CellTypeRegistrar.get()
		self.amOpen = True
		self.space.pushDims()
		self.space.setDim(self.space.X, ".ds.new-cell-type-info")
		self.space.setDim(self.space.Y, ".ds.new-cell-types")
		self.space.setDim(self.space.Z, ".ds.new-cell-subtypes")
		chugCell = self.space.acursedCell
		infoChugCell = None
		
		prog = reg.fromName("prog")
		text = reg.fromName("text")

		for (n, t) in reg.registrants():
			# the tuple operator is ',' never forget
			cell = self.space.makeTransientCell(prog, 
					(n, self._createTypedCell, (t,)))
			infoCell = self.space.makeTransientCell(text, 
					reg.typeInfo(t))
			self.transientCells.extend([cell, infoCell])
			# hook up our prog cell downward
			self.space.link(chugCell, self.space.POS, self.space.Y,
					cell)
			# hook up info cell rightward
			self.space.link(cell, self.space.POS, self.space.X,
					infoCell)
			# hook up info cell downward
			if infoChugCell:
				self.space.link(infoChugCell, self.space.POS, 
						self.space.Y, infoCell)
			chugCell = cell
			infoChugCell = infoCell
		# hook up our prog cell ring rank
		self.space.link(self.transientCells[-2], self.space.POS,
				self.space.Y, self.attachCell)
		# hook up info cell ring rank
		self.space.link(self.transientCells[-1], self.space.POS,
				self.space.Y, self.transientCells[1])
		self.space.redraw()
Example #4
0
    def open(self):
        reg = CellTypeRegistrar.get()
        self.amOpen = True
        self.space.pushDims()
        self.space.setDim(self.space.X, ".ds.new-cell-type-info")
        self.space.setDim(self.space.Y, ".ds.new-cell-types")
        self.space.setDim(self.space.Z, ".ds.new-cell-subtypes")
        chugCell = self.space.acursedCell
        infoChugCell = None

        prog = reg.fromName("prog")
        text = reg.fromName("text")

        for (n, t) in reg.registrants():
            # the tuple operator is ',' never forget
            cell = self.space.makeTransientCell(prog,
                                                (n, self._createTypedCell,
                                                 (t, )))
            infoCell = self.space.makeTransientCell(text, reg.typeInfo(t))
            self.transientCells.extend([cell, infoCell])
            # hook up our prog cell downward
            self.space.link(chugCell, self.space.POS, self.space.Y, cell)
            # hook up info cell rightward
            self.space.link(cell, self.space.POS, self.space.X, infoCell)
            # hook up info cell downward
            if infoChugCell:
                self.space.link(infoChugCell, self.space.POS, self.space.Y,
                                infoCell)
            chugCell = cell
            infoChugCell = infoCell
        # hook up our prog cell ring rank
        self.space.link(self.transientCells[-2], self.space.POS, self.space.Y,
                        self.attachCell)
        # hook up info cell ring rank
        self.space.link(self.transientCells[-1], self.space.POS, self.space.Y,
                        self.transientCells[1])
        self.space.redraw()
Example #5
0
class DJSONBackend(object):

    NEG = Cell.NEG
    POS = Cell.POS

    reg = CellTypeRegistrar.get()

    def __setattr__(self, name, val):
        self.__dict__[name] = val

    def __init__(self, filey=None):
        # Only want this ever done once, since we will have a backend
        # managing each view
        object.__init__(self)
        self.filey = filey
        if self.filey:
            self.load(filey)

    @classmethod
    def makeCell(cls, cid, json_cells):
        # deleted cells stored as python None, json 'null'
        cinfo = json_cells[cid]
        if not cinfo:
            return None
        if not "type" in cinfo:
            raise ValueError("A JSON cell must contain a 'type' field")
        tName = cinfo["type"]
        cData = cinfo["data"]
        constructor = cls.reg.fromName(tName)
        if constructor:
            # save cons for cellizeCons later
            madeCell = constructor(cid, cData)
        else:
            madeCell = cls.reg.registerDynamicCell(tName, cid, cData)
        return madeCell

    @classmethod
    def fromCell(cls, cell):
        cType = cls.reg.fromType(cell)
        return {
            "type": cType,
            "data": cell.data,
            "cons": cls.freezeCellCons(cell)
        }

    @staticmethod
    def createNew(rootCell):
        me = DJSONBackend()
        DJSONBackend.createDummy(me)
        me.cells.append(rootCell)
        me.acursedId = 0
        me.acursedIds.append(me.acursedId)
        return me

    @staticmethod
    def createDummy(back):
        # Eventually version will be useful for something
        back.version = 1
        for i in ["allDims", "acursedIds", "dimConfig", "cells"]:
            back.__setattr__(i, [])
        startDims = [".ds.1", ".ds.2", ".ds.3"]
        back.allDims.extend(startDims)
        back.dimConfig.extend(list(startDims))

    def load(self, filey):
        # I want to use 'with filey:' here, but for testing purposes
        # filey might be a StringIO, which doesn't humor me with an
        # __exit__/__enter__ method pair
        self.filey = filey
        space = json.load(self.filey)
        self.loadMetadata(space)
        self.loadCells(space)
        filey.close()

    @staticmethod
    def freezeCellCons(cell):
        cons = {}
        for (dim, d) in cell.cons.iteritems():
            if None != d[0] and None != d[1]:
                cons.update({dim: [d[0].cellId, d[1].cellId]})
            elif None != d[0]:
                cons.update({dim: [d[0].cellId, -1]})
            else:
                cons.update({dim: [-1, d[1].cellId]})
        return cons

    def thawCellCons(self, cell, json_cell):
        for (dim, direcs) in json_cell["cons"].iteritems():
            if -1 != direcs[0]:
                targetCell = self.cells[direcs[0]]
                cell.addNegCon(dim, targetCell)
            if -1 != direcs[1]:
                targetCell = self.cells[direcs[1]]
                cell.addPosCon(dim, targetCell)

    def loadCells(self, space):
        json_cells = space["cells"]
        self.cells = []
        # we are O(n^2) atm
        for i in xrange(len(json_cells)):
            self.cells.append(self.makeCell(i, json_cells))
        for i in xrange(len(json_cells)):
            self.thawCellCons(self.cells[i], json_cells[i])

    def loadMetadata(self, space):
        # Eventually version will be useful for something
        self.version = space["version"]
        for i in ["allDims", "acursedIds", "dimConfig"]:
            self.__setattr__(i, space[i])
        self.acursedId = self.acursedIds[0]

    def saveMetadata(self, space):
        self.acursedIds[0] = self.acursedId
        space["version"] = self.version
        for i in ["allDims", "acursedIds", "dimConfig"]:
            space[i] = self.__getattribute__(i)

    def saveCells(self, space):
        space["cells"] = []
        # Heard about this trick from python tricks somewhere
        cellsApp = space["cells"].append
        for c in self.cells:
            cellsApp(self.fromCell(c))

    def saveAs(self, filey):
        """Save everything to filey's location and direct further operations 
there, thereafter."""
        self.filey = filey
        self.save()

    def save(self):
        if self.filey:
            space = {}
            self.saveMetadata(space)
            self.saveCells(space)
            if hasattr(self.filey, 'name'):
                # We are probably a file-backed thing
                self.filey = file(self.filey.name, "w")
                json.dump(space, self.filey)
                self.filey.close()  # close should flush
            else:
                # StringIO, something file-like, probably
                # for testing
                self.filey.truncate(0)
                json.dump(self.space, self.filey)
Example #6
0
class DimSpace(QtCore.QObject):
    NEG = Cell.NEG
    POS = Cell.POS

    X = 0
    Y = 1
    Z = 2

    dimChanged = pyqtSignal(int, str)
    reg = CellTypeRegistrar.get()

    def __init__(self, scene):
        QtCore.QObject.__init__(self)
        self.scene = scene
        self.back = None
        self.connections = []
        self.reg.dynamicCellsRegistered.connect(
            self.updateDynamicallyTypedCells)

    @pyqtSlot(list)
    def updateDynamicallyTypedCells(self, cells):
        for c in cells:
            old_c = self.cells[c.cellId]
            if self.acursedCell == old_c:
                self.setAcursed(c)
            old_c.remove(self.space, cached=False)
            self.cells[c.cellId] = c
        self.redraw()

    def save(self):
        # self.dims always points to the latest dims
        self.back.dimConfig = self.dims
        # we maintain the acursedCell, the backends maintains the
        # acursedId, the two need only meet at save time
        self.back.acursedId = self.acursedCell.cellId
        self.back.save()

    def saveAs(self, path):
        filey = file(path, "w")
        self.back.saveAs(filey)

    def load(self, origin, path=None):
        if self.back:
            self.clear()
        if path:
            filey = file(path, "r")
            self.back = DJSONBackend(filey)
        else:
            rootCell = self.reg.fromName("text")(0, "Root")
            self.back = DJSONBackend.createNew(rootCell)
        self.acursedCell = self.back.cells[self.back.acursedId]
        # needs to update the backend's version at save time
        self.dims = self.back.dimConfig
        self.dimsStack = [self.dims]
        # just pointers to the backend's structures, no need to update
        self.allDims = self.back.allDims
        self.cells = self.back.cells
        self.origin = origin
        self.redraw()
        self.acursedCell.select()

    def swapDims(self):
        self.dims[0], self.dims[1] = self.dims[1], self.dims[0]
        self.dimChanged.emit(self.X, self.dims[0])
        self.dimChanged.emit(self.Y, self.dims[1])

    def nameDim(self, dim):
        if not dim in self.allDims:
            self.allDims.append(dim)

    def pushDims(self):
        self.dimsStack.append(list(self.dims))
        self.dims = self.dimsStack[-1]

    def popDims(self):
        if len(self.dimsStack) > 1:
            othDims = self.dimsStack.pop()
            self.dims = self.dimsStack[-1]
            for i in xrange(len(self.dims)):
                if self.dims[i] != othDims[i]:
                    self.dimChanged.emit(i, self.dims[i])

    def setDim(self, appDim, boundDim):
        self.dims[appDim] = boundDim
        self.dimChanged.emit(appDim, boundDim)

    def getDim(self, appDim):
        return self.dims[appDim]

    def dirToString(self, direc):
        if direc == self.NEG:
            return "Negward"
        return "Posward"

    def dimToString(self, appDim):
        return chr(appDim + ord('X'))

    def removeCell(self, cell):
        cell.remove(self.scene)
        cell.unlink()
        if not cell.isTransient():
            self.cells[cell.cellId] = None

    def removeLink(self, cell, appDim, direction=None):
        cell.removeCon(self.dims[appDim], repair=True, direction=direction)

    def link(self, linkFrom, moveDir, appDim, linkTo, exclusive=None):
        if exclusive:
            linkFrom.unlink(repair=False)
        if self.POS == moveDir:
            linkFrom.addPosCon(self.dims[appDim], linkTo)
            linkTo.addNegCon(self.dims[appDim], linkFrom)
        else:
            linkFrom.addNegCon(self.dims[appDim], linkTo)
            linkTo.addPosCon(self.dims[appDim], linkFrom)

    def makeTransientCell(self, theType, *args):
        # cellId is really only checked at save time now that
        # we use cells as connections for in memory cells
        # Since we ignore transient cells anyway, this id can
        # be any garbage value
        cell = theType(-1, *args)
        cell.setTransient()
        cell.sel_brush = QtGui.QBrush(QtGui.QColor("magenta"))
        return cell

    @staticmethod
    def makeCell(self, theType, *args):
        cell = theType(len(self.cells), *args)
        self.cells.append(cell)

    def makeCellConcrete(self, transCell):
        transCell.setTransient(False)
        transCell.cellId = len(self.cells)
        transCell.sel_brush = QtGui.QBrush(QtGui.QColor("cyan"))
        self.cells.append(transCell)

    def setAcursed(self, cell):
        self.acursedCell.deselect()
        cell.select()
        self.acursedCell = cell
        self.acursedId = cell.cellId

    def removeTransientCells(self,
                             cell,
                             prevCell=None,
                             moveDir=None,
                             dimen=None):
        if cell.isTransient():
            # cannot unlink yet
            cell.remove(self.scene, cached=False)
            self.cells[cell.cellId] = None
        return True

    def chugDim(self, moveDir, appDim):
        dim = self.dims[appDim]
        if moveDir == self.NEG: direc = -1
        else: direc = 1
        print("dims:", self.allDims)
        ind = (self.allDims.index(dim) + direc) % len(self.allDims)
        self.dims[appDim] = self.allDims[ind]
        self.dimChanged.emit(appDim, self.dims[appDim])

    def redraw(self):
        """Call after dimensions are changed"""
        self.clear()
        self.broadcast(self.redrawCell, self.acursedCell)
        self.broadcast(self.drawCons, self.acursedCell, allCons=True)

    def fixOverlap(self, cell, prevCell=None, moveDir=None, dimen=None):
        if not prevCell:
            return
        self.placeRelativeTo(cell, prevCell, moveDir, dimen)

    def redrawCell(self, cell, prevCell=None, moveDir=None, dimen=None):
        if prevCell == None:
            cell.add(self)
            cell.setPos(self.origin)
            return
        self.placeRelativeTo(cell, prevCell, moveDir, dimen)

    def chugDraw(self):
        """No new cells to create, regroup cells around new acursed"""
        self.broadcast(self.chugDrawCell, self.acursedCell)
        if not self.connections and len(self.cells) > 1:
            self.broadcast(self.drawCons, self.acursedCell, allCons=True)

    def chugDrawCell(self, cell, prevCell=None, moveDir=None, dimen=None):
        if prevCell == None:
            cell.add(self)
            cell.setPos(self.origin)
            return
        self.placeRelativeTo(cell, prevCell, moveDir, dimen)

    def removeOverlap(self, cell, prevCell=None, moveDir=None, dimen=None):
        if prevCell == None:
            return
        items = cell.collidingItems(QtCore.Qt.IntersectsItemBoundingRect)
        if items:
            for item in items:
                if isinstance(item, QtGui.QGraphicsSimpleTextItem):
                    inter = cell.rect().intersected(item.rect())

    def drawCons(self, cell, prevCell=None, moveDir=None, dimen=None):
        if prevCell == None:
            return
        conMap = map(lambda x: (x.linkTo, x.linkFrom), self.connections)
        if (prevCell, cell) in conMap:
            return
        con = Connection(self.scene, prevCell, moveDir, dimen, cell)
        con.position()
        self.connections.append(con)

    def placeRelativeTo(self, cell, adjCell, moveDir, dimen):
        # TODO: Z will crash and burn atm
        cell.add(self)
        if adjCell == self.acursedCell:
            cell.setZValue(6)
        elif adjCell.isConnectedTo(self.acursedCell):
            cell.setZValue(4)
        newRect = QtCore.QRectF(cell.skin.sceneBoundingRect())
        adjRect = adjCell.skin.sceneBoundingRect()
        adjRect.moveTopLeft(adjCell.skin.targetPos())
        if dimen == self.X:
            if moveDir == self.NEG:
                newRect.moveCenter(
                    QPointF(adjRect.left() - 10 - newRect.width() / 2,
                            adjRect.center().y()))
            else:
                newRect.moveCenter(
                    QPointF(adjRect.right() + 10 + newRect.width() / 2,
                            adjRect.center().y()))
        elif dimen == self.Y:
            if moveDir == self.NEG:
                newRect.moveCenter(
                    QPointF(adjRect.center().x(),
                            adjRect.top() - 10 - newRect.height() / 2))
            else:
                newRect.moveCenter(
                    QPointF(adjRect.center().x(),
                            adjRect.bottom() + 10 + newRect.height() / 2))
        center = (newRect.center().x(), newRect.center().y())
        cell.setPos(center)
        return True

    def colwiseTraversal(self,
                         func,
                         curCell,
                         allCons=False,
                         marked=None,
                         moveDir=None):
        if not marked:
            marked = [curCell]
        func(curCell, None, None, None)
        if cell.hasCon(self.dims[self.X], self.NEG) and not \
          self.POS == moveDir:
            cony = cell.getCon(self.dims[self.X], self.NEG)
            if cony not in marked:
                marked.append(cony)
                self.colwiseTraversal(func, cony, allCons, marked, self.NEG)
            elif allCons:
                func(cony, cell, self.NEG, self.X)
        if cell.hasCon(self.dims[self.X], self.POS) and not \
          self.NEG == moveDir:
            cony = cell.getCon(self.dims[self.X], self.POS)
            if cony not in marked:
                marked.append(cony)
                self.colwiseTraversal(func, cony, allCons, marked, self.POS)
            elif allCons:
                func(cony, cell, self.POS, self.X)
        if cell.hasCon(self.dims[self.Y], self.NEG) and not \
          self.POS == moveDir:
            cony = cell.getCon(self.dims[self.Y], self.NEG)
            if cony not in marked:
                marked.append(cony)
                self.colwiseTraversal(func, cony, allCons, marked, self.NEG)
            elif allCons:
                func(cony, cell, self.NEG, self.Y)
        if cell.hasCon(self.dims[self.Y], self.POS) and not \
          self.NEG == moveDir:
            cony = cell.getCon(self.dims[self.Y], self.POS)
            if cony not in marked:
                marked.append(cony)
                self.colwiseTraversal(func, cony, allCons, marked, self.POS)
            elif allCons:
                func(cony, cell, self.POS, self.Y)

    def broadcast(self, func, curCell, allCons=False):
        #if not isinstance(curCell, list):
        #curCell = [ curCell ]
        #marked = [ curCell[0] ]
        #goCons = [ (cell, None, None, None) for cell in curCell ]
        marked = [curCell]
        goCons = [(curCell, None, None, None)]
        for (cell, prevCell, moveDir, dimen) in goCons:
            func(cell, prevCell, moveDir, dimen)
            for i in xrange(len(self.dims)):
                if cell.hasCon(self.dims[i], self.NEG) and not \
                  (i == dimen and self.POS == moveDir):
                    cony = cell.getCon(self.dims[i], self.NEG)
                    if cony not in marked:
                        marked.append(cony)
                        goCons.append((cony, cell, self.NEG, i))
                    elif allCons:
                        func(cony, cell, self.NEG, i)
                if cell.hasCon(self.dims[i], self.POS) and not \
                  (i == dimen and self.NEG == moveDir):
                    cony = cell.getCon(self.dims[i], self.POS)
                    if cony not in marked:
                        marked.append(cony)
                        goCons.append((cony, cell, self.POS, i))
                    elif allCons:
                        func(cony, cell, self.POS, i)

    def executeCell(self):
        print("executing cell:", self.acursedCell, self.acursedCell.getChild())
        self.acursedCell.execute()

    def editCell(self):
        self.acursedCell.edit()

    def clear(self):
        # Cache our cell skins in our cells
        for c in self.cells:
            if c:
                c.remove(self.scene)
        # Clear connections from scene
        for con in self.connections:
            con.remove()
        self.connections = []

    def chug(self, direction, apparentDim):
        if apparentDim < len(self.dims) and apparentDim >= 0:
            curDim = self.dims[apparentDim]
            if self.acursedCell.hasCon(curDim, direction):
                self.setAcursed(self.acursedCell.getCon(curDim, direction))
                return True
        return False

    def chugWhile(self, count, direc, dim):
        if callable(count):
            while count(self.acursedCell) and self.chug(direc, dim):
                pass
        else:
            while count >= 0 and chug(direc, dim):
                count -= 1