Beispiel #1
0
class ColorChooser(Frame):
    def __init__(self, parent, *args, **kw):

        apply(Frame.__init__, (self, parent) + args, kw)

        self.grid_rowconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=0)
        self.grid_rowconfigure(2, weight=0)
        self.grid_rowconfigure(3, weight=0)

        self.canvas = Canvas(self, relief='sunken', borderwidth=2, width=150)
        self.canvas.grid(row=0,
                         column=1,
                         columnspan=1,
                         sticky=Tkinter.NSEW,
                         pady=2,
                         padx=2)

        frame = Frame(self)
        frame.grid_columnconfigure(1, weight=1)
        self.boxSize = 100
        self.numPixels = 10
        self.pixelWidth = round(self.boxSize / self.numPixels)
        self.colorBox = Canvas(frame,
                               relief='sunken',
                               borderwidth=2,
                               width=self.boxSize + 2,
                               height=self.boxSize + 2)
        self.colorBox.bind('<Button-1>', self.pickInColorBox)
        self.colorBox.bind('<Button-2>', self.pickInColorBox)
        self.colorBox.bind('<Button-3>', self.pickInColorBox)
        self.colorBox.grid(row=0,
                           column=2,
                           rowspan=3,
                           sticky=Tkinter.NSEW,
                           padx=4,
                           pady=4)
        self.pixel = []
        self.colors = []
        self.setupColorBox()
        self.scale = Tkinter.Scale(frame,
                                   orient=Tkinter.VERTICAL,
                                   length=self.boxSize,
                                   from_=0,
                                   to=99,
                                   label='',
                                   showvalue=0,
                                   command=self.refreshColorBox)
        self.scale.grid(row=0,
                        column=3,
                        rowspan=3,
                        sticky=Tkinter.NS,
                        padx=4,
                        pady=4)
        frame.grid(row=1, column=0, columnspan=2, sticky=Tkinter.NSEW)

        labels = ('Red', 'Green', 'Blue')
        self.labeled_scale = 3 * [None]

        for n in range(3):

            label = Label(frame, text=labels[n] + ':', anchor=Tkinter.W)
            label.grid(row=n, column=0, sticky=Tkinter.EW)

            self.labeled_scale[n] = LabeledScale(
                frame,
                values=range(101),
                label_format='%3d',
                set_callback=self.scaleCallback)
            self.labeled_scale[n].grid(row=n, column=1, sticky=Tkinter.EW)

    def setupColorBox(self):

        pw = self.pixelWidth
        np = self.numPixels
        for x in range(np):
            self.pixel.append([])
            self.colors.append([])
            for y in range(np):
                rgb = hsbToRgb(0, 1 - x / float(np), 1 - y / float(np))
                c = '#%02x%02x%02x' % (rgb[0] * 255, rgb[1] * 255,
                                       rgb[2] * 255)
                p = self.colorBox.create_rectangle(2 + pw * x,
                                                   2 + pw * y,
                                                   2 + (pw * x) + pw,
                                                   (2 + pw * y) + pw,
                                                   outline=c,
                                                   fill=c)
                self.pixel[x].append(p)
                self.colors[x].append(rgb)

    def pickInColorBox(self, event):

        x = int(event.x / self.pixelWidth)
        y = int(event.y / self.pixelWidth)
        X = min(x, self.numPixels - 1)
        Y = min(y, self.numPixels - 1)
        x = max(X, 0)
        y = max(Y, 0)

        rgb = self.colors[x][y]
        self.setColor(rgb[0], rgb[1], rgb[2])

    def refreshColorBox(self, H):

        np = self.numPixels
        H = int(H) / 100.
        for x in range(np):
            for y in range(np):
                rgb = hsbToRgb(H, 1 - x / float(np), 1 - y / float(np))
                c = '#%02x%02x%02x' % (rgb[0] * 255, rgb[1] * 255,
                                       rgb[2] * 255)
                self.colorBox.itemconfigure(self.pixel[x][y],
                                            outline=c,
                                            fill=c)
                self.colors[x][y] = rgb

    def scaleCallback(self, *index):

        c = 3 * [0]
        for n in range(3):
            c[n] = int(2.559 * float(self.labeled_scale[n].getValue()))

        color = '#%02x%02x%02x' % (c[0], c[1], c[2])
        self.canvas.config(bg=color)

    def setColor(self, r, g, b):

        c = (r, g, b)
        for n in range(3):
            s = round(100.0 * c[n])
            s = min(100, s)
            self.labeled_scale[n].set(s)

    def getColor(self):

        c = 3 * [0]
        for n in range(3):
            c[n] = float(self.labeled_scale[n].getValue()) / 100.0

        return tuple(c)
Beispiel #2
0
class Spacer(Frame):
    def __init__(self, parent, relief='raised', *args, **kw):

        apply(Frame.__init__, (self, parent) + args, kw)

        #self.grid_rowconfigure(0, weight=1)
        #self.grid_columnconfigure(1, weight=1)

        self.bg = self.cget('bg')
        self.relief = relief
        self.grid_columnconfigure(0, weight=1)
        self.canvas = Canvas(self, background=self.bg, width=1, height=6)
        self.canvas.grid(row=0, column=0, sticky=Tkinter.NSEW)

        #self.canvas.bind('<Configure>', self.resizeCallback)
        self.grid(sticky=Tkinter.EW)
        self.canvasL1 = []
        self.canvasL2 = []
        self.canvasL3 = []
        self.refresh = 0
        self.event = None
        self.bind('<Configure>', self.resizeAfter)

    def resizeAfter(self, event):

        self.event = event
        if self.refresh:
            return
        else:
            self.refresh = 1
            self.after_idle(lambda: self.resize(self.event))

    def resize(self, event):

        m = 6
        w = event.width
        h = event.height
        N = int(h / m)

        self.canvas.config(width=w, height=h)
        if self.relief == 'sunken':
            fill1 = 'grey65'
            fill2 = 'grey95'
        else:
            fill1 = 'grey95'
            fill2 = 'grey65'

        for i in range(N):
            y = 1 + (i / float(N)) * h
            if i >= len(self.canvasL1):
                rect1 = self.canvas.create_rectangle(4,
                                                     y + 0,
                                                     w - 5,
                                                     y + 2,
                                                     width=0,
                                                     fill=fill1)
                rect2 = self.canvas.create_rectangle(5,
                                                     y + 1,
                                                     w - 4,
                                                     y + 3,
                                                     width=0,
                                                     fill=fill2)
                rect3 = self.canvas.create_rectangle(5,
                                                     y + 1,
                                                     w - 5,
                                                     y + 2,
                                                     width=0,
                                                     fill=self.bg)
                self.canvasL1.append(rect1)
                self.canvasL2.append(rect2)
                self.canvasL3.append(rect3)
            else:
                self.canvas.coords(self.canvasL1[i], 4, y + 0, w - 5, y + 2)
                self.canvas.coords(self.canvasL2[i], 5, y + 1, w - 4, y + 3)
                self.canvas.coords(self.canvasL3[i], 5, y + 1, w - 5, y + 2)

        if N > len(self.canvasL1):
            for i in range(N, len(self.canvasL1)):
                self.canvas.delete(self.canvasL1[i])
                self.canvas.delete(self.canvasL2[i])
                self.canvas.delete(self.canvasL3[i])

        self.refresh = 0
Beispiel #3
0
class Tree(Frame):
    def __init__(self,
                 parent,
                 iconSize='medium',
                 multiSelect=False,
                 font='Helvetica 8',
                 doubleCallback=None,
                 *args,
                 **kw):

        Frame.__init__(self, parent, *args, **kw)

        self.multiSelect = multiSelect
        self.icons = {}
        self.openDict = {}
        self.scrollbarWidth = 15
        self.canvasList = []
        self.canvasDict = {}
        self.canvasLines = []
        self._wait = False
        self.vOffset = 0
        self.nodes = []  # Just a list of nodes
        self.nodeDict = {}  # To fetch nodes via objects
        self.font = font
        self.doubleCallback = doubleCallback

        #bg = self.cget('background')

        iconItems = [{
            'kind': 'command',
            'label': 'Small',
            'command': self.smallIcons
        }, {
            'kind': 'command',
            'label': 'Medium',
            'command': self.medIcons
        }, {
            'kind': 'command',
            'label': 'Large',
            'command': self.largeIcons
        }]

        self.menu = Menu(self, tearoff=False)
        menu_items = [
            {
                'kind': 'cascade',
                'label': 'Icon size',
                'submenu': iconItems
            },
        ]

        self.menu.setMenuItems(menu_items)

        self.rowHeight = None
        self.visibleRows = 80

        self.setIconSize(iconSize, redraw=False)

        self.canvas = Canvas(self,
                             relief='flat',
                             borderwidth=0,
                             background=BG_COLOR,
                             xscrollcommand=self._setHScrollbar,
                             *args,
                             **kw)

        self.canvas.pack()

        self.xScrollbar = Scrollbar(self,
                                    orient='horizontal',
                                    width=self.scrollbarWidth,
                                    borderwidth=1,
                                    callback=self._moveHScrollbar,
                                    background=BG_COLOR)

        self.yScrollbar = Scrollbar(self,
                                    orient='vertical',
                                    width=self.scrollbarWidth,
                                    borderwidth=1,
                                    callback=self._setVScrollbar,
                                    background=BG_COLOR)

        self.canvas.bind('<Button-1>', self._mouseClick)
        self.canvas.bind('<Double-1>', self._mouseDoubleClick)
        if isWindowsOS:
            self.canvas.bind('<MouseWheel>', self._windowsOsScroll)
        else:
            self.canvas.bind('<Button-4>', self._mouseUp)
            self.canvas.bind('<Button-5>', self._mouseDown)

        self.canvas.bind('<p>', self._printCanvas)
        self.canvas.bind('<KeyPress-Prior>', self._pageUp)
        self.canvas.bind('<KeyPress-Next>', self._pageDown)
        self.canvas.bind('<KeyPress-Up>', self._keyUp)
        self.canvas.bind('<KeyPress-Down>', self._keyDown)
        self.canvas.bind('<KeyPress-Home>', self._keyHome)
        self.canvas.bind('<KeyPress-End>', self._keyEnd)
        self.canvas.bind('<Enter>', self._enter)
        self.canvas.bind('<ButtonPress-3>', self._popupMenu)

        self.bind('<Configure>', self._changeSizeAfter)

    def _popupMenu(self, event):

        self.menu.popupMenu(event)

    def smallIcons(self):

        self.setIconSize('small')

    def medIcons(self):

        self.setIconSize('medium')

    def largeIcons(self):

        self.setIconSize('large')

    def setIconSize(self, iconSize, redraw=True):

        size = ICON_SIZE_DICT.get(iconSize, 22)
        if size != self.rowHeight:
            self.rowHeight = size + 1
            self.font = 'Helvetica %d' % (size / 2)

            ccpnDir = getTopDirectory()
            iconDir = '%dx%d' % (size, size)
            imageDir = path.join(ccpnDir, 'python', 'memops', 'gui',
                                 'graphics', iconDir)

            files = [f for f in listdir(imageDir) if f.endswith('.gif')]

            for file in files:
                imageFile = path.join(imageDir, file)
                self.icons[file[:-4]] = PhotoImage(file=imageFile)

            if redraw:
                self._changeSize()

        return size

    def _setHScrollbar(self, start, end):

        self.xScrollbar.set(float(start), float(end))

    def _moveHScrollbar(self, start, end):

        self.canvas.xview('moveto', start)

    def _enter(self, event):

        self.menu.popdownMenu()
        self.canvas.focus_force()

    def _printCanvas(self, *event):

        from memops.gui.FileSelect import FileType
        from memops.gui.FileSelectPopup import FileSelectPopup

        fileTypes = [FileType('PostScript', ['*.ps']), FileType('All', ['*'])]
        fileSelectPopup = FileSelectPopup(self,
                                          file_types=fileTypes,
                                          title='Print canvas to file',
                                          dismiss_text='Cancel',
                                          selected_file_must_exist=False)

        fileName = fileSelectPopup.getFile()

        self.canvas.postscript(colormode='color', file=fileName)

    def _windowsOsScroll(self, event):

        delta = event.delta
        if delta > 0:
            self._mouseUp(event)
        elif delta < 0:
            self._mouseDown(event)

    def _keyHome(self, event):

        self.vOffset = 0
        self._drawAfter()

    def _keyEnd(self, event):

        numNodes = len(self.nodes)
        visNodes = self.visibleRows
        self.vOffset = max(0, numNodes - visNodes)
        self._drawAfter()

    def _scroll(self, delta=1):

        height = int(self.winfo_height())
        numNodes = len(self.nodes)
        visNodes = self.visibleRows

        if numNodes <= visNodes:
            return

        vOffset = self.vOffset + delta
        vOffset = max(0, vOffset)
        vOffset = min(numNodes - visNodes, vOffset)

        if vOffset != self.vOffset:
            self.vOffset = vOffset
            self._drawAfter()

    def _pageUp(self, event):

        self._scroll(-1 * self.visibleRows)

    def _pageDown(self, event):

        self._scroll(self.visibleRows)

    def _mouseUp(self, event):

        self._scroll(-8)

    def _mouseDown(self, event):

        self._scroll(8)

    def _keyUp(self, event):

        self._scroll(-1)

    def _keyDown(self, event):

        self._scroll(1)

    def _setVScrollbar(self, start, end):

        self.cancelEdits()

        height = int(self.winfo_height())

        gaps = start + 1 - end

        nRows = float(len(self.nodes))

        if gaps == 0 or nRows == 0.0:
            self.yScrollbar.set(0, 1)
            self.vOffset = 0
        else:

            # Have to do this so that the bar keeps up with the mouse
            overlap = int(nRows - self.visibleRows)
            size = min(1.0, self.visibleRows / nRows)
            self.yScrollbar.set(min(gaps, max(0, start)),
                                max(size, min(1.0, start + size)))
            self.vOffset = min(
                max(0, int('%1.1d' % (start / gaps * (overlap + 1)))), overlap)

            #vOffset = max(0, start*nRows)
            #vOffset = min(nRows-self.visibleRows, vOffset)
            #self.vOffset = int(vOffset)

        self._drawAfter()

    def _updateScrollBars(self):

        allRows = len(self.nodes)
        visRows = self.visibleRows

        if allRows < visRows:
            self.vOffset = 0
            self.yScrollbar.set(0, 1)
            self.yScrollbar.place_forget()

        else:
            size = self.scrollbarWidth
            width = int(self.winfo_width()) - 1
            height = int(self.winfo_height()) - 1
            start = float(self.vOffset) / allRows
            end = float(self.vOffset + visRows) / allRows

            self.yScrollbar.set(start, end)
            self.yScrollbar.place(x=width - size + 1,
                                  y=1,
                                  width=size,
                                  height=height)

        self.update_idletasks()

    def _mouseClick(self, event):

        self.cancelEdits()

        x = self.canvas.canvasx(event.x)
        y = self.canvas.canvasy(event.y)
        obj = self.canvas.find('closest', x, y)[0]
        node, typ = self.canvasDict.get(obj, (None, None))

        if node:
            if typ is TOGGLE:
                node.toggle()

            else:
                if self.multiSelect and (event.state & 4 or event.state & 1):
                    if event.state & 4:
                        node.isSelected = not node.isSelected

                    elif event.state & 1:
                        indices = [
                            self.nodes.index(node),
                        ]
                        for i, node2 in enumerate(self.nodes):
                            if node2.isSelected:
                                indices.append(i)

                        for node2 in self.nodes[min(indices):max(indices) + 1]:
                            node2.isSelected = True

                else:
                    for node2 in self.nodes:
                        if node2.isSelected:
                            node2.isSelected = False

                    node.isSelected = True

            self._drawAfter()

    def _mouseDoubleClick(self, event):

        self.cancelEdits()

        x = self.canvas.canvasx(event.x)
        y = self.canvas.canvasy(event.y)
        obj = self.canvas.find('closest', x, y)[0]
        node, typ = self.canvasDict.get(obj, (None, None))

        if node:
            if typ is TOGGLE:
                #node.toggle()
                return

            elif self.doubleCallback:
                self.doubleCallback(node)

        self._drawAfter()

    def _drawAfter(self):

        if self._wait:
            return

        self._wait = True
        self.after_idle(self._draw)

    def _draw(self):

        self._updateScrollBars()

        delta = self.rowHeight
        canvas = self.canvas
        cImage = canvas.create_image
        cList = self.canvasList
        cDict = self.canvasDict
        cLines = self.canvasLines
        cConfig = canvas.itemconfigure
        cDel = canvas.delete
        cCoords = canvas.coords
        cText = canvas.create_text
        cRect = canvas.create_rectangle
        cBbox = canvas.bbox
        cLine = canvas.create_line
        cLift = canvas.lift
        cLower = canvas.lower
        cPoly = canvas.create_polygon
        nodes = self.nodes
        nodeDict = self.nodeDict
        visibleRows = self.visibleRows
        icons = self.icons
        font = self.font
        vOffset = self.vOffset
        bg = BG_COLOR  # self.cget('bg')

        roots = [n for n in nodes if not n.parent]

        if not roots:
            raise Exception('No rooted nodes')

        for item in cLines:
            cDel(item)

        stack = [(node, 0) for node in roots]
        nodes = []
        while stack:
            node, level = stack.pop(0)
            nodes.append((node, level))

            if node.isOpen:
                level2 = level + 1
                stack = [(c, level2) for c in node.children] + stack

        yDict = {}
        pLevel = 0
        pNode = None
        pad = 2 + (delta / 2)
        bSpace = 4
        nodes = nodes[vOffset:]
        for row, data in enumerate(nodes):

            node, level = data

            y = pad + row * delta
            x = pad + level * delta
            x1 = x + delta
            x2 = x1 + delta - bSpace

            yDict[node] = y, x1

            yP, xP = yDict.get(node.parent, (0, x))

            if yP is not None:
                line = cLine(xP, yP, xP, y, fill=LINE_COLOR, width=1)
                cLower(line)
                cLines.append(line)

            if row > visibleRows:
                break

            iconImage = icons[node.icon]

            if node.isSelected:
                bgColor = SELECT_BG_COLOR
                fgColor = SELECT_FG_COLOR
            else:
                bgColor = bg
                fgColor = bg

            if row < len(cList):
                line, rect, tog1, tog2, box, icon, text = cList[row]
                cConfig(rect, fill=bgColor, outline=fgColor)
                cConfig(icon, image=iconImage)
                cConfig(text, text=node.label or '', font=font)
                cCoords(icon, x1, y)
                cCoords(text, x2, y)
                cCoords(line, x, y, x1, y)

            else:
                line = cLine(x, y, x1, y, fill=LINE_COLOR)
                rect = cRect(x, y, x2, y, fill=bgColor, outline=fgColor)
                box = cRect(-2, -2, -2, -2, fill=NODE_BG_COLOR)
                tog1 = cLine(-2, -2, -2, -2)
                tog2 = cLine(-2, -2, -2, -2)
                icon = cImage(x1, y, image=iconImage)
                text = cText(x2,
                             y,
                             text=node.label or '',
                             justify='left',
                             anchor='w',
                             font=font)
                cList.append((line, rect, tog1, tog2, box, icon, text))

            if node.callback:
                cCoords(box, x - 4, y - 4, x + 4, y + 4)

                if node.isOpen:
                    cCoords(tog1, -2, -2, -2, -2)
                    cCoords(tog2, x - 2, y, x + 3, y)

                else:
                    cCoords(tog1, x, y - 2, x, y + 3)
                    cCoords(tog2, x - 2, y, x + 3, y)

            else:
                cCoords(tog1, -2, -2, -2, -2)
                cCoords(tog2, -2, -2, -2, -2)
                cCoords(box, -2, -2, -2, -2)

            bbox = cBbox(text)
            if bbox:
                cCoords(rect, bbox[0] - 2, bbox[1], bbox[2] + 2, bbox[3])

            cLift(box)
            cLift(tog1)
            cLift(tog2)

            cDict[tog1] = (node, TOGGLE)
            cDict[tog2] = (node, TOGGLE)
            cDict[box] = (node, TOGGLE)
            cDict[text] = (node, TEXT)
            cDict[icon] = (node, ICON)

        nRows = min(visibleRows, len(nodes))
        if len(cList) > nRows:
            for row in range(nRows, len(cList)):
                for item in cList[row]:
                    if cDict.get(item):
                        del cDict[item]
                    cDel(item)

            self.canvasList = cList[:nRows]

        self._wait = False

    def setFont(self, font):

        self.font = font
        self._drawAfter()

    def _changeSizeAfter(self, event):

        self.after_idle(lambda: self._changeSize(event))

    def _changeSize(self, event=None):

        self.cancelEdits()

        if event:
            width = event.width
            height = event.height
        else:
            width = int(self.winfo_width())
            height = int(self.winfo_height())

        self.canvas.config(width=width, height=height)
        self.visibleRows = height / self.rowHeight

        bbox = self.canvas.bbox('all')

        if bbox:  # None at startup: nothing drawn
            canvasWidth = bbox[2] - bbox[0]
            if width < canvasWidth:
                size = self.scrollbarWidth
                end = width / float(canvasWidth)
                self.canvas.config(scrollregion="0 0 %s %s" %
                                   (canvasWidth, height))

                if self.visibleRows < len(self.nodes):
                    self.xScrollbar.place(x=0,
                                          y=height - size,
                                          width=width - size,
                                          height=size)
                else:
                    self.xScrollbar.place(x=0,
                                          y=height - size,
                                          width=width,
                                          height=size)

                self.xScrollbar.set(0, end)
            else:
                self.xScrollbar.place_forget()
        else:
            self.xScrollbar.place_forget()

        self._drawAfter()

    # Public

    def cancelEdits(self):

        self.menu.popdownMenu()

    def getSelected(self):

        return [node.object for node in self.nodes if node.isSelected]

    def select(self, object, expand=True):

        node = self.nodeDict.get(object)
        if node is not None:
            node.isSelected = True

            if expand:
                parent = node.parent

                while parent:
                    parent.isOpen = True
                    parent = parent.parent

            self._drawAfter()

    def selectAll(self, expand=True):

        for node in self.nodes:
            node.isSelected = True
            if expand:
                node.isOpen = expand

    def selectDeep(self, object, expand=True):

        node = self.nodeDict.get(object)
        if node is not None:
            stack = [
                node,
            ]
            nodes = []

            while stack:
                node2 = stack.pop()
                stack.extend(node2.children)
                nodes.append(node2)

            for node2 in nodes:
                if expand:
                    node2.isOpen = True
                node2.isSelected = True

            self._drawAfter()

    def setSelected(self, objects, expand=True):

        select = self.select
        for object in objects:
            select(object, expand)

    def expand(self, object):

        node = self.nodeDict.get(object)
        if node is not None:
            node.expand()
            self._drawAfter()

    def expandAll(self):

        for node in self.nodes:
            node.expand()

        self._drawAfter()

    def expandDeep(self, object):

        node = self.nodeDict.get(object)
        if node is not None:
            stack = [
                node,
            ]
            nodes = []

            while stack:
                node2 = stack.pop()
                stack.extend(node2.children)
                nodes.append(node2)

            for node2 in nodes:
                node2.iexpand()

            self._drawAfter()

    def contract(self, object):

        node = self.nodeDict.get(object)
        if node is not None:
            node.collapse()
            self._drawAfter()

    def contractAll(self):

        for node in self.nodes:
            node.collapse()

        self._drawAfter()

    def contractDeep(self, object):

        node = self.nodeDict.get(object)
        if node is not None:
            stack = [
                node,
            ]
            nodes = []

            while stack:
                node2 = stack.pop()
                stack.extend(node2.children)
                nodes.append(node2)

            for node2 in nodes:
                node2.collapse()

            self._drawAfter()

    def update(self,
               parents,
               objects,
               labels=None,
               icons=None,
               callbacks=None,
               editWidgets=None):

        n = len(parents)

        for test in (objects, callbacks, labels, icons, editWidgets):
            if test is not None:
                assert len(test) == n

        self.nodes = nodes = []
        self.nodeDict = nodeDict = {}
        self.openDict = {}

        if not labels:
            labels = [None] * n

        if not icons:
            icons = [None] * n

        if not callbacks:
            callbacks = [None] * n

        if not editWidgets:
            editWidgets = [[] for x in xrange(n)]

        for i, parent in enumerate(parents):
            object = objects[i]

            node = Node(self, parent, object, labels[i], icons[i],
                        callbacks[i], False, False, editWidgets[i])

        # JMCI FIXME: need to understand how the redraw works

        self._draw()

    def add(self,
            parent,
            object,
            label=None,
            icon='media-playback-stop',
            callback=None,
            isOpen=False,
            isSelected=False,
            editWidgets=None):

        nodeDict = self.nodeDict
        if nodeDict.get(object):
            nodeDict[object].delete()

            #raise Exception('Node already present for object %s' % object)

        node = Node(self, parent, object, label, icon, callback, isOpen,
                    isSelected, editWidgets)

    def remove(self, object):

        node = self.nodeDict.get(object)
        if node is not None:
            if self.openDict.get(object):
                del self.openDict[object]

            node.delete()

            self._drawAfter()