def body(self, parent): self.bw = 2 # borderwidth width = self.cWidth + self.bw height = self.cHeight + self.bw self.label = Label(parent, text=self.text) self.label.grid(row=0, column=0, sticky=Tkinter.W) self.percent = Label(parent, text=' %') self.percent.grid(row=0, column=2, sticky=Tkinter.W) self.canvas = Canvas(parent, background='grey70', width=width, height=height) self.canvas.grid(row=0, column=1, sticky=Tkinter.W) self.canvas.create_rectangle(0, 0, width, height, outline='black', width=self.bw) self.bar = self.canvas.create_rectangle(self.bw, self.bw, self.bw, self.cHeight, outline='#B05848', fill='#B05848', width=self.bw) self.update()
def __init__(self, parent, resizeCallback = None, width=600, height=600, *args, **kw): self.bbox = None self.busy = 0 self.initialX = None self.initialY = None self.resizeCallback = resizeCallback apply(Frame.__init__, (self, parent) + args, kw) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.menu = Menu(self, tearoff=0, include_event=True) self.configMenu() self.canvas = Canvas(self, relief='flat', borderwidth=0, width=width, height=height) self.canvas.configure(xscrollincrement=2, yscrollincrement=2) self.canvas.grid(row = 0, column = 0, sticky = Tkinter.NSEW ) self.horizScrollbar = Tkinter.Scrollbar(self, bg=self.cget('bg'), command=self.canvas.xview, orient=Tkinter.HORIZONTAL, borderwidth=1) self.vertScrollbar = Tkinter.Scrollbar(self, bg=self.cget('bg'), command=self.canvas.yview, orient=Tkinter.VERTICAL, borderwidth=1) self.canvas.configure(xscrollcommand=self.horizScrollbar.set,yscrollcommand=self.vertScrollbar.set) self.canvas.bind('<Configure>', self.resizeAfter) self.canvas.bind('<Button-1>', self.mouseButton1) self.canvas.bind('<Button-2>', self.mouseButton2) self.canvas.bind('<Button-3>', self.mouseButton3) self.canvas.bind('<ButtonRelease-1>', self.mouseButtonRelease1) self.canvas.bind('<ButtonRelease-2>', self.mouseButtonRelease2) self.canvas.bind('<B2-Motion>', self.mouseScroll) self.canvas.bind('<B3-Motion>', self.doNothing) self.canvas.bind('<Motion>', self.mouseEnter) self.canvas.bind('<Enter>', self.mouseEnter)
def __init__(self, parent, callback=None, texts=None, objects=None, categories=None, colors=None, index=0, prefix='', indent='', initCallback=False, forceCallback=False, numbering=False, arrowLine='#602000', arrowFill='#B05848', labelColor='#501000', menuBg='#F0F0FF', sticky='w', docKey=None, tipText=None, categoriesLast=True, *args, **kw): Frame.__init__(self, parent, sticky=sticky, docKey=docKey, tipText=tipText, createToolTip=True, *args, **kw) self.callback = callback self.texts = texts or [] self.objects = objects or [] self.categories = categories or [] self.colors = colors or [] self.prefix = prefix self.indent = indent self.initCallback = initCallback self.numbering = numbering self.arrowLine = arrowLine self.arrowFill = arrowFill self.labelColor = labelColor self.active = True self.categoriesLast = categoriesLast # Current selection self.index = None self.object = NullText self.rows = [] self.bg = self.cget('bg') self.label = Label(self, foreground=labelColor) self.canvas = Canvas(self, width=12, height=12, background=self.bg) self.menu = Menu(self.canvas, tearoff=False, bg=menuBg, relief='solid', borderwidth=1, activeborderwidth=1) self.menu.images = [] # Photoimage has to remain referenced self.setup(self.texts, self.objects, index, self.colors, self.categories) self.label.bind( "<Button-1>", self._labelClick) self.menu.bind( "<Leave>", self._leave) self.canvas.bind("<Button-1>", self._canvasClick) self.canvas.bind("<Configure>", self._resizeCallback) self.grid_columnconfigure(0, weight=1) self.label.grid(row=0, column=0, sticky='w') self.canvas.grid(row=0, column=1, sticky='w', padx=2)
def __init__(self, parent, borderRelief='raised', text=' ', justify='left', font=None, sticky='ew', docKey=None, tipText=None, *args, **kw): Frame.__init__(self, parent, sticky=sticky, *args, **kw) self.borderRelief = borderRelief self.bg = self.cget('bg') self.justify = justify self.canvas1 = Canvas(self, background=self.bg) if self.borderRelief == 'sunken': fill1 = 'grey60' fill2 = 'white' else: fill1 = 'white' fill2 = 'grey60' fill3 = 'grey85' self.label = Label(self, text=text, font=font, docKey=docKey, tipText=tipText) self.label.grid() self.canvasL = [ self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3) ] self.canvasR = [ self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3) ] self.bind('<Configure>', self.resize)
def __init__(self, parent, color='black', side='both', canvas_bg='lightgrey', *args, **kw): self.color = color self.side = side apply(Frame.__init__, (self, parent) + args, kw) #self.grid_rowconfigure(0, weight=1) #self.grid_columnconfigure(1, weight=1) fill = Tkinter.X w = kw.get('width', 1) z = h = kw.get('height', 1) #self.canvas.config(height=h) self.canvas = Canvas(self, width=w, height=h, background=canvas_bg) self.cross = {'upper': [], 'lower': [], 'both': []} # # This is setup only... coordinates do not matter here # if self.side in ['both', 'upper']: self.cross['upper'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.cross['upper'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.cross['both'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) if self.side in ['both', 'lower']: self.cross['lower'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.cross['lower'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.canvas.pack(expand=Tkinter.YES, fill=fill) #self.canvas.bind('<Configure>', self.resizeCallback) self.bind('<Configure>', self.resizeCallback)
def __init__(self, parent, arrowSize=11, outline='#5050b0', fill='#a0a0ff', isArrowClosed=True, callback=None, *args, **kw): self.arrowSize = arrowSize self.isArrowClosed = isArrowClosed self.callback = callback apply(Frame.__init__, (self, parent) + args, kw) bg = kw.get('bg') if (not bg): bg = kw.get('background') if (not bg): bg = parent.cget('bg') # below does not work for some reason, instead explicitly create rectangle below #self.canvas = Canvas(self, width=arrowSize, height=arrowSize, bg=bg) self.canvas = Canvas(self, width=arrowSize + 3, height=arrowSize + 1) self.canvas.grid(row=0, column=0) # need +/-1 otherwise get line along borders self.canvas.create_rectangle(-1, -1, arrowSize + 3, arrowSize + 1, fill=bg) # arbitrary coords self.arrow = self.canvas.create_polygon(0, 0, 1, 0, 1, 1, fill=fill, outline=outline) self.drawArrow() self.canvas.bind('<Button-1>', self.flipState)
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 __init__(self, parent, callback, speed = 1.5, delay = 50, fill = 'grey73', outline = 'grey90', hilight='grey90', width = 144, height = 24, *args, **kw): self.callback = callback self.speed = speed self.delay = delay self.fill = fill self.outline = outline self.hilight = hilight Frame.__init__(self, parent=parent, *args, **kw) # if canvas width/height fixed then resizing has no effect, it seems #self.grid_rowconfigure(0, weight=1) #self.grid_columnconfigure(0, weight=1) font = '-schumacher-clean-bold-r-normal--14-140-75-75-c-70-iso646.1991-irv' self.canvas = c = Canvas(self, width=width, height=height, relief='flat', borderwidth=0) c.bind('<Configure>', self.resize) c.bind('<ButtonPress>', self.press) c.bind('<Motion>', self.motion) c.bind('<Enter>', self.mouseEnter) c.bind('<Leave>', self.mouseLeave) c.bind('<ButtonRelease>', self.release) self.bg = c.create_rectangle(1, 1, 1, 1, fill='red', outline='grey50') self.boxes0 = [] self.boxes1 = [] self.boxes2 = [] self.strikes = [] self.dashes = [] for n in range(24): box1 = c.create_rectangle(0, 0, 0, 0, fill=outline, outline=outline) box2 = c.create_rectangle(0, 0, 0, 0, fill=outline, outline=outline) box0 = c.create_rectangle(0, 0, 0, 0, fill=outline, outline=outline) self.boxes0.append(box0) self.boxes1.append(box1) self.boxes2.append(box2) for n in range(8): dash = c.create_line(0,0,0,0,fill='black') self.dashes.append( dash ) for n in range(4): strike = c.create_line(0,0,0,0,fill='black') self.strikes.append( strike ) c.grid(row=0, column=0, sticky=Tkinter.NSEW) self.continue_callback = False self.multiplier = 1.0
def refreshSize(self, event=None): canvas = Canvas(self) textItem = canvas.create_text(0, 0, text='A', font=self.font) coords = canvas.bbox(textItem) letterWidth = coords[2] - coords[0] + 2 canvas.destroy() if not self.buttons: return if event: width = event.width height = event.height else: width = int(self.winfo_width()) height = int(self.winfo_height()) self.maxRowObjects = len(self.buttons) x = 0 for i, button in enumerate(self.buttons): text = button.cget('text') if '\n' in text: texts = text.split('\n') text = texts[0] for t in texts[1:]: if len(t) > len(text): text = t n = len(text) x1 = x + int(letterWidth * n) if x1 > width: self.maxRowObjects = max(1, i) break x = x1 self.update(self.objects, None, self.labels, self.colors, self.fonts) self.waiting = False
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()
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
def __init__(self, parent, borderRelief='raised', text=' ', justify='left', width=None, font=None, height=None, docKey=None, tipText=None, *args, **kw): kw['borderwidth'] = self.bw = 18 Frame.__init__(self, parent, *args, **kw) self.borderRelief = borderRelief self.bg = self.cget('bg') self.justify = justify self.canvas1 = Canvas(self, background=self.bg) self.canvas2 = Canvas(self, background=self.bg) self.canvas3 = Canvas(self, background=self.bg) self.canvas4 = Canvas(self, background=self.bg) if self.borderRelief == 'sunken': fill1 = 'grey60' fill2 = 'white' else: fill1 = 'white' fill2 = 'grey60' fill3 = 'grey85' self.label = Label(self, text=text, font=font, docKey=None, tipText=tipText) self.canvasL1 = [] self.canvasL1a = [] self.canvasL2 = [] self.canvasL3 = [] self.canvasL3a = [] self.canvasL3b = [] self.canvasL4 = [] self.canvasL5 = [] self.canvasL5a = [] self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.bind('<Configure>', self.resize)
class LabelFrame(Frame): def __init__(self, parent, borderRelief='raised', text=' ', justify='left', width=None, font=None, height=None, docKey=None, tipText=None, *args, **kw): kw['borderwidth'] = self.bw = 18 Frame.__init__(self, parent, *args, **kw) self.borderRelief = borderRelief self.bg = self.cget('bg') self.justify = justify self.canvas1 = Canvas(self, background=self.bg) self.canvas2 = Canvas(self, background=self.bg) self.canvas3 = Canvas(self, background=self.bg) self.canvas4 = Canvas(self, background=self.bg) if self.borderRelief == 'sunken': fill1 = 'grey60' fill2 = 'white' else: fill1 = 'white' fill2 = 'grey60' fill3 = 'grey85' self.label = Label(self, text=text, font=font, docKey=None, tipText=tipText) self.canvasL1 = [] self.canvasL1a = [] self.canvasL2 = [] self.canvasL3 = [] self.canvasL3a = [] self.canvasL3b = [] self.canvasL4 = [] self.canvasL5 = [] self.canvasL5a = [] self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1)) self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2)) self.canvasL1.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL1a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL2.append( self.canvas2.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3a.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL3b.append( self.canvas3.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL4.append( self.canvas4.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL5.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.canvasL5a.append( self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3)) self.bind('<Configure>', self.resize) def setText(self, text): self.label.set(text) self.resize() def resize(self, event=None): if event: w = event.width h = event.height else: w = int(self.winfo_width()) h = int(self.winfo_height()) self.after_idle(lambda: self.draw(w, h)) def draw(self, w, h): bw = self.bw pad = bw / 2 h2 = h - (2 * bw) textWidth = int(self.label.winfo_reqwidth()) if self.justify == 'left': textLeft = (3 * pad) + (0.05 * w) textRight = min(w, textLeft + textWidth) elif self.justify == 'right': textRight = (3 * pad) + (0.05 * w) textLeft = w - (textWidth + textRight) else: textLeft = (w / 2) - (textWidth / 2) textRight = textLeft + textWidth c1 = self.canvas1 c2 = self.canvas2 c3 = self.canvas3 c4 = self.canvas4 c1coords = c1.coords c2coords = c2.coords c3coords = c3.coords c4coords = c4.coords c1.place(x=0, y=0, anchor='nw', width=w, height=bw, bordermode='ignore') c2.place(x=0, y=bw, anchor='nw', width=bw, height=h2, bordermode='ignore') c3.place(x=0, y=h - bw, anchor='nw', width=w, height=bw, bordermode='ignore') c4.place(x=w - bw, y=bw, anchor='nw', width=bw, height=h2, bordermode='ignore') self.label.place(x=textLeft, y=0, anchor='nw', bordermode='ignore') e1, e2, e3 = self.canvasL1 c1coords(e1, pad, pad, textLeft - pad + 3, pad + 3) c1coords(e2, pad + 1, pad + 1, textLeft - pad + 3, pad + 3) c1coords(e3, pad + 1, pad + 1, textLeft - pad + 2, pad + 2) e1, e2, e3 = self.canvasL1a c1coords(e1, pad, pad, pad + 3, bw) c1coords(e2, pad + 1, pad + 1, pad + 3, bw) c1coords(e3, pad + 1, pad + 1, pad + 2, bw) e1, e2, e3 = self.canvasL2 c2coords(e1, pad, 0, pad + 3, h2) c2coords(e2, pad + 1, 0, pad + 3, h2) c2coords(e3, pad + 1, 0, pad + 2, h2) e1, e2, e3 = self.canvasL3 c3coords(e1, pad, pad, w - pad + 3, pad + 3) c3coords(e2, pad + 1, pad + 1, w - pad + 3, pad + 3) c3coords(e3, pad + 1, pad + 1, w - pad + 2, pad + 2) e1, e2, e3 = self.canvasL3a c3coords(e1, pad, 0, pad + 3, pad + 3) c3coords(e2, pad + 1, 0, pad + 3, pad + 3) c3coords(e3, pad + 1, 0, pad + 2, pad + 2) e1, e2, e3 = self.canvasL3b c3coords(e1, w - pad, 0, w - pad + 3, pad + 3) c3coords(e2, w - pad + 1, 0, w - pad + 3, pad + 3) c3coords(e3, w - pad + 1, 0, w - pad + 2, pad + 2) e1, e2, e3 = self.canvasL4 c4coords(e1, pad, 0, pad + 3, h2) c4coords(e2, pad + 1, 0, pad + 3, h2) c4coords(e3, pad + 1, 0, pad + 2, h2) e1, e2, e3 = self.canvasL5 c1coords(e1, textRight + pad, pad, w - pad + 3, pad + 3) c1coords(e2, textRight + pad + 1, pad + 1, w - pad + 3, pad + 3) c1coords(e3, textRight + pad + 1, pad + 1, w - pad + 2, pad + 2) e1, e2, e3 = self.canvasL5a c1coords(e1, w - pad, pad, w - pad + 3, bw) c1coords(e2, w - pad + 1, pad + 1, w - pad + 3, bw) c1coords(e3, w - pad + 1, pad + 1, w - pad + 2, bw)
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)
class CrossLine(Frame): def __init__(self, parent, color='black', side='both', canvas_bg='lightgrey', *args, **kw): self.color = color self.side = side apply(Frame.__init__, (self, parent) + args, kw) #self.grid_rowconfigure(0, weight=1) #self.grid_columnconfigure(1, weight=1) fill = Tkinter.X w = kw.get('width', 1) z = h = kw.get('height', 1) #self.canvas.config(height=h) self.canvas = Canvas(self, width=w, height=h, background=canvas_bg) self.cross = {'upper': [], 'lower': [], 'both': []} # # This is setup only... coordinates do not matter here # if self.side in ['both', 'upper']: self.cross['upper'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.cross['upper'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.cross['both'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) if self.side in ['both', 'lower']: self.cross['lower'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.cross['lower'].append( self.canvas.create_line(0, 0, 0, 0, fill=color)) self.canvas.pack(expand=Tkinter.YES, fill=fill) #self.canvas.bind('<Configure>', self.resizeCallback) self.bind('<Configure>', self.resizeCallback) def resizeCallback(self, event): self.update_idletasks() #w = self.canvas.winfo_width() #h = self.canvas.winfo_height() w = self.winfo_width() h = self.winfo_height() if self.side == 'both': mh = h / 2 elif self.side == 'lower': mh = 0 else: mh = h if self.side in ['both', 'upper']: self.canvas.coords(self.cross['upper'][0], 0, 0, w / 3, mh) self.canvas.coords(self.cross['upper'][1], w * 2 / 3, mh, w, 0) self.canvas.coords(self.cross['both'][0], w / 3, mh, w * 2 / 3, mh) if self.side in ['both', 'lower']: self.canvas.coords(self.cross['lower'][0], 0, h, w / 3, mh) self.canvas.coords(self.cross['lower'][1], w * 2 / 3, mh, w, h) # color is a tuple def setColor(self, color): (r, g, b) = color self.canvas.itemconfig(self.item, fill=hexRepr(r, g, b))
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)
class LabelDivider(Frame): def __init__(self, parent, borderRelief='raised', text=' ', justify='left', font=None, sticky='ew', docKey=None, tipText=None, *args, **kw): Frame.__init__(self, parent, sticky=sticky, *args, **kw) self.borderRelief = borderRelief self.bg = self.cget('bg') self.justify = justify self.canvas1 = Canvas(self, background=self.bg) if self.borderRelief == 'sunken': fill1 = 'grey60' fill2 = 'white' else: fill1 = 'white' fill2 = 'grey60' fill3 = 'grey85' self.label = Label(self, text=text, font=font, docKey=docKey, tipText=tipText) self.label.grid() self.canvasL = [ self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3) ] self.canvasR = [ self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill1), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill2), self.canvas1.create_rectangle(0, 0, 0, 0, width=0, fill=fill3) ] self.bind('<Configure>', self.resize) def setText(self, text): self.label.set(text) self.resize() def resize(self, event=None): if event: w = event.width h = event.height else: w = int(self.winfo_width()) h = int(self.winfo_height()) self.after_idle(lambda: self.draw(w, h)) def draw(self, w, h): bw = int(self.label.winfo_height()) pad = bw / 2 h2 = h - (2 * bw) textWidth = int(self.label.winfo_reqwidth()) if self.justify == 'left': textLeft = (3 * pad) + (0.05 * w) textRight = min(w, textLeft + textWidth) elif self.justify == 'right': textRight = (3 * pad) + (0.05 * w) textLeft = w - (textWidth + textRight) else: textLeft = (w / 2) - (textWidth / 2) textRight = textLeft + textWidth c1 = self.canvas1 c1coords = c1.coords c1.place(x=0, y=0, anchor='nw', width=w, height=bw) self.label.place(x=textLeft, y=0, anchor='nw') e1, e2, e3 = self.canvasL c1coords(e1, pad, pad, textLeft - pad + 3, pad + 3) c1coords(e2, pad + 1, pad + 1, textLeft - pad + 3, pad + 3) c1coords(e3, pad + 1, pad + 1, textLeft - pad + 2, pad + 2) e1, e2, e3 = self.canvasR c1coords(e1, textRight + pad, pad, w - pad + 3, pad + 3) c1coords(e2, textRight + pad + 1, pad + 1, w - pad + 3, pad + 3) c1coords(e3, textRight + pad + 1, pad + 1, w - pad + 2, pad + 2)
class ProgressBar(BasePopup): def __init__(self, parent, text='', progress=0, total=100, title=None, width=200, height=15, transient=True, *args, **kw): self.progress = float(progress) self.cWidth = width self.cHeight = height self.total = float(total) or 1.0 self.text = text BasePopup.__init__(self, parent=parent, title=title or 'Progress Bar', transient=transient, *args, **kw) def body(self, parent): self.bw = 2 # borderwidth width = self.cWidth + self.bw height = self.cHeight + self.bw self.label = Label(parent, text=self.text) self.label.grid(row=0, column=0, sticky=Tkinter.W) self.percent = Label(parent, text=' %') self.percent.grid(row=0, column=2, sticky=Tkinter.W) self.canvas = Canvas(parent, background='grey70', width=width, height=height) self.canvas.grid(row=0, column=1, sticky=Tkinter.W) self.canvas.create_rectangle(0, 0, width, height, outline='black', width=self.bw) self.bar = self.canvas.create_rectangle(self.bw, self.bw, self.bw, self.cHeight, outline='#B05848', fill='#B05848', width=self.bw) self.update() def update(self): p = self.progress / self.total width = int(self.cWidth * p) self.canvas.coords(self.bar, self.bw, self.bw, width, self.cHeight) self.percent.set(' %3.1d' % int(100 * p) + "%") self.label.set(self.text) self.update_idletasks() if self.progress == self.total: time.sleep(0.1) self.close() def increment(self, n=1): p = self.progress + n self.progress = max(min(self.total, p), 0) self.update() def get(self): return self.progress / self.total def set(self, value): if value <= 1: self.progress = float(value) * self.total elif value <= self.total: self.progress = float(value) else: raise 'Cannot set to a value exceeding the total' self.update() def setText(self, text=''): self.text = text self.label.set(self.text)
class ScrolledCanvas(Frame): def __init__(self, parent, resizeCallback=None, width=600, height=600, *args, **kw): self.bbox = None self.busy = 0 self.initialX = None self.initialY = None self.resizeCallback = resizeCallback apply(Frame.__init__, (self, parent) + args, kw) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.menu = Menu(self, tearoff=0, include_event=True) self.configMenu() self.canvas = Canvas(self, relief='flat', borderwidth=0, width=width, height=height) self.canvas.configure(xscrollincrement=2, yscrollincrement=2) self.canvas.grid(row=0, column=0, sticky=Tkinter.NSEW) self.horizScrollbar = Tkinter.Scrollbar(self, bg=self.cget('bg'), command=self.canvas.xview, orient=Tkinter.HORIZONTAL, borderwidth=1) self.vertScrollbar = Tkinter.Scrollbar(self, bg=self.cget('bg'), command=self.canvas.yview, orient=Tkinter.VERTICAL, borderwidth=1) self.canvas.configure(xscrollcommand=self.horizScrollbar.set, yscrollcommand=self.vertScrollbar.set) self.canvas.bind('<Configure>', self.resizeAfter) self.canvas.bind('<Button-1>', self.mouseButton1) self.canvas.bind('<Button-2>', self.mouseButton2) self.canvas.bind('<Button-3>', self.mouseButton3) self.canvas.bind('<ButtonRelease-1>', self.mouseButtonRelease1) self.canvas.bind('<ButtonRelease-2>', self.mouseButtonRelease2) self.canvas.bind('<B2-Motion>', self.mouseScroll) self.canvas.bind('<B3-Motion>', self.doNothing) self.canvas.bind('<Motion>', self.mouseEnter) self.canvas.bind('<Enter>', self.mouseEnter) def doNothing(self, event): pass def mouseEnter(self, event): if self.menu.winfo_ismapped(): self.removeMenu() def refresh(self): self.bbox = self.canvas.bbox('all') bbox = self.bbox if not bbox: self.busy = 0 return cWidth = int(self.canvas.cget('width')) cHeight = int(self.canvas.cget('height')) if cHeight > bbox[3] - bbox[1]: self.vertScrollbar.grid_forget() else: self.vertScrollbar.grid(row=0, column=1, sticky=Tkinter.NS) if cWidth > bbox[2] - bbox[0]: self.horizScrollbar.grid_forget() else: self.horizScrollbar.grid(row=1, column=0, sticky=Tkinter.EW) x1 = bbox[0] y1 = bbox[1] x2 = max(bbox[0] + cWidth, bbox[2]) y2 = max(bbox[1] + cHeight, bbox[3]) self.canvas.configure(scrollregion=(x1, y1, x2, y2)) self.update_idletasks() self.busy = 0 def printCanvas(self, *event): 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.bbox = bbox = self.canvas.bbox('all') w = bbox[2] - bbox[0] h = bbox[3] - bbox[1] self.canvas.postscript(colormode='color', file=fileName, x=bbox[0], y=bbox[1], width=w + 2, pagewidth='21.c', height=h + 2) def configMenu(self): items = [ { 'kind': 'command', 'label': 'Print to file', 'command': self.printCanvas }, ] self.menu.setMenuItems(items) def removeMenu(self, *event): self.menu.unpost() def mouseButton3(self, event): self.menu.popupMenu(event) def mouseButton1(self, event): self.removeMenu() if not self.initialX: self.initialX = event.x self.initialY = event.y def mouseButton2(self, event): self.removeMenu() if not self.initialX: self.initialX = event.x self.initialY = event.y self.initialPX = self.horizScrollbar.get()[0] self.initialPY = self.vertScrollbar.get()[0] def mouseButtonRelease1(self, event): self.initialX = None self.initialY = None def mouseButtonRelease2(self, event): self.initialX = None self.initialY = None self.initialPX = None self.initialPY = None def mouseScroll(self, event): self.menu.unpost() bbox = self.bbox if not bbox: return bW = float(bbox[2] - bbox[0]) bH = float(bbox[3] - bbox[1]) cWidth = int(self.canvas.cget('width')) cHeight = int(self.canvas.cget('height')) if cWidth < bW: dx = self.initialX - event.x prop = self.initialPX + (dx / bW) self.canvas.xview('moveto', prop) if cHeight < bH: dy = self.initialY - event.y prop = self.initialPY + (dy / bH) self.canvas.yview('moveto', prop) def resizeAfter(self, event): if self.busy: return else: self.busy = 1 self.removeMenu() self.after_idle(lambda: self.resize(event)) def resize(self, event): if self.resizeCallback: self.after_idle( lambda: self.resizeCallback(event.width, event.height)) self.canvas.configure(width=event.width, height=event.height) self.after_idle(self.refresh)
def __init__(self, parent, # arguments below are Tkinter.Scrollbar options orient = Tkinter.HORIZONTAL, width = 15, borderwidth = 1, background = None, troughcolor = None, repeatdelay = 300, # msecs before repeat action on arrows and troughs repeatinterval = 100, # msecs between repeat action on arrows and troughs # arguments below are not Tkinter.Scrollbar options # callback is approximately same as Tkinter.Scrollbar command # option but has different (more convenient) arguments allow_resize = False, callback = None, relief='sunken', show_text = False, text_color = '#000000', text_func = None, units_scroll = 0.1, pages_scroll = 1.0, min_thickness = None, *args, **kw): assert orient in (Tkinter.HORIZONTAL, Tkinter.VERTICAL) if (show_text): assert text_func is not None self.relief = relief self.orient = orient self.callback = callback self.borderwidth = borderwidth self.repeatdelay = repeatdelay self.repeatinterval = repeatinterval self.show_text = show_text self.text_func = text_func self.units_scroll = units_scroll self.pages_scroll = pages_scroll self.min_thickness = min_thickness self.mode = 0 self.lo = 0.0 self.hi = 1.0 self.first_pass = True Frame.__init__(self, parent, *args, **kw) if (background is None): bg = parent.cget('bg') else: bg = background if (troughcolor is None): bg_trough = scaleColor(self, bg, 0.9) else: bg_trough = troughcolor # below are for shadows if relief == 'sunken': color1 = scaleColor(self, bg_trough, 0.7) color2 = scaleColor(self, bg_trough, 1.2) color3 = scaleColor(self, bg, 1.2) color4 = scaleColor(self, bg, 0.7) elif relief == 'raised': color1 = scaleColor(self, bg_trough, 1.2) color2 = scaleColor(self, bg_trough, 0.7) color3 = scaleColor(self, bg, 0.7) color4 = scaleColor(self, bg, 1.2) else: color1 = color2 = scaleColor(self, bg_trough, 0.7) color3 = color4 = scaleColor(self, bg, 1.2) self.brColor = color4 self.tlColor = color3 defaultSize = 10 # gets overriden by other widgets in container # but need to do something otherwise canvas asks for too much space kw2 = {} if (orient == Tkinter.HORIZONTAL): kw2['width'] = defaultSize kw2['height'] = width else: kw2['width'] = width kw2['height'] = defaultSize self.canvas = c = Canvas(self, bg=bg, **kw2) # grid does not seem to work because once canvas size specified # in any way it never seems to be resized c.pack(side=Tkinter.TOP, expand=Tkinter.YES, fill=Tkinter.BOTH) self.tlOuter = c.create_polygon(0, 0, 0, 0, 0, 0,0, 0,fill=color1, outline='') self.brOuter = c.create_polygon(0, 0, 0, 0, 0, 0,0, 0,fill=color2, outline='') self.bgOuter = c.create_rectangle(0, 0, 0, 0, fill=bg_trough, outline='') # self.arrowXTl,Br are for shadows of the arrows # self.arrowXFill is for triangle infill # arrow and rectangle boundaries which are colored the # same as (and so in some sense are part of) the trough # the main part of the arrow does not need its own polygon # because it is the same color as the main rectangle self.arrow1Tl = c.create_polygon(0, 0, 0, 0, 0, 0, 0, 0, fill=color3, outline='') self.arrow1Br = c.create_polygon(0, 0, 0, 0, 0, 0, 0, 0, fill=color4, outline='') self.arrow1Fill = c.create_polygon(0, 0, 0, 0, 0, 0, fill=bg, outline='') self.arrow2Tl = c.create_polygon(0, 0, 0, 0, 0, 0, 0, 0, fill=color3, outline='') self.arrow2Br = c.create_polygon(0, 0, 0, 0, 0, 0, 0, 0, fill=color4, outline='') self.arrow2Fill = c.create_polygon(0, 0, 0, 0, 0, 0, fill=bg, outline='') # slider is the bit you grab in the middle # created with two triangles for the shadowsed border # with rectangle panel in middle self.tlSlider = c.create_polygon(0, 0, 0, 0, 0, 0,fill=color3, outline='') self.brSlider = c.create_polygon(0, 0, 0, 0, 0, 0,fill=color4, outline='') self.bgSlider = c.create_rectangle(0, 0, 0, 0, fill=bg, outline='') if (show_text): self.text0 = c.create_text(0, 0, fill=text_color) self.text1 = c.create_text(0, 0, fill=text_color) if (orient == Tkinter.HORIZONTAL): c.itemconfig(self.text0, anchor=Tkinter.W) c.itemconfig(self.text1, anchor=Tkinter.E) else: c.itemconfig(self.text0, anchor=Tkinter.S) c.itemconfig(self.text1, anchor=Tkinter.N) c.bind('<Configure>', self.configure) c.bind('<Button-1>', self.buttonPressMove) c.bind('<B1-Motion>', self.buttonMotionMove) c.bind('<ButtonRelease-1>', self.buttonReleaseMove) if (allow_resize): c.bind('<Button-2>', self.buttonPressResize) c.bind('<B2-Motion>', self.resize)
class PulldownList(Frame): # if using indentation then should use list as stack only # in other words only delete or insert at end # There is a 1:1 correspondance between the ordered lists of texts and # list of objects # categories is the category name for each text/object # objects with the same category will go under a submenu # of that name def __init__(self, parent, callback=None, texts=None, objects=None, categories=None, colors=None, index=0, prefix='', indent='', initCallback=False, forceCallback=False, numbering=False, arrowLine='#602000', arrowFill='#B05848', labelColor='#501000', menuBg='#F0F0FF', sticky='w', *args, **kw): Frame.__init__(self, parent, sticky=sticky, *args, **kw) self.callback = callback self.texts = texts or [] self.objects = objects or [] self.categories = categories or [] self.colors = colors or [] self.prefix = prefix self.indent = indent self.initCallback = initCallback self.numbering = numbering self.arrowLine = arrowLine self.arrowFill = arrowFill self.labelColor = labelColor # Current selection self.index = None self.object = NullText self.rows = [] self.bg = self.cget('bg') self.label = Label(self, foreground=labelColor) self.canvas = Canvas(self, width=12, height=12, background=self.bg) self.menu = Menu(self.canvas, tearoff=False, bg=menuBg, relief='solid', borderwidth=1, activeborderwidth=1) self.menu.images = [] # Photoimage has to remain referenced self.setup(self.texts, self.objects, index, self.colors, self.categories) self.label.bind("<Button-1>", self._labelClick) self.menu.bind("<Leave>", self._leave) self.canvas.bind("<Button-1>", self._canvasClick) self.canvas.bind("<Configure>", self._resizeCallback) self.grid_columnconfigure(0, weight=1) self.label.grid(row=0, column=0, sticky='w') self.canvas.grid(row=0, column=1, sticky='w', padx=2) # # Retrieval # def get(self): return (self.getText(), self.getObject()) def getSelected(self): return self.get() def getObject(self): return self._fetch(self.index, self.objects) def getText(self): return self._fetch(self.index, self.texts) def getSelectedIndex(self): return self.index # # Setting selected # def set(self, item): # Works with an object or a text index = None if item in self.texts: index = list(self.texts).index(item) elif item in self.objects: index = list(self.objects).index(item) if index is not None: self.setIndex(index) def setSelected(self, item): self.set(item) def setIndex(self, index, doCallback=False): self.index = index if self.objects: obj = self.objects[index] if obj is not self.object: self.object = obj if (doCallback or self.initCallback) and self.texts and self.callback: self.callback(obj) self._updateLabel() # # Bulk configuration # def clear(self): self.setup([], [], 0) def setup(self, texts, objects, index, colors=None, categories=None): self.texts = texts nTexts = len(texts) if not objects: objects = texts while len(objects) < nTexts: objects.append(None) self.objects = objects if colors is None: self.colors = [None] * nTexts else: while len(colors) < nTexts: colors.append(None) self.colors = colors if categories is None: self.categories = [None] * nTexts else: while len(categories) < nTexts: categories.append(None) self.categories = categories self._setMenuItems() self.setIndex(index or 0) # # In-place/minor configuration # def insert(self, index, text, object=None, color=None, category=None, select=False): index = max(0, min(len(self.texts), index)) self.texts.insert(index, text) self.objects.insert(index, object) self.colors.insert(index, color) self.categories.insert(index, category) self._setMenuItems() if select: self.setIndex(index) def append(self, text, object=None, color=None, category=None, select=False): self.insert(len(self.texts), text, object=None, color=None, category=None, select=False) def delete(self, index, howMany=1): if index < 0: return elif index >= len(self.texts): return end = min(index + howMany, len(self.texts)) self._clearMenu() del self.texts[index:end] del self.objects[index:end] del self.colors[index:end] del self.categories[index:end] self._setMenuItems() index = min(len(self.texts) - 1, self.index) self.setIndex(index) # # Internal methods # def _leave(self, event): x = event.x y = event.y x1 = self.menu.winfo_width() y1 = self.menu.winfo_height() if (x < 0) or (y < 0) or (x >= x1) or (y >= y1): self._popdown() def _resizeCallback(self, *event): c = self.canvas w = c.winfo_width() - 1 h = c.winfo_height() - 1 c.delete('all') c.create_rectangle(0, 0, 10, 2, fill=self.arrowFill, outline=self.arrowLine) c.create_polygon(0, 4, 0, 6, 5, 11, 10, 6, 10, 4, fill=self.arrowFill, outline=self.arrowLine) def _fetch(self, index, array): if index is None: return None if index < 0: index += len(array) if index < 0: return None elif index >= len(array): return None else: return array[index] def _setMenuItems(self): self._clearMenu() self.menu.images = [] # Clear photoimages if not self.texts and not self.menu.entrycget(1, 'label'): item = {'kind': 'command', 'label': NullText, 'command': None} self.menu.addMenuItem(item) self.rows = [0] return topList = [] categoryDict = {} for i in range(len(self.texts)): text = self.texts[i] color = self.colors[i] category = self.categories[i] if category: if categoryDict.get(category) is None: categoryDict[category] = [] topList.append((None, category, None, category)) categoryDict[category].append((i, text, color)) else: topList.append((i, text, color, None)) row = 0 for index, text, color, cat in topList: columnbreak = 0 if row and row % 20 == 0: columnbreak = 1 if cat: string = (self.indent * row) + self.prefix + text items = [] rowB = 0 for index2, text2, color2 in categoryDict.get(cat, []): columnbreakB = 0 if rowB and rowB % 20 == 0: columnbreakB = 1 if self.numbering: number = '%d%. ' % (index2 + 1) else: number = '' string2 = number + self.prefix + text2 command = lambda n=index2: self.setIndex(n, True) if color2: image = self._makeColorTile(color2) item2 = { 'kind': 'command', 'accelerator': string2, 'command': command, 'image': image, 'columnbreak': columnbreakB } else: item2 = { 'kind': 'command', 'label': string2, 'command': command, 'columnbreak': columnbreakB } items.append(item2) self.rows.append(row) rowB += 1 item = { 'kind': 'cascade', 'label': string, 'submenu': items, 'columnbreak': columnbreak } else: if self.numbering: number = '%d%. ' % (index + 1) else: number = '' string = (self.indent * row) + number + self.prefix + text command = lambda n=index: self.setIndex(n, True) if color: image = self._makeColorTile(color) item = { 'kind': 'command', 'accelerator': string, 'command': command, 'image': image, 'columnbreak': columnbreak } else: item = { 'kind': 'command', 'label': string, 'command': command, 'columnbreak': columnbreak } self.menu.addMenuItem(item) self.rows.append(row) row += 1 def _clearMenu(self): self.menu.delete(0, 'end') self.index = 0 self.rows = [] def _popdown(self, *event): self.menu.unpost() def _labelClick(self, event): s = self.rows[self.index] #x = event.x_root - event.x + 2 + self.label.winfo_width() x = event.x_root - 2 y = event.y_root - event.y - max(0, s) * (self.label.winfo_height() + 1) self.menu.post(x, y) def _canvasClick(self, event): s = self.rows[self.index] x = event.x_root - event.x + 2 y = event.y_root - event.y - max(0, s) * (self.label.winfo_height() + 1) self.menu.post(x, y) def _updateLabel(self): if self.texts: text = self.texts[self.index] or NullText else: text = NullText self.label.set(text=text) def _makeColorTile(self, color): image = Tkinter.PhotoImage() self.menu.images.append(image) if type(color) == type([]): colors = [scaleColor(self.menu, c, 1.0) for c in color] else: colors = [ scaleColor(self.menu, color, 1.0), ] cols = max(8, len(colors)) for x in range(cols): i = x % len(colors) c = colors[i] for y in range(16): image.put('{%s %s}' % (c, c), to=(2 * x, y)) return image
def __init__(self, parent, scrollX=True, scrollY=True, *args, **kw): self.parent = parent self.scrollX = scrollX self.scrollY = scrollY self.prototypes = [] self.nodes = [] self.node = None # Selected self.links = [] self.link = None # Selected self.objDict = {} # Map canvas to nodes, links self.cornerDict = {} self.editWidget = None self.mouseOver = None self.inMotion = None self.inMotion2 = None self.inMotion3 = None self.dragRegion = None self._resizeBusy = False self.selectedNodes = [] self.selectedLinks = [] self.highlightNodes = [] self.highlightLinks = [] kw['relief'] = 'flat' kw['borderwidth'] = 0 Frame.__init__(self, parent, *args, **kw) self.canvas = canvas = Canvas(self, relief='flat', borderwidth=0) self.canvas.configure(xscrollincrement=2, yscrollincrement=2, bg=self.cget('bg')) self.canvas.grid(row=0, column=0, sticky='nsew') if scrollX: self.horizScrollbar = Tkinter.Scrollbar(self, bg=self.cget('bg'), command=self.canvas.xview, orient=Tkinter.HORIZONTAL, borderwidth=1) self.canvas.configure(xscrollcommand=self.horizScrollbar.set) if scrollY: self.vertScrollbar = Tkinter.Scrollbar(self, bg=self.cget('bg'), command=self.canvas.yview, orient=Tkinter.VERTICAL, borderwidth=1) self.canvas.configure(yscrollcommand=self.vertScrollbar.set) canvas.bind('<Button-1>', self._mouseSingleClick) if not isWindowsOS(): canvas.bind('<Button-4>', self.scrollUp) canvas.bind('<Button-5>', self.scrollDown) else: canvas.bind('<MouseWheel>', self._windowsOsScroll) canvas.bind('<Double-1>', self._mouseDoubleClick) canvas.bind('<B1-Motion>', self._mouseDrag) canvas.bind('<ButtonRelease-1>', self._mouseRelease) canvas.bind('<Motion>', self._mouseEnter) canvas.bind('<Enter>', self._mouseEnter) canvas.bind('<Leave>', self._mouseLeave) canvas.bind('<KeyPress-Up>', self._moveUp) canvas.bind('<KeyPress-Down>', self._moveDown) canvas.bind('<KeyPress-Right>', self._moveRight) canvas.bind('<KeyPress-Left>', self._moveLeft) canvas.bind('<KeyPress-Delete>', self.deleteSelected) self.bind('<Configure>', self._resizeAfter) self.menu = Menu(self, tearoff=False) alignItems = [{ 'kind': 'command', 'label': 'Y axis', 'command': self._alignHorizontal }, { 'kind': 'command', 'label': 'X axis', 'command': self._alignVertical }] distributeItems = [{ 'kind': 'command', 'label': 'Horizontal', 'command': self._distributeHorizontal }, { 'kind': 'command', 'label': 'Verical', 'command': self._distributeVertical }] menuItems = [ { 'kind': 'cascade', 'label': 'Align', 'submenu': alignItems }, #0 { 'kind': 'cascade', 'label': 'Distribute', 'submenu': distributeItems }, #1 { 'kind': 'command', 'label': 'Link Selected', 'command': self.linkSelected }, #2 { 'kind': 'command', 'label': 'Reset Links', 'command': self._resetLinks }, #3 { 'kind': 'separator' }, { 'kind': 'command', 'label': 'Delete Links', #5 'command': self.deleteLinks }, { 'kind': 'command', 'label': 'Delete Items', #6 'command': self.deleteNodes }, { 'kind': 'separator' }, { 'kind': 'command', 'label': 'Save PostScript File', 'command': self.printCanvas }, ] self.menuItems = menuItems self.menu.setMenuItems(menuItems) canvas.bind('<ButtonPress-3>', self._popupMenu) self._drawAfter()
def __init__(self, parent, numButtons, state=None, orient='h', background=None, selectColor='#C0C0FF', size=15, callback=None, label=None, grid=None, *args, **kw): self.numButtons = numButtons self.orient = orient self.selectColor = selectColor self.size = size self.callback = callback self.state = state or [False] * numButtons self.canvasDict = {} self.canvasNums = {} self.initialN = None self.initialS = None if (background is None): self.bg = parent.cget('bg') else: self.bg = background Frame.__init__(self, parent, grid=grid, *args, **kw) self.bgLight = scaleColor(self, self.bg, 1.5) self.bgDark = scaleColor(self, self.bg, 0.4) self.bgLight2 = scaleColor(self, self.bg, 1.2) self.bgDark2 = scaleColor(self, self.bg, 0.7) if label: self.label = Label(self, text=label, tipText=TOOL_TIP) self.label.grid(row=0, column=0, sticky=Tkinter.EW) if orient in (Tkinter.HORIZONTAL, 'horizontal', 'h'): c_row = 0 c_col = 1 else: c_row = 1 c_col = 0 else: self.label = None if orient in (Tkinter.HORIZONTAL, 'horizontal', 'h'): self.orient = 'h' self.canvas = c = Canvas(self, bg=self.bg, height=size) self.grid_columnconfigure(c_col, weight=1) else: self.orient = 'v' self.canvas = c = Canvas(self, bg=self.bg, width=size) self.grid_rowconfigure(c_row, weight=1) c.grid(row=c_row, column=c_col, sticky='nsew') c.bind('<Configure>', self.resizeCanvas) c.bind('<Button-1>', self.slideState) c.bind('<B1-Motion>', self.slideState) c.bind('<ButtonRelease-1>', self.slideStateDone) c.bind('<Button-2>', self.clickState) c.bind('<B2-Motion>', self.clickState) c.bind('<ButtonRelease-2>', self.clickStateDone)
class PulldownMenu(Frame): # if using indentation then should use list as stack only # in other words only delete or insert at end # entries entries must have attribute text_attr or if this is # None then assume that entries entries themselves provide name def __init__(self, parent, callback=None, entries=None, text_attr=None, colors=None, outline='#602000', fill='#B05848', label_color='#501000', selected_index=-1, indent='', extra='', sticky='w', do_initial_callback=True, force_callback=False, *args, **kw): if (entries is None): entries = [] Frame.__init__(self, parent, sticky=sticky, *args, **kw) self.text_attr = text_attr #indentation and extra string for popup information self.indent = indent self.extra = extra self.callback = callback self.do_initial_callback = do_initial_callback self.force_callback = force_callback frame = Frame(self) #frame = parent self.frame = frame self.bg = frame.cget('bg') self.outline = outline self.fill = fill self.label_color = label_color self.menu = Menu(parent, tearoff=0, borderwidth=1, activeborderwidth=1) self.menu.images = [] self.label = Label(self, foreground=label_color) self.first_pass = True #self.entries = entries self.entries = [] self.colors = [] self.setup(entries, selected_index, colors=colors) s = 10 self.canvas = Canvas(self, width=s, height=s, background=self.bg) self.label.bind("<Button-1>", self.labelPopup) # below does not work for some reason #self.bind("<Button-1>", self.labelPopup) # below does not work any more since can have submenus and # no way to reach those with below since involves leaving menu #self.menu.bind("<Leave>", self.popdown) self.menu.bind("<Leave>", self.leave) self.menu.bind("<Button-1>", self.buttonPress) self.poppedUpSubmenu = False self.canvas.bind("<Button-1>", self.canvasPopup) self.canvas.bind("<Configure>", self.resizeCallback) self.label.grid(row=0, column=0, sticky=Tkinter.W) self.canvas.grid(row=0, column=1, sticky=Tkinter.E, padx=2) def leave(self, event): if (not self.poppedUpSubmenu): x = event.x y = event.y x1 = self.menu.winfo_width() y1 = self.menu.winfo_height() if (x < 0) or (y < 0) or (x >= x1) or (y >= y1): self.popdown() def buttonPress(self, event): if (event.widget != self.menu): return for n in range(len(self.entries) - 1, -1, -1): if event.y >= self.menu.yposition(n): break else: return item = self.entries[n] if (isinstance(item, {}.__class__) and item['kind'] == 'cascade'): self.poppedUpSubmenu = True else: self.poppedUpSubmenu = False def resizeCallback(self, *event): w = self.canvas.winfo_width() / 2 h = self.canvas.winfo_height() / 2 self.canvas.delete('all') self.canvas.create_polygon(1, 1, w, 2 * h - 1, 2 * w - 1, 1, fill=self.fill, outline=self.outline) def getEntry(self, entry_index, entries=None): if not entries: entries = self.entries if type(entry_index) == types.TupleType: e = entry_index[0] if len(entry_index) > 1: items = entries[e]['submenu'] entry = self.getEntry(entry_index[1:], items) else: entry = entries[e]['label'] elif (entry_index >= 0): entry = entries[entry_index] else: entry = None return entry def getEntryText(self, entry_index, entries=None): if not entries: entries = self.entries if type(entry_index) in (types.TupleType, types.ListType): e = entry_index[0] if len(entry_index) > 1: items = entries[e]['submenu'] text = self.getEntryText(entry_index[1:], items) else: text = entries[e]['label'] elif (entry_index != -1): #print 'getEntryText', entry_index, entries entry = entries[entry_index] if (self.text_attr): text = getattr(entry, self.text_attr) else: text = entry else: text = '' # TBD: for now text returned should not be unicode text = str(text) # below did not work for one person (Chinese characters??) but above did ###text = text.encode('utf-8') return text def setup(self, entries, selected_index, first_pass=True, colors=None): #print 'setup', entries, selected_index if first_pass is not None: self.first_pass = first_pass self.clearMenuItems() if (entries): e = list(entries) else: e = [No_entries_label] self.entries = e self.colors = colors or [None] * len(e) if type(selected_index) in (types.TupleType, types.ListType): if (not selected_index or selected_index[0] >= len(entries)): selected_index = -1 else: if (selected_index >= len(entries)): selected_index = -1 if (selected_index == -1): selected_index = 0 self.selected_index = -1 # changed in setSelectedIndex() self.setMenuItems() self.setSelectedIndex(selected_index) def substituteCascadeCallbacks(self, item, selected_index): if (item['kind'] == 'cascade'): n = 0 for subitem in item['submenu']: self.substituteCascadeCallbacks(subitem, selected_index + [n]) n = n + 1 else: callback = item.get('command') if (callback): label = item['label'] item['command'] = lambda: self.cascadeCallback( callback, label, tuple(selected_index)) def cascadeCallback(self, callback, label, selected_index): self.selected_index = selected_index self.setLabel(selected_index) callback(selected_index, label) def setMenuItems(self): self.menu.images = [] for n in range(len(self.entries)): columnbreak = 0 if n and n % 20 == 0: columnbreak = 1 item = self.entries[n] color = None if n < len(self.colors): color = self.colors[n] if isinstance(item, {}.__class__): if (item['kind'] == 'cascade'): self.substituteCascadeCallbacks(item, [n]) else: t = (self.indent * n) + self.extra + str(self.getEntryText(n)) command = lambda n=n: self.setSelectedIndex(n) if color: image = self.makeColorTile(color) item = { 'kind': 'command', 'accelerator': t, 'command': command, 'image': image, 'columnbreak': columnbreak } else: item = { 'kind': 'command', 'label': t, 'command': command, 'columnbreak': columnbreak } self.menu.addMenuItem(item) def clearMenuItems(self): if self.entries: self.menu.delete(0, len(self.entries)) # below assumes entry_index is integer not tuple def insert(self, entry_index, entry, make_selected=False, color=None): if (self.haveNoEntries()): if (entry_index != 0): return elif ((entry_index < 0) or (entry_index >= len(self.entries))): return self.clearMenuItems() self.checkForNone() self.entries.insert(entry_index, entry) self.colors.insert(entry_index, color) self.setMenuItems() if (make_selected or (self.selected_index == -1)): self.setSelectedIndex(entry_index, force_callback=True) else: self.setSelectedIndex(self.selected_index) # below assumes entry is integer not tuple def append(self, entry, make_selected=False, color=None): self.clearMenuItems() self.checkForNone() self.entries.append(entry) self.colors.append(color) self.setMenuItems() if (make_selected or (self.selected_index == -1)): self.setSelectedIndex(len(self.entries) - 1, force_callback=True) else: self.setSelectedIndex(self.selected_index) def checkForNone(self): if (self.haveNoEntries()): self.entries = [] self.colors = [] self.menu.delete(0) def haveNoEntries(self): if (len(self.entries) == 1 and self.entries[0] == No_entries_label): return True else: return False def baseIndex(self, ind): if type(ind) == types.TupleType: ind = ind[0] return ind # below assumes entry_index is integer not tuple def delete(self, entry_index, n=1): if (self.haveNoEntries()): return if ((entry_index < 0) or (entry_index >= len(self.entries))): return self.clearMenuItems() n1 = entry_index n2 = n1 + n m = self.baseIndex(self.selected_index) del self.entries[n1:n2] del self.colors[n1:n2] if (not self.entries): self.entries = [No_entries_label] self.colors = [None] self.setMenuItems() if ((m >= n1) and (m < n2)): if (n1 == 0): selected_index = 0 else: selected_index = n1 - 1 self.setSelectedIndex(selected_index, force_callback=True) def replace(self, entries, selected_index=-1, colors=None): self.menu.delete(0, len(self.entries)) self.setup(entries, selected_index, first_pass=False, colors=colors) def popdown(self, *event): self.menu.unpost() def setLabel(self, selected_index): text = self.getEntryText(selected_index) if (not text): text = self.extra # arbitrary self.label.set(text=text) def labelPopup(self, event): self.poppedUpSubmenu = False s = self.baseIndex(self.selected_index) x = event.x_root - event.x + 2 y = event.y_root - event.y - \ max(0, s) * (self.label.winfo_height() + 1) self.menu.post(x, y) def canvasPopup(self, event): s = self.baseIndex(self.selected_index) x = event.x_root - event.x - self.label.winfo_width() + 2 y = event.y_root - event.y - \ max(0, s) * (self.label.winfo_height() + 1) + \ self.canvas.winfo_height() - self.label.winfo_height() self.menu.post(x, y) def getSelectedIndex(self): return self.selected_index def setSelectedIndex(self, selected_index, force_callback=False): if (force_callback or self.force_callback or \ (selected_index != self.selected_index)): #print 'setSelectedIndex', self.entries, selected_index, self.selected_index, self.first_pass self.selected_index = selected_index self.setLabel(selected_index) if (self.callback): if (self.haveNoEntries()): if (not self.first_pass): self.callback(-1, None) elif (selected_index != -1): if (not self.first_pass or self.do_initial_callback): self.callback(selected_index, self.entries[selected_index]) self.first_pass = False def get(self): return self.getSelected() def getSelected(self): ind = self.getSelectedIndex() if (ind == -1): return None else: return self.getEntry(ind) def set(self, selected): self.setSelected(selected) def findEntryIndex(self, entry, entries=None): #print 'findEntryIndex1', entry, entries if (entries): noEntries = True else: noEntries = False entries = self.entries try: ind = entries.index(entry) return ind except: pass #print 'findEntryIndex2', entry, entries for n in range(len(entries)): e = entries[n] #print 'findEntryIndex3', entry, e if e == entry: if noEntries: return [n] else: return n elif type(e) == types.DictType: if (len(entries) > 1): try: ind = self.findEntryIndex(entry, e['submenu']) return [n] + ind except: pass else: if (entry == e['label']): return [n] raise 'unknown entry "%s"' % entry # selects first item found in entries which matches def setSelected(self, selected): #print 'setSelected1', selected, type(selected), self.entries try: selected_index = self.findEntryIndex(selected) except: #selected_index = -1 return #print 'setSelected2', selected_index self.setSelectedIndex(selected_index) def makeColorTile(self, color): image = Tkinter.PhotoImage() self.menu.images.append(image) if type(color) == type([]): colors = [scaleColor(self.menu, c, 1.0) for c in color] else: colors = [ scaleColor(self.menu, color, 1.0), ] cols = max(8, len(colors)) for x in range(cols): i = x % len(colors) c = colors[i] for y in range(16): image.put('{%s %s}' % (c, c), to=(2 * x, y)) return image
def __init__(self, parent, callback=None, entries=None, text_attr=None, colors=None, outline='#602000', fill='#B05848', label_color='#501000', selected_index=-1, indent='', extra='', sticky='w', do_initial_callback=True, force_callback=False, *args, **kw): if (entries is None): entries = [] Frame.__init__(self, parent, sticky=sticky, *args, **kw) self.text_attr = text_attr #indentation and extra string for popup information self.indent = indent self.extra = extra self.callback = callback self.do_initial_callback = do_initial_callback self.force_callback = force_callback frame = Frame(self) #frame = parent self.frame = frame self.bg = frame.cget('bg') self.outline = outline self.fill = fill self.label_color = label_color self.menu = Menu(parent, tearoff=0, borderwidth=1, activeborderwidth=1) self.menu.images = [] self.label = Label(self, foreground=label_color) self.first_pass = True #self.entries = entries self.entries = [] self.colors = [] self.setup(entries, selected_index, colors=colors) s = 10 self.canvas = Canvas(self, width=s, height=s, background=self.bg) self.label.bind("<Button-1>", self.labelPopup) # below does not work for some reason #self.bind("<Button-1>", self.labelPopup) # below does not work any more since can have submenus and # no way to reach those with below since involves leaving menu #self.menu.bind("<Leave>", self.popdown) self.menu.bind("<Leave>", self.leave) self.menu.bind("<Button-1>", self.buttonPress) self.poppedUpSubmenu = False self.canvas.bind("<Button-1>", self.canvasPopup) self.canvas.bind("<Configure>", self.resizeCallback) self.label.grid(row=0, column=0, sticky=Tkinter.W) self.canvas.grid(row=0, column=1, sticky=Tkinter.E, padx=2)
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)