Example #1
0
 def __init__(self, parent=None, width=450, height=450, color="#FFFFFF", cliente=None):
     """Inicializa un WhiteBoard con un Canvas de width por height y color de fondo.
     En wbCurrentText se mantiene el id del TextBox de trabajo actual
     Liga los eventos de click del mouse y de presion de teclas a las funciones 
     onClick y onKey, respectivamente, y le da foco al WhiteBoard para poder trabajar.
     """
     Canvas.__init__(self, parent, width=width, height=height, bg=color)
     self.bind("<Button-1>", self.click)
     self.bind("<B1-Motion>", self.mouseMove)
     self.bind("<ButtonRelease-1>", self.release)
     self.bind("<Key>", self.onKey)
     self.bind("<Control-x>", self.cutSelection)
     self.bind("<Control-c>", self.copySelection)
     self.bind("<Control-v>", self.paste)
     self.bind("<Control-b>", self.pasteForeign)
     #self.bind("<FocusOut>", lambda e: self.focus_set())
     #self.focus_set()
     self.maxWidth = width
     self.maxHeight = height
     self.tool = TEXT
     self.color = colorPalette[BLACK]
     self.myColor = colorPalette[BLACK]
     self.lineWidth = FINE
     self.clipboard = WBClipboard()
     self.imgs = Imgs()
     self.mode = self.RW
     self.reset()
     self.font = ('Arial', 14, 'bold')
     self.tk.call('encoding', 'system', 'utf-8')
     self.client = cliente
     self.parent = parent
Example #2
0
class WhiteBoard(Canvas):
    NEAR_RADIO = 5
    NEAR_REMOVE_RADIO = 10
    WHITEBOARD_BORDER = 5
    RW = 1
    RO = 2

    def __init__(self, parent=None, width=450, height=450, color="#FFFFFF", cliente=None):
        """Inicializa un WhiteBoard con un Canvas de width por height y color de fondo.
        En wbCurrentText se mantiene el id del TextBox de trabajo actual
        Liga los eventos de click del mouse y de presion de teclas a las funciones 
        onClick y onKey, respectivamente, y le da foco al WhiteBoard para poder trabajar.
        """
        Canvas.__init__(self, parent, width=width, height=height, bg=color)
        self.bind("<Button-1>", self.click)
        self.bind("<B1-Motion>", self.mouseMove)
        self.bind("<ButtonRelease-1>", self.release)
        self.bind("<Key>", self.onKey)
        self.bind("<Control-x>", self.cutSelection)
        self.bind("<Control-c>", self.copySelection)
        self.bind("<Control-v>", self.paste)
        self.bind("<Control-b>", self.pasteForeign)
        #self.bind("<FocusOut>", lambda e: self.focus_set())
        #self.focus_set()
        self.maxWidth = width
        self.maxHeight = height
        self.tool = TEXT
        self.color = colorPalette[BLACK]
        self.myColor = colorPalette[BLACK]
        self.lineWidth = FINE
        self.clipboard = WBClipboard()
        self.imgs = Imgs()
        self.mode = self.RW
        self.reset()
        self.font = ('Arial', 14, 'bold')
        self.tk.call('encoding', 'system', 'utf-8')
        self.client = cliente
        self.parent = parent

    def putImg(self, number):
        self.img = number

    def setMyColor(self, color):
        self.myColor = colorPalette[color]

    def setROMode(self):
        self.mode = self.RO
        self.focus("")
        self.wbCurrentText = None
        self.wbCurrentObject = None
        self.clearSelection()

    def unsetROMode(self):
        self.mode = self.RW
        
    def changeTool(self, tool):
        self.tool = tool
        if tool==TEXT:
            self.focus_set()
        
        if tool==GRAPH:
            GraphDialog(self.parent)   
        else:
            self.focus("")
            
    def changeColor(self, color):
        self.color = colorPalette[color]

    def changeWidth(self, width):
        self.lineWidth = width

    def _updateDelta(self, x1, y1):
        y0 = self.pointList.pop()
        x0 = self.pointList.pop()
        self.pointList.append(x1)
        self.pointList.append(y1)
        dx = x1 - x0
        dy = y1 - y0
        self.dx = self.dx + dx
        self.dy = self.dy + dy
        return (dx, dy)

    def mouseMove(self, event):
        x1 = self.canvasx(event.x)
        y1 = self.canvasy(event.y)
        if self.tool == MOVE:
            delta = self._updateDelta(x1, y1)
            for x in self.selectedItems:
                self.move(x, *delta)
            self.move(self.selectionBox, *delta)
        elif self.wbCurrentObject != None and self.tool != FREEHAND and self.tool != HIGHLIGHT:
            x0 = self.pointList[0]
            y0 = self.pointList[1]
            self.coords(self.wbCurrentObject, x0, y0, x1, y1)
        elif self.wbCurrentObject != None and (self.tool == FREEHAND or self.tool == HIGHLIGHT):
            self.pointList.append(x1)
            self.pointList.append(y1)
            self.coords(self.wbCurrentObject, *self.pointList)
    
    def release(self, event):
        if self.mode == self.RO:
            return
        x1 = self.canvasx(event.x)
        y1 = self.canvasy(event.y)
        self.pointList.append(x1)
        self.pointList.append(y1)
        x0 = self.pointList[0]
        y0 = self.pointList[1]
        if self.tool == SQRT or self.tool == INTEGRAL or self.tool == AXES or self.tool == GRAPH:
            self.delete(self.wbCurrentObject)
        if self.img != None:
            self.addItem(SYMBOL, self.pointList, self.myColor, "", self.img)
            self.img = None
        elif ((x0 == x1 and y0 == y1) and self.tool != SELECT \
          and self.tool != MOVE and self.tool != ERASE_ITEM \
          and self.tool != ERASE_SELECTION and self.tool != FILL) or self.tool == TEXT:
            self.delete(self.wbCurrentObject)
            self.createTextBox(self.pointList, self.myColor)
        elif self.tool == ERASE_SELECTION:
            self.delete(self.wbCurrentObject)
            if (x0 != x1) or (y0 != y1):
                self.doSelection(x0, y0, x1, y1)
                self.eraseSelectedItems(self.selectedItems)
                self.clearSelection()
        elif self.tool == ERASE_ITEM:
            self.doSelection(x1, y1, x1, y1)
            if self.selectedItems != [] and self._getItemKind(self.selectedItems[0]) != TEXT:
                self.eraseSelectedItems(self.selectedItems)
            self.clearSelection()
        elif self.tool == SELECT:
            self.delete(self.wbCurrentObject)
            self.doSelection(x0, y0, x1, y1)
            if self.selectedItems != []:
                bbox = self.bbox(*self.selectedItems)
                self.selectionBox = self.create_rectangle(bbox, fill=colorPalette[SELECTION], stipple=colorPalette[STIPPLE])
        elif self.tool == MOVE:
            self.moveItems(self.selectedItems, self.dx, self.dy)
            self.tool = SELECT
            self.dx = 0
            self.dy = 0
        elif self.tool == SQRT or self.tool == INTEGRAL or self.tool == AXES or self.tool == GRAPH:
            self.addItem(self.tool, self.pointList, self.myColor, "", FINE)
        elif self.tool != TEXT and self.tool != FILL:
            self.addItem(self.tool, self.pointList, self.color, "", self.lineWidth)
        self.wbCurrentObject = None
        self.pointList = []

    def click(self, event):
        """Borra el último TextBox en caso de ser necesario (es decir, si no tiene texto).
        Además llama a las funciones onClick que reacciona a eventos del boton 1 del mouse,
        y a moveCursor, que posiciona el cursor dentro del TextBox actual
        """
        if self.mode == self.RO:
            return
        x0 = self.canvasx(event.x)
        y0 = self.canvasy(event.y)
        self.pointList.append(x0)
        self.pointList.append(y0)
        self._onClick()

    def foreignObjectsCount(self):
        return len(self.foreignObjects)
                   
    def moveCursor(self, x, y):
        """Mueve el cursor hasta la posicion indicada por el evento
        """
        if self.wbCurrentText:
            self.icursor(self.wbCurrentText, "@%d,%d" % (x, y))

    def _onClick(self):
        """
        Callback que reacciona ante el click del mouse y, dependiendo
        de si hay un TextBox cerca o no, cambia el valor de wbCurent
        o crea un nuevo TextBox, respectivamente
        """
        x0 = self.pointList[0]
        y0 = self.pointList[1]
        if self.tool == SELECT and self.clickOnSelection():
            self.tool = MOVE
        else:
            self.clearSelection()
        if self.tool == TEXT or self.img != None:
            pass
        elif self.tool == LINE:
            newLine = self.create_line(x0, y0, x0, y0, fill=self.color, width=self.lineWidth)
            self.itemconfig(newLine, tags=self.tool)
            self.wbCurrentObject = newLine
        elif self.tool == ARROW:
            newLine = self.create_line(x0, y0, x0, y0, fill=self.color, width=self.lineWidth, arrow=LAST)
            self.itemconfig(newLine, tags=self.tool)
            self.wbCurrentObject = newLine
        elif self.tool == DARROW:
            newLine = self.create_line(x0, y0, x0, y0, fill=self.color, width=self.lineWidth, arrow=BOTH)
            self.itemconfig(newLine, tags=self.tool)
            self.wbCurrentObject = newLine
        elif self.tool == DASH:
            newLine = self.create_line(x0, y0, x0, y0, fill=self.color, width=self.lineWidth, dash=10)
            self.itemconfig(newLine, tags=self.tool)
            self.wbCurrentObject = newLine
        elif self.tool == RECTANGLE:
            newRect = self.create_rectangle(x0, y0, x0, y0, outline=self.color, width=self.lineWidth)
            self.itemconfig(newRect, tags=self.tool)
            self.wbCurrentObject = newRect
        elif self.tool == CIRCLE:
            newCircle = self.create_oval(x0, y0, x0, y0, outline=self.color, width=self.lineWidth)
            self.itemconfig(newCircle, tags=self.tool)
            self.wbCurrentObject = newCircle
        elif self.tool == SQRT or self.tool == INTEGRAL or self.tool == AXES or self.tool == GRAPH:
            newItem = self.create_rectangle(x0, y0, x0, y0, outline=self.myColor)
            self.wbCurrentObject = newItem
        elif self.tool == FREEHAND:
            newLine = self.create_line(x0, y0, x0, y0, fill=self.color, width=self.lineWidth)
            self.itemconfig(newLine, tags=self.tool)
            self.wbCurrentObject = newLine
        elif self.tool == HIGHLIGHT:
            newLine = self.create_line(x0, y0, x0, y0, fill=self.color, width=self.lineWidth)
            self.itemconfig(newLine, tags=self.tool)
            self.lower(newLine, self.rBase)
            self.wbCurrentObject = newLine
        elif self.tool == FILL:
            item = self.findItem(x0, y0)
            if item != None:
                self.fillItem(item, self.color)
        elif self.tool == ERASE_SELECTION or self.tool == SELECT:
            if self.wbCurrentText != None:
                if self.itemcget(self.wbCurrentText, "text") == "":
                    self.eraseSelectedItems([self.wbCurrentText])
            self.wbCurrentText = None
            self.focus("")
            newSelection = self.create_rectangle(x0, y0, x0, y0, fill=colorPalette[SELECTION], stipple=colorPalette[STIPPLE])
            self.wbCurrentObject = newSelection

    def onKey(self, event):
        """
        Callback que reacciona ante el pulsado de una tecla
        y llama a la funcion insertChar para el TextBox actual
        """
        c = event.char
        sym = event.keysym
        if self.wbCurrentText != None:
            insert = self.index(self.wbCurrentText, INSERT)
            # Vemos que tipo de tecla es y actuamos en consecuencia
            if sym == "Left":
                self.icursor(self.wbCurrentText, insert - 1)
            elif sym == "Right":
                self.icursor(self.wbCurrentText, insert + 1)
            elif sym == "Home":
                self.icursor(self.wbCurrentText, 0)
            elif sym == "End":
                self.icursor(self.wbCurrentText, END)
            elif sym == "Delete":
                self.deleteChars(self.wbCurrentText, insert, insert)
            elif sym == "BackSpace":
                if insert > 0:
                    self.deleteChars(self.wbCurrentText, insert - 1, insert - 1)
                elif self.itemcget(self.wbCurrentText, "text") == "":
                    self._removeNext()
            elif sym == "Return":
                self.insertChars(self.wbCurrentText, insert, "\n")
            else:
                self.insertChars(self.wbCurrentText, insert, c)

    def _removeNext(self):
        delete = None
        coords = self.coords(self.wbCurrentText)
        next = self.nextTextBox(coords[0], coords[1], self.NEAR_REMOVE_RADIO, self.wbCurrentText)
        if next != None:
            coords2 = self.coords(next)
            h = abs(coords2[1] - coords[1])/2
            self.focus(next)
            delete = self.wbCurrentText
            self.eraseSelectedItems([self.wbCurrentText])
            self.wbCurrentText = next
            self.moveCursor(coords[0], coords2[1] + h)
        else:
            next = self.nearestImage(coords[0], coords[1], self.NEAR_REMOVE_RADIO)
            if next != None:
                coords2 = list(self.coords(next))
                delete = next
                self.eraseSelectedItems([next])
                self.createTextBox(coords2, self.myColor)
#        if delete in self.selectedItems:
#            self.selectedItems.remove(delete)

    def cutSelection(self, event=None):
        if self.mode == self.RO:
            return
        if self.tool == SELECT:
            self.copySelection(event)
            self.eraseSelectedItems(self.selectedItems)
            self.clearSelection()

    def copySelection(self, event=None):
        if self.mode == self.RO:
            return
        if self.tool == SELECT and self.selectedItems != []:
            objectsId = self._filterItemsId(self.selectedItems)
            self.clipboard.clipboardEmpty()
            for x in objectsId:
                tags = self.gettags(x)
                kind = self._getItemKind(x)
                coords = list(self.coords(x))
                text = None
                outline = None
                fill = None
                width = None
                if kind == SYMBOL:
                    width = int(tags[1])
                if kind == LINE or kind == ARROW or kind == DARROW \
                  or kind == DASH or kind == FREEHAND or kind == HIGHLIGHT:
                    outline = self.itemcget(x, "fill")
                    width = self.itemcget(x, "width")
                if kind == RECTANGLE or kind == CIRCLE:
                    outline = self.itemcget(x, "outline")
                    fill = self.itemcget(x, "fill")
                    width = self.itemcget(x, "width")
                if kind == INTEGRAL:
                    coords = self._getIntegralCoords(x, float(tags[2]))
                    outline = self.itemcget(x, "fill")
                if kind == SQRT or kind == GRAPH:
                    coords = self._getSqrtCoords(x, float(tags[2]))
                    outline = self.itemcget(x, "fill")
                if kind == AXES:
                    coords = self._getAxesCoords(x, float(tags[2]), float(tags[3]))
                    outline = self.itemcget(x, "fill")
                if kind == TEXT:
                    text = self.itemcget(x, "text")
                    outline = self.itemcget(x, "fill")
                self.clipboard.clipboardAddItem(kind, coords, outline, fill, width, text)

    def paste(self, event=None):
        if self.mode == self.RO:
            return
        if self.tool == SELECT:
            self.clearSelection()
            for x in self.clipboard.clipboardGetItems():
                if x["kind"] == TEXT:
                    self.addTextBox(x["points"], x["outline"])
                    self.insertChars(self.wbCurrentText, 0, x["text"])
                    self.addToSelection(self.wbCurrentText)
                    self.focus("")
                    self.wbCurrentText = None
                else:
                    self.addItem(x["kind"], x["points"], x["outline"], x["fill"], x["width"], PASTE)

    def pasteForeign(self, event=None):
        if self.mode == self.RO:
            return
        if self.wbCurrentText != None:
            insert = self.index(self.wbCurrentText, INSERT)
            txt = self.client.getSystemClipboard()
            self.insertChars(self.wbCurrentText, insert, txt)

    def addToSelection(self, item):
        items = self._findItemsTag(item)
        if self.selectedItems == []:
            self.selectedItems = items
            bbox = self.bbox(*self.selectedItems)
            self.selectionBox = self.create_rectangle(bbox, fill=colorPalette[SELECTION], stipple=colorPalette[STIPPLE])
            #self.lower(self.selectionBox, self.rBase)
        else:            
            self.selectedItems = self.selectedItems + items
            bbox = self.bbox(*self.selectedItems)
            self.coords(self.selectionBox, *bbox)

    def clickOnSelection(self):
        ret = False
        x1 = self.pointList[0]
        y1 = self.pointList[1]
        if self.selectionBox != None:
            box = self.coords(self.selectionBox)
            if box[0] <= x1 <= box[2] and box[1] <= y1 <= box[3]:
                ret = True
        return ret

    def clearSelection(self):
        if self.selectionBox != None:
            self.delete(self.selectionBox)
            self.selectionBox = None
        self.selectedItems = []

    def _getItemId(self, item):
        itemId = item
        itemTag = self.gettags(item)
        kind = self._getItemKind(itemId)
        if kind == INTEGRAL or kind == SQRT or kind == AXES or kind == GRAPH:
            itemId = int(itemTag[1][4:])
        return itemId

    def _getItemKind(self, item):
        itemTag = self.gettags(item)
        kind = int(itemTag[0])
        return kind

    def _filterItemsId(self, items):
        res = []
        for x in items:
            itemId = self._getItemId(x)
            if itemId not in res:
                res.append(itemId)
        return res

    def _findItemsTag(self, item):
        ret = None
        itemTag = self.gettags(item)
        kind = self._getItemKind(item)
        if kind == INTEGRAL or kind == SQRT or kind == AXES or kind == GRAPH:
            res = self.find_withtag(itemTag[1])
            res = list(res)
        else:
             res = [item]
        return res

    def findItem(self, x, y):
        ret = None
        res = self.find_overlapping(x, y, x, y)
        res = filter(lambda x: not self._getItemId(x) in self.foreignObjects.values(), res)
        if(len(res) > 0):
            ret = res[0]
        return ret

    def findItemsEnclosed(self, x0, y0, x1, y1):
        res = self.find_enclosed(x0, y0, x1, y1)
        res = list(res)
        res = self._filterSearch(res)
        #res = filter(lambda x: not self._getItemId(x) in self.foreignObjects.values(), res)
        return res

    def _filterSearch(self, search):
        remove = []
        for x in search:
            if self._getItemId(x) in self.foreignObjects.values():
                remove.append(x)
            else:
                isComplete = True
                itemTag = self.gettags(x)
                kind = self._getItemKind(x)
                if kind == INTEGRAL or kind == SQRT or kind == AXES or kind == GRAPH:
                    res = self.find_withtag(itemTag[1])
                    res = list(res)
                    for y in res:
                        if y not in search:
                            isComplete = False
                if not isComplete:
                    remove.append(x)
        for x in remove:
            search.remove(x)
        return search
        
    def doSelection(self, x0, y0, x1, y1):
        if x0 == x1 and y0 == y1:
            item = self.findItem(x0,y0)
            if item != None:
                self.selectedItems = self._findItemsTag(item)
        else:
            self.selectedItems = self.findItemsEnclosed(x0,y0,x1,y1)

    def moveItems(self, selection, dx, dy, foreignId=None):
        if foreignId is None:
            objectsId = self._filterItemsId(selection)
            result = self.client.broadcast_moveItems(objectsId, dx, dy)
        else:
            for i in selection:
                to_move = self._findItemsTag(self.foreignObjects[i])
                for x in to_move:
                    self.move(x, dx, dy)
            result = defer.Deferred()
        return result

    def eraseSelectedItems(self, selection, foreignId=None):
        if foreignId is None:
            objectsId = self._filterItemsId(selection)
            self.wbCurrentText = None
            self.delete(*selection)
            result = self.client.broadcast_eraseItem(objectsId)
        else:
            to_remove = []
            for i in selection:
                to_remove = to_remove + self._findItemsTag(self.foreignObjects[i])
                del(self.foreignObjects[i])
            self.delete(*to_remove)
            result = defer.Deferred()
        return result

    def fillItem(self, item, color, foreignId=None):
        if foreignId is None:
            itemId = self._getItemId(item)
            kind = self._getItemKind(itemId)
            if kind == INTEGRAL or kind == SQRT or \
              kind == AXES or kind == TEXT or kind == SYMBOL or kind == GRAPH:
                return
            items = self._findItemsTag(item)
            for x in items:
                self.itemconfigure(x, fill=color)
            result = self.client.broadcast_fillItem(itemId, color)
        else:
            itemId = self.foreignObjects[foreignId]
            items = self._findItemsTag(itemId)
            for x in items:
                self.itemconfigure(x, fill=color)
            result = defer.Deferred()
        return result

    def createItem(self, kind, points, outline, fill, width, graph=None):
        if kind == LINE:
            newItem = self.create_line(points, fill=outline, width=width)
            self.itemconfig(newItem, tags=(LINE,))
        elif kind == ARROW:
            newItem = self.create_line(points, fill=outline, width=width, arrow=LAST)
            self.itemconfig(newItem, tags=(ARROW,))
        elif kind == DARROW:
            newItem = self.create_line(points, fill=outline, width=width, arrow=BOTH)
            self.itemconfig(newItem, tags=(DARROW,))
        elif kind == DASH:
            newItem = self.create_line(points, fill=outline, width=width, dash=10)
            self.itemconfig(newItem, tags=(DASH,))
        elif kind == RECTANGLE:
            newItem = self.create_rectangle(points, outline=outline, fill=fill, width=width)
            self.itemconfig(newItem, tags=(RECTANGLE,))
        elif kind == CIRCLE:
            newItem = self.create_oval(points, outline=outline, fill=fill, width=width)
            self.itemconfig(newItem, tags=(CIRCLE,))
        elif kind == SQRT:
            newItem = self.createSqrt(points, outline)
        elif kind == INTEGRAL:
            newItem = self.createIntegral(points, outline)
        elif kind == AXES:
            newItem = self.createAxesBox(points, outline)
        elif kind == FREEHAND:
            newItem = self.create_line(points, fill=outline, width=width)
            self.itemconfig(newItem, tags=(FREEHAND,))
        elif kind == HIGHLIGHT:
            newItem = self.create_line(points, fill=outline, width=width)
            self.itemconfig(newItem, tags=(HIGHLIGHT,))
            self.lower(newItem, self.rBase)
        elif kind == SYMBOL:
            newItem = self.createImg(points, width)
    	elif kind == GRAPH:
    	    newItem = self.createGraph(points, outline, graph=graph)
        return newItem
    
    def addItem(self, kind, points, outline, fill, width, foreignId=None, graph=None):
        if foreignId == None:
            if kind == SQRT or kind == INTEGRAL or kind == SYMBOL or kind == AXES:
                self.wbCurrentObject = self.createItem(kind, points, outline, fill, width)
            if kind == GRAPH:
                self.wbCurrentObject = self.createItem(kind, points, outline, fill, width, graph=GraphDialog.default)
                result = self.client.broadcast_addItem(self.wbCurrentObject, kind, points, outline, fill, width, graph=GraphDialog.default)
            else:
                result = self.client.broadcast_addItem(self.wbCurrentObject, kind, points, outline, fill, width)
            
        elif foreignId == PASTE or foreignId == POST:
            newItem = self.createItem(kind, points, outline, fill, width)
            result = self.client.broadcast_addItem(newItem, kind, points, outline, fill, width)
            if foreignId == PASTE:
                self.addToSelection(newItem)
        else:
            if kind == GRAPH:
                newItem = self.createItem(kind, points, outline, fill, width, graph)
            else:
                newItem = self.createItem(kind, points, outline, fill, width)
            self.foreignObjects[foreignId] = newItem
            result = defer.Deferred()

    def createImg(self, points, number, foreignId=None):
        newImg = self.create_image(points[0], points[1], image=self.imgs.getImg(number))
        self.itemconfig(newImg, tags=(SYMBOL, number))
        return newImg

    def createSqrt(self, points, color, foreignId=None):
        x0 = points[0]
        y0 = points[1]
        x1 = points[2]
        y1 = points[3]
        if x0 > x1:
            x0, x1 = x1, x0
        if y0 > y1:
            y0, y1 = y1, y0
        h = y1 - y0
        y2 = y0 + h/2
        x2 = x0 + h/5
        dx = x1 + h/5
        newLine1 = self.create_line(x0, y2, x2, y1, fill=color)
        newLine2 = self.create_line(x2, y1, x2, y0, fill=color)
        newLine3 = self.create_line(x2, y0, dx, y0, fill=color)
        newLine4 = self.create_line(dx, y0, dx, y0 + h/10, fill=color)
        tag = "sqrt" + str(newLine1)
        self.itemconfig(newLine1, tags=(SQRT, tag, x1 - x0))
        self.itemconfig(newLine3, tags=(SQRT, tag, x1 - x0))        
        self.itemconfig(newLine2, tags=(SQRT, tag, x1 - x0))
        self.itemconfig(newLine4, tags=(SQRT, tag, x1 - x0))
        return newLine2

    def createGraph(self, points, color, foreignId=None, graph=None):   
        """recibe un area rectangular del canvas (definida en points) 
        y grafica la funcion respetando las coordenadas dadas""" 
        x0 = points[0]
        y0 = points[1]
        x1 = points[2]
        y1 = points[3]
        
        if x0 > x1:
            x0, x1 = x1, x0
        if y0 > y1:
            y0, y1 = y1, y0

        if graph is None:
            graph = GraphDialog.default #atributo de clase. 
        
        f1,minx,maxx,miny,maxy = graph

        minx = float(minx)
        maxx = float(maxx)
        miny = float(miny)                
        maxy = float(maxy)
        
        f = compile(f1, f1, 'eval')
        
        h = y1 - y0
        w = x1 - x0
        hs = maxy-miny
        ws = maxx-minx
     
        assert(h>0)
        assert(w>0)
        assert(hs>0)
        assert(ws>0)
        #crear ejes.
        centroy = y0 + maxy*h/hs
        centrox = x1 - maxx*w/ws
        
        if centroy < y1 and centroy > y0:
            ejex = self.create_line(x0, centroy, x1, centroy, fill=color)
        if centrox < x1 and centrox > x0:            
            ejey = self.create_line(centrox, y0, centrox, y1, fill=color)

        coords = []
        step = 2
        cant = int(w/step)
        deltax = ws/cant
        
        for i in range(cant):
            x = minx + i*deltax
            y = eval(f, vars(math), {'x':x})
            j = y1 - h*(y-miny)/hs
            if j<y1 and j>y0:
                coords.append(x0+i*step)
                coords.append(j)
        newgraph = self.create_line(*coords)
        tag = "grap" + repr(ejex)
        self.itemconfig(newgraph, tags=(GRAPH, tag, w))
        self.itemconfig(ejex, tags=(GRAPH, tag, w))
        self.itemconfig(ejey, tags=(GRAPH, tag, w))                
        return ejex

    def createIntegral(self, points, color, foreignId=None):
        x0 = points[0]
        y0 = points[1]
        x1 = points[2]
        y1 = points[3]
        if x0 > x1:
            x0, x1 = x1, x0
        if y0 > y1:
            y0, y1 = y1, y0
        h = y1 - y0
        w = h/10
        x2 = x0 + w
        newLine1 = self.create_arc(x2, y0 + h/5, x2+w, y0, start=180, extent=-180, style=ARC, outline=color)
        newLine2 = self.create_line(x2, y1-h/10, x2, y0+h/10, fill=color)
        newLine3 = self.create_arc(x2, y1-h/5, x0, y1, start=0, extent=-180, style=ARC, outline=color)
        tag = "intg" + str(newLine2)
        self.itemconfig(newLine2, tags=(INTEGRAL, tag, h))
        self.itemconfig(newLine3, tags=(INTEGRAL, tag, h))
        self.itemconfig(newLine1, tags=(INTEGRAL, tag, h))
        return newLine2

    def createAxesBox(self, points, color, foreignId=None):
        x0 = points[0]
        y0 = points[1]
        x1 = points[2]
        y1 = points[3]
        if x0 > x1:
            x0, x1 = x1, x0
        if y0 > y1:
            y0, y1 = y1, y0
        h = y1 - y0
        w = x1 - x0
        hs = w / 12
        vs = h / 12
        orig = self.create_line(x0 + w/2, y0 + h/2, x0 + w/2, y0 + h/2, fill=color)
        tag = "axes" + str(orig)
        for i in range(0, 13):
            hLine = self.create_line(x0, y0 + i*vs, x1, y0 + i*vs, fill=color)
            vLine = self.create_line(x0 + i*hs, y0, x0 + i*hs, y1, fill=color)
            self.itemconfig(hLine, tags=(AXES, tag, h, w))
            self.itemconfig(vLine, tags=(AXES, tag, h, w))
        self.itemconfig(orig, tags=(AXES, tag, h, w))
        return orig

    def _getIntegralCoords(self, integralId, h):
        coords = self.coords(integralId)
        res = [coords[0] - h/10, coords[3] - h/10, coords[0] - h/10, coords[1] + h/10]
        return res

    def _getSqrtCoords(self, sqrtId, w):
        coords = self.coords(sqrtId)
        h = coords[1] - coords[3]
        res = [coords[0]-h/5, coords[1], coords[0]-h/5 + w, coords[3]]
        return res

    def _getAxesCoords(self, axesId, h, w):
        coords = self.coords(axesId)
        x0 = coords[0] - w/2
        y0 = coords[1] - h/2
        res = [x0, y0, x0 + w, y0 + h]
        return res

    def createTextBox(self, points, color, foreignId=None):
        if self.wbCurrentText != None:
            if self.itemcget(self.wbCurrentText, "text") == "":
                self.eraseSelectedItems([self.wbCurrentText])
                self.wbCurrentText = None
        near = self.nearestTextBox(points[0], points[1], self.NEAR_RADIO)
        if near != None:
            self.focus(near)
            self.wbCurrentText = near
            self.moveCursor(points[0], points[1])
        else:
            self.addTextBox(points, color)

    def addTextBox(self, points, color, foreignId=None):
        """
        Crea un nuevo TextBox en la posicion (x,y)
        """
        x = points[0]
        y = points[1]
        newText = self.create_text(x, y, fill=color, font=self.font)
        self.itemconfig(newText, justify=LEFT)
        self.itemconfig(newText, anchor=NW)
        self.itemconfig(newText, width=self.maxWidth - x - self.WHITEBOARD_BORDER)
        self.itemconfig(newText, tags=(TEXT, ))
        if foreignId is None:
            self.wbCurrentText = newText
            self.focus(newText)
            result = self.client.broadcast_addTextBox(newText, points, color)
        else:
            self.foreignObjects[foreignId] = newText
            result = defer.Deferred()
        return result

    def insertChars(self, textbox, index, string, foreignId=None):
        """
        Inserta string desde index en la caja de texto con id dado por
        textbox.
        """
        if foreignId is None:
            try:
                string = unicode(string, 'utf-8')
            except TypeError:
                pass
            result = self.client.broadcast_insertChars(textbox, index, string)
        else:
            textbox = self.foreignObjects[foreignId]
            result = defer.Deferred()
        self.insert(textbox, index, string)
        return result

    def sendMsg(self, string):
        """
        envia un mensaje de chat al servidor. 
        """
        try:
            string = unicode(string, 'utf-8')
        except TypeError:
            pass
        result = self.client.broadcast_sendMsg(string)        
        
        

    def addTextBoxFull(self, points, text, color, foreignId=None):
        self.addTextBox(points, color, foreignId)
        self.insertChars(self.wbCurrentText, 0, text, foreignId)

    def deleteChars(self, textbox, startIndex, endIndex, foreignId=None):
        """
        Borra el texto entre startIndex y endIndex de la caja de texto 
        con id dado por textbox.
        """
        if foreignId is None:
            result = self.client.broadcast_deleteChars(textbox, startIndex, endIndex)
        else:
            textbox = self.foreignObjects[foreignId]
            result = defer.Deferred()
        self.dchars(textbox, startIndex, endIndex)
        return result

    def nearestTextBox(self, x0, y0, dist):
        """
        Chequea si hay un TextBox a menos de dist pixeles
        a partir de la posicion (x,y).
        Devuelve: None -> si no existe
                  ret -> id de uno de los TextBoxes que se encuentren
        """
        res = self.find_overlapping(x0 - dist, y0 - dist + self.NEAR_RADIO, x0 + dist, y0 + dist + self.NEAR_RADIO)
        res = filter(lambda x: not x in self.foreignObjects.values() and self.type(x) == "text", res)
        ret = None
        if(len(res) > 0):
            ret = res[0]
        return ret

    def nextTextBox(self, x0, y0, dist, tbox=None):
        res = self.find_overlapping(x0 - dist, y0 - dist + self.NEAR_RADIO, x0 + dist, y0 + dist + self.NEAR_RADIO)
        res = filter(lambda x: not x in self.foreignObjects.values() and self.type(x) == "text" and x != tbox, res)
        ret = None
        if(len(res) > 0):
            ret = res[0]
        return ret

    def nearestImage(self, x0, y0, dist):
        """
        Chequea si hay un TextBox a menos de dist pixeles
        a partir de la posicion (x,y).
        Devuelve: None -> si no existe
                  ret -> id de uno de los TextBoxes que se encuentren
        """
        res = self.find_overlapping(x0 - dist, y0 - dist, x0 + dist, y0 + dist)
        res = filter(lambda x: not x in self.foreignObjects.values() and self.type(x) == "image", res)
        ret = None
        if(len(res) > 0):
            ret = res[0]
        return ret

    def cleanExtra(self):
        self.delete(self.rBase, self.hdelimiter, self.vdelimiter)

    def reset(self):
        self.wbCurrentText = None
        self.wbCurrentObject = None
        self.pointList = []
        objects = self.find_all()
        for i in range(0, len(objects)):
            self.delete(objects[i])
        self.rBase = self.create_rectangle(0, 0, 0, 0)
        self.itemconfig(self.rBase, tags=(RECTANGLE,))
        self.hdelimiter = self.create_line(0, 500, 700, 500, fill="black", width=1, dash=10)
        self.vdelimiter = self.create_line(700, 0, 700, 500, fill="black", width=1, dash=10)
        self.itemconfig(self.hdelimiter, tags=(DASH,))
        self.itemconfig(self.vdelimiter, tags=(DASH,))
        self.foreignObjects = {"1":self.rBase, "2":self.hdelimiter, "3":self.vdelimiter}
        self.selectedItems = []
        self.selectionBox = None
        self.clipboard.clipboardEmpty()
        self.dx = 0
        self.dy = 0
        self.mode = self.RW
        self.img = None