def processArrowKey(self, evt): direction = evt.keysym if self.type is None: return elif self.type == "text": self.window.entryIcon.arrowAction(direction) return elif self.type == "typeover": self.erase() if direction in ("Up", "Down"): fromIcon = self.icon fromSite = fromIcon.sites.lastCursorSite() toIcon, toSite = self._geometricTraverse( fromIcon, fromSite, direction) self.moveToIconSite(toIcon, toSite, evt) siteBefore, siteAfter, text, idx = self.icon.typeoverSites() if direction == 'Right': # Move to site after (typeover will be automatically cancelled) self.setToIconSite(self.icon, siteAfter) if direction == 'Left': # reset typeover and move to previous site self.icon.setTypeover(0, siteAfter) self.icon.draw() self.window.refresh(self.icon.rect, redraw=False, clear=False) siteBeforeIcon = self.icon.childAt(siteBefore) if siteBeforeIcon is None: toIcon, toSite = self.icon, siteBefore else: toIcon, toSite = icon.rightmostSite(siteBeforeIcon) self.moveToIconSite(toIcon, toSite, evt) return if self.type == "window": x, y = self.pos directions = { "Up": (0, -1), "Down": (0, 1), "Left": (-1, 0), "Right": (1, 0) } xOff, yOff = directions[direction] x += xOff * WINDOW_CURSOR_INCREMENT y += yOff * WINDOW_CURSOR_INCREMENT windowWidth, windowHeight = self.window.image.size if WINDOW_CURSOR_MARGIN < x < windowWidth - WINDOW_CURSOR_MARGIN and \ WINDOW_CURSOR_MARGIN < y < windowHeight - WINDOW_CURSOR_MARGIN: self.erase() self.pos = x, y self.draw() return elif self.type == "icon": self._processIconArrowKey(evt)
def backspace(self, siteId, evt): redrawRect = self.topLevelParent().hierRect() parent = self.parent() leftArg = self.leftArg() rightArg = self.rightArg() op = self.operator win = self.window if parent is None and leftArg is None: entryAttachedIcon, entryAttachedSite = None, None elif parent is not None and leftArg is None: entryAttachedIcon = parent entryAttachedSite = parent.siteOf(self) else: # leftArg is not None, attach to that entryAttachedIcon, entryAttachedSite = icon.rightmostSite( icon.findLastAttrIcon(leftArg), ignoreAutoParens=True) win.entryIcon = entryicon.EntryIcon(initialString=op, window=win) if leftArg is not None: leftArg.replaceChild(None, 'output') if rightArg is not None: rightArg.replaceChild(None, 'output') win.entryIcon.setPendingArg(rightArg) if parent is None: if leftArg is None: win.replaceTop(self, win.entryIcon) else: win.replaceTop(self, leftArg) entryAttachedIcon.replaceChild(win.entryIcon, entryAttachedSite) else: parentSite = parent.siteOf(self) if leftArg is not None: parent.replaceChild(leftArg, parentSite) entryAttachedIcon.replaceChild(win.entryIcon, entryAttachedSite) self.replaceChild(None, 'leftArg') self.replaceChild(None, 'rightArg') win.cursor.setToEntryIcon() win.redisplayChangedEntryIcon(evt, redrawRect)
def _lexicalTraverse(self, fromIcon, fromSite, direction): """Return the cursor position (icon and siteId) to the left or right according to the "text-flow".""" fromSiteType = fromIcon.typeOf(fromSite) if direction == 'Left': if fromSiteType in iconsites.parentSiteTypes: # Cursor is on an output site. There's probably nowhere to go (return # the same cursor position). In the unlikely case that it is attached to # something, make a recursive call with the proper cursor site (input) attachedIc = fromIcon.childAt(fromSite) if attachedIc is None: return fromIcon, fromSite attachedSite = attachedIc.siteOf(fromIcon) return self._lexicalTraverse(attachedIc, attachedSite, direction) elif fromSite == 'seqOut': if isinstance(fromIcon, icon.BlockEnd): return fromIcon, "seqIn" return icon.rightmostSite(fromIcon) elif fromSite == 'seqIn': prevStmt = fromIcon.prevInSeq() if prevStmt is None: return fromIcon, fromSite if isinstance(prevStmt, icon.BlockEnd): return prevStmt, "seqIn" return icon.rightmostSite(prevStmt) # Cursor is on an input site of some sort (input, attrIn, cprhIn) prevSite = fromIcon.sites.prevCursorSite(fromSite) if prevSite is None: highestIc = iconsites.highestCoincidentIcon(fromIcon) parent = highestIc.parent() if parent is None: if highestIc.hasCoincidentSite(): return iconsites.lowestCoincidentSite( highestIc, highestIc.hasCoincidentSite()) return highestIc, self._topSite(highestIc, seqDown=False) parentSite = parent.siteOf(highestIc) if highestIc == fromIcon and fromIcon.hasCoincidentSite(): return self._lexicalTraverse(parent, parentSite, direction) return iconsites.lowestCoincidentSite(parent, parentSite) iconAtPrevSite = fromIcon.childAt(prevSite) if iconAtPrevSite is None: return fromIcon, prevSite return icon.rightmostSite(iconAtPrevSite) else: # 'Right' if fromSiteType in iconsites.parentSiteTypes or fromSiteType == 'seqIn': nextSite = fromIcon.sites.firstCursorSite() if nextSite is None: return fromIcon, self._topSite(fromIcon, seqDown=True) if fromSite == 'output' and nextSite == fromIcon.hasCoincidentSite( ): return self._lexicalTraverse(fromIcon, nextSite, direction) return fromIcon, nextSite if fromSite == 'seqOut': nextStmt = fromIcon.nextInSeq() if nextStmt is None: return fromIcon, fromSite nextSite = nextStmt.sites.firstCursorSite() if nextSite is None: return nextStmt, 'seqOut' return nextStmt, nextSite # Start from the lowest coincident site at the cursor ic, site = iconsites.lowestCoincidentSite(fromIcon, fromSite) childIc = ic.childAt(site) if childIc is not None: # There is an icon attached to it that can accept a cursor, go there firstChildSite = childIc.sites.firstCursorSite() if firstChildSite is not None: return childIc, firstChildSite # There is no icon attached to the site that can accept a cursor. Iterate up # the hierarchy to find an icon with a site to take one. If none is found, # attach to the seqOut or output site of the top icon nextSite = ic.sites.nextCursorSite(site) nextIcon = ic while nextSite is None or nextSite == nextIcon.hasCoincidentSite(): parent = nextIcon.parent() if parent is None: return nextIcon, self._topSite(nextIcon, seqDown=True) parentSite = parent.siteOf(nextIcon) nextSite = parent.sites.nextCursorSite(parentSite) nextIcon = parent return nextIcon, nextSite
def backspace(self, siteId, evt): win = self.window if siteId == 'indexIcon': # Cursor is on the index site. Try to remove brackets if self.hasSite('upperIcon') and self.childAt('upperIcon') or \ self.hasSite('stepIcon') and self.childAt('stepIcon') or \ self.hasSite('attrIcon') and self.childAt('attrIcon'): # Can't remove brackets: select the icon and its children win._select(self, op='hier') elif not self.childAt('indexIcon'): # Icon is empty, remove parent = self.parent() win.removeIcons([self]) if parent is not None: win.cursor.setToIconSite(parent, 'attrIcon') else: # Icon has a single argument and it's in the first slot: unwrap # the bracket from around it. redrawRegion = comn.AccumRects( self.topLevelParent().hierRect()) parent = self.parent() content = self.childAt('indexIcon') if parent is None: # The icon was on the top level: replace it with its content self.replaceChild(None, 'indexIcon') win.replaceTop(self, content) win.cursor.setToBestCoincidentSite(content, 'output') else: # The icon has a parent, but since the subscript icon sits on # an attribute site we can't attach, so create an entry icon # and make the content a pending argument to it. parentSite = parent.siteOf(self) win.entryIcon = entryicon.EntryIcon(parent, parentSite, window=win) parent.replaceChild(win.entryIcon, parentSite) win.entryIcon.setPendingArg(content) win.cursor.setToEntryIcon() win.redisplayChangedEntryIcon(evt, redrawRegion.get()) return redrawRegion.add( win.layoutDirtyIcons(filterRedundantParens=False)) win.refresh(redrawRegion.get()) return elif siteId == 'attrIcon': # The cursor is on the attr site, remove the end bracket redrawRegion = comn.AccumRects(self.topLevelParent().hierRect()) entryicon.reopenParen(self) redrawRegion.add(win.layoutDirtyIcons(filterRedundantParens=False)) win.refresh(redrawRegion.get()) return # Site is after a colon. Try to remove it redrawRegion = comn.AccumRects(self.topLevelParent().hierRect()) if siteId == 'upperIcon': # Remove first colon mergeSite1 = 'indexIcon' mergeSite2 = 'upperIcon' else: # Remove second colon mergeSite1 = 'upperIcon' mergeSite2 = 'stepIcon' mergeIcon1 = self.childAt(mergeSite1) mergeIcon2 = self.childAt(mergeSite2) if mergeIcon2 is None: # Site after colon is empty (no need to merge) cursorIc, cursorSite = icon.rightmostFromSite(self, mergeSite1) elif mergeIcon1 is None: # Site before colon is empty, move the icon after the colon to it self.replaceChild(None, mergeSite2) self.replaceChild(mergeIcon2, mergeSite1) cursorIc, cursorSite = self, mergeSite1 else: # Both sites are occupied merge the two expressions rightmostIc, rightmostSite = icon.rightmostSite(mergeIcon1) if rightmostIc.typeOf(rightmostSite) == 'input': # An empty input on the right allows merge without inserting entry icon self.replaceChild(None, mergeSite2) rightmostIc.replaceChild(mergeIcon2, rightmostSite) reorderexpr.reorderArithExpr(mergeIcon1) cursorIc, cursorSite = rightmostIc, rightmostSite else: lowestIc, lowestSite = iconsites.lowestCoincidentSite( self, mergeSite2) if lowestIc.childAt(lowestSite): # Can't merge the two expressions: insert an entry icon self.replaceChild(None, mergeSite2) win.entryIcon = entryicon.EntryIcon('', window=win) win.entryIcon.setPendingArg(mergeIcon2) rightmostIc.replaceChild(win.entryIcon, rightmostSite) cursorIc = cursorSite = None else: # Empty site right of colon, merge left side in to that and reorder self.replaceChild(None, mergeSite2) self.replaceChild(mergeIcon2, mergeSite1) lowestIc.replaceChild(mergeIcon1, lowestSite) reorderexpr.reorderArithExpr(lowestIc) cursorIc, cursorSite = rightmostIc, rightmostSite # If there is a step site that wasn't part of the merge, shift it. if self.hasSite('stepIcon') and mergeSite2 != 'stepIcon': moveIcon = self.childAt('stepIcon') self.replaceChild(moveIcon, 'upperIcon') # Remove the colon (colonectomy) if self.hasSite('stepIcon'): self.changeNumSubscripts(2) else: self.changeNumSubscripts(1) # Place the cursor or new entry icon, and redraw if win.entryIcon is None: win.cursor.setToIconSite(cursorIc, cursorSite) redrawRegion.add(win.layoutDirtyIcons()) win.refresh(redrawRegion.get()) else: win.cursor.setToEntryIcon() win.redisplayChangedEntryIcon(evt, redrawRegion.get())
def backspace(self, siteId, evt): siteName, index = iconsites.splitSeriesSiteId(siteId) win = self.window if siteName == "values" and index == 0: # Cursor is on first input site. Remove icon and replace with cursor text = self.op + '=' valueIcons = [ s.att for s in self.sites.values if s.att is not None ] targetIcon = self.childAt("targetIcon") if len(valueIcons) in (0, 1): # Zero or one argument, convert to entry icon (with pending arg if # there was an argument) attached to name icon redrawRegion = comn.AccumRects( self.topLevelParent().hierRect()) if self.parent() is not None: print('AugmentedAssign has parent?????') return if targetIcon is None: win.entryIcon = entryicon.EntryIcon(initialString=text, window=win) win.replaceTop(self, win.entryIcon) else: win.entryIcon = entryicon.EntryIcon(initialString=text, window=win) win.replaceTop(self, targetIcon) targetIcon.replaceChild(win.entryIcon, 'attrIcon') if len(valueIcons) == 1: win.entryIcon.setPendingArg(valueIcons[0]) else: # Multiple remaining arguments: convert to tuple with entry icon as # first element redrawRegion = comn.AccumRects( self.topLevelParent().hierRect()) valueIcons = [ s.att for s in self.sites.values if s.att is not None ] newTuple = listicons.TupleIcon(window=win, noParens=True) if targetIcon is None: win.entryIcon = entryicon.EntryIcon(initialString=text, window=win) newTuple.replaceChild(win.entryIcon, "argIcons_0") else: win.entryIcon = entryicon.EntryIcon(initialString=text, window=win) targetIcon.replaceChild(win.entryIcon, 'attrIcon') newTuple.replaceChild(targetIcon, 'argIcons_0') for i, arg in enumerate(valueIcons): if i == 0: win.entryIcon.setPendingArg(arg) else: self.replaceChild(None, self.siteOf(arg)) newTuple.insertChild(arg, "argIcons", i) win.replaceTop(self, newTuple) win.cursor.setToEntryIcon() win.redisplayChangedEntryIcon(evt, redrawRegion.get()) elif siteName == "values": # Cursor is on comma input. Delete if empty or previous site is empty prevSite = iconsites.makeSeriesSiteId(siteName, index - 1) childAtCursor = self.childAt(siteId) if childAtCursor and self.childAt(prevSite): cursors.beep() return topIcon = self.topLevelParent() redrawRegion = comn.AccumRects(topIcon.hierRect()) if not self.childAt(prevSite): self.removeEmptySeriesSite(prevSite) win.cursor.setToIconSite(self, prevSite) else: rightmostIcon = icon.findLastAttrIcon(self.childAt(prevSite)) rightmostIcon, rightmostSite = icon.rightmostSite( rightmostIcon) self.removeEmptySeriesSite(siteId) win.cursor.setToIconSite(rightmostIcon, rightmostSite) redrawRegion.add(win.layoutDirtyIcons(filterRedundantParens=False)) win.refresh(redrawRegion.get()) win.undo.addBoundary()