Exemplo n.º 1
0
 def backspace(self, siteId, evt):
     siteName, index = iconsites.splitSeriesSiteId(siteId)
     topIcon = self.topLevelParent()
     redrawRegion = comn.AccumRects(topIcon.hierRect())
     win = self.window
     if index == 0:
         if siteName == "targets0":
             return
         if siteName == "values" and not hasattr(self.sites, 'targets1'):
             # This is the only '=' in the assignment, convert it to a tuple
             argIcons = [tgtSite.att for tgtSite in self.sites.targets0]
             numTargets = len(argIcons)
             argIcons += [valueSite.att for valueSite in self.sites.values]
             newTuple = listicons.TupleIcon(window=win, noParens=True)
             for i, arg in enumerate(argIcons):
                 if arg is not None:
                     self.replaceChild(None, self.siteOf(arg))
                 newTuple.insertChild(arg, "argIcons", i)
             parent = self.parent()
             if parent is None:
                 win.replaceTop(self, newTuple)
             else:
                 # I don't think this is possible, remove if print never appears
                 print("Assign icon has parent?????")
                 parentSite = parent.siteOf(self)
                 parent.replaceChild(newTuple, parentSite)
             cursorSite = iconsites.makeSeriesSiteId('argIcons', numTargets)
             win.cursor.setToIconSite(newTuple, cursorSite)
         else:
             # Merge lists around '=' to convert it to ','
             #... This should do the same as backspaceComma and insert entry icon
             topIcon = self.topLevelParent()
             redrawRegion = comn.AccumRects(topIcon.hierRect())
             if siteName == "values":
                 removetgtGrpIdx = len(self.tgtLists) - 1
                 srcSite = "targets%d" % removetgtGrpIdx
                 destSite = "values"
                 destIdx = 0
                 cursorIdx = len(getattr(self.sites, srcSite)) - 1
             else:
                 srcSite = siteName
                 removetgtGrpIdx = int(siteName[7:])
                 destSite = siteName[:7] + str(removetgtGrpIdx - 1)
                 destIdx = len(getattr(self.sites, destSite))
                 cursorIdx = destIdx - 1
             argIcons = [s.att for s in getattr(self.sites, srcSite)]
             for i, arg in enumerate(argIcons):
                 self.replaceChild(None, self.siteOf(arg))
                 self.insertChild(arg, destSite, destIdx + i)
             self.removeTargetGroup(removetgtGrpIdx)
             cursorSite = iconsites.makeSeriesSiteId(destSite, cursorIdx)
             win.cursor.setToIconSite(
                 *icon.rightmostFromSite(self, cursorSite))
     else:
         # Cursor is on comma input.  Delete if empty or previous site is empty
         listicons.backspaceComma(self, siteId, evt)
         return
     redrawRegion.add(win.layoutDirtyIcons(filterRedundantParens=False))
     win.refresh(redrawRegion.get())
     win.undo.addBoundary()
Exemplo n.º 2
0
 def _iconsBetween(self, ic, site):
     """Find the icons that should be selected by shift-select between the current
     anchor (self.anchorIc and Pos, or self.anchorLine) and cursor at ic, site."""
     siteX, siteY = ic.posOfSite(site)
     siteType = ic.typeOf(site)
     if siteType in ("attrIn", "attrOut"):
         siteY -= icon.ATTR_SITE_OFFSET
     elif siteType in ("seqIn", "seqOut"):
         seqInX, seqInY = ic.posOfSite("seqIn")
         seqOutX, seqOutY = ic.posOfSite("seqOut")
         siteY = (seqInY + seqOutY) // 2
     if self.anchorIc is not None:
         anchorX, anchorY = self.anchorIc.posOfSite(self.anchorSite)
         anchorSiteType = self.anchorIc.typeOf(self.anchorSite)
         if anchorSiteType in ("attrIn", "attrOut"):
             anchorY -= icon.ATTR_SITE_OFFSET
         elif anchorSiteType in ("seqIn", "seqOut"):
             seqInX, seqInY = self.anchorIc.posOfSite("seqIn")
             seqOutX, seqOutY = self.anchorIc.posOfSite("seqOut")
             anchorY = (seqInY + seqOutY) // 2
         if anchorX < siteX:
             anchorX += 4  # Avoid overlapped icons and sites
             siteX -= 3
         elif siteX < anchorX:
             siteX += 4
             anchorX -= 3
         selectRect = comn.AccumRects(
             (anchorX, anchorY - 3, anchorX, anchorY + 3))
         selectRect.add((siteX, siteY - 3, siteX, siteY + 3))
     else:
         if self.anchorLine[0] == self.anchorLine[2]:
             anchorX = self.anchorLine[0]
             if anchorX < siteX:
                 self.anchorLine = comn.offsetRect(self.anchorLine, 4, 0)
                 siteX -= 3
             elif siteX < anchorX:
                 siteX += 4
                 icon.moveRect(self.anchorLine, (-3, 0))
         selectRect = comn.AccumRects(self.anchorLine)
         selectRect.add((siteX, siteY, siteX, siteY))
     # Get the icons that would be covered by a rectangular selection of the box
     iconsToSelect = self.window.findIconsInRegion(selectRect.get())
     iconsToSelect = [
         ic for ic in iconsToSelect if ic.inRectSelect(selectRect.get())
     ]
     # If the selection spans multiple statements, change to statement-level selection
     topIcons = {ic.topLevelParent() for ic in iconsToSelect}
     if len(topIcons) <= 1:
         return iconsToSelect
     else:
         return self._seqIconsBetween(topIcons)
Exemplo n.º 3
0
 def selectToCursor(self, ic, site, direction):
     """Modify selection based on cursor movement (presumably with Shift key held)"""
     selectedIcons = set(self.window.selectedIcons())
     redrawRect = comn.AccumRects()
     if len(selectedIcons) == 0 and self.type == "icon":
         # This is a new cursor-based selection
         self.anchorIc = self.icon
         self.anchorSite = self.site
     elif self.anchorIc is not None or self.anchorLine is not None:
         # There is a current recorded selection, but verify that it is valid by
         # matching it with the current actual selection
         lastSelIcons = set(
             self._iconsBetween(self.lastSelIc, self.lastSelSite))
         diffIcons = selectedIcons.difference(lastSelIcons)
         if len({i for i in diffIcons if not isinstance(i, icon.BlockEnd)}):
             self.anchorIc = None
             self.anchorLine = None
     if self.anchorIc is None and self.anchorLine is None:
         # The current selection is not valid, assume it was made via mouse.  Choose
         # an anchor line as the farthest side of the selection rectangle from the
         # cursor using the direction of arrow motion to choose horiz/vert
         selectedRect = comn.AccumRects()
         for i in selectedIcons:
             selectedRect.add(i.selectionRect())
         left, top, right, bottom = selectedRect.get()
         left += 3  # Inset rectangle to avoid overlaps and protruding sites
         right -= 3
         top += 1
         bottom -= 1
         siteX, siteY = ic.posOfSite(site)
         if direction in ("Left", "Right"):
             anchorX = right if abs(siteX - left) <= abs(siteX -
                                                         right) else left
             self.anchorLine = (anchorX, top, anchorX, bottom)
         else:
             anchorY = bottom if abs(siteY - top) <= abs(siteY -
                                                         bottom) else top
             self.anchorLine = (left, anchorY, right, anchorY)
     select = set(self._iconsBetween(ic, site))
     erase = selectedIcons.difference(select)
     select = select.difference(selectedIcons)
     for i in erase:
         redrawRect.add(i.hierRect())
         i.select(False)
     for i in select:
         redrawRect.add(i.hierRect())
         i.select()
     self.window.refresh(redrawRect.get())
     self.setToIconSite(ic, site)
     self.lastSelIc = ic
     self.lastSelSite = site
Exemplo n.º 4
0
 def backspace(self, siteId, evt):
     win = self.window
     redrawRegion = comn.AccumRects(self.topLevelParent().hierRect())
     if siteId == 'attrIcon':
         # Cursor is on attribute site of right paren.  Re-open the paren
         # On backspace from the outside right paren, reopen the list
         entryicon.reopenParen(self)
         redrawRegion.add(win.layoutDirtyIcons(filterRedundantParens=False))
         win.refresh(redrawRegion.get())
         return
     else:
         # Cursor is on the argument site: remove the parens unless an attribute is
         # attached to the parens, in which case, don't delete, just select
         attrIcon = self.childAt('attrIcon')
         if attrIcon:
             win.unselectAll()
             toSelect = list(attrIcon.traverse())
             if siteId == 'argIcon':
                 toSelect.append(self)
             for i in toSelect:
                 win.select(i)
             win.refresh(redrawRegion.get())
             return
         parent = self.parent()
         content = self.childAt('argIcon')
         if parent is None:
             if content is None:
                 # Open paren was the only thing left of the statement.  Remove
                 if self.prevInSeq() is not None:
                     cursorIc = self.prevInSeq()
                     cursorSite = 'seqOut'
                 elif self.nextInSeq() is not None:
                     cursorIc = self.nextInSeq()
                     cursorSite = 'seqIn'
                 else:
                     cursorIc = None
                     pos = self.pos()
                 win.removeIcons([self])
                 if cursorIc is None:
                     win.cursor.setToWindowPos(pos)
                 else:
                     win.cursor.setToIconSite(cursorIc, cursorSite)
             else:
                 # Open paren on top level had content
                 self.replaceChild(None, 'argIcon')
                 win.replaceTop(self, content)
                 topNode = reorderexpr.reorderArithExpr(content)
                 win.cursor.setToBestCoincidentSite(topNode, 'output')
         else:
             # Open paren had a parent.  Remove by attaching content to parent
             parentSite = parent.siteOf(self)
             if content is None:
                 parent.replaceChild(None, parentSite, leavePlace=True)
                 win.cursor.setToIconSite(parent, parentSite)
             else:
                 parent.replaceChild(content, parentSite)
                 win.cursor.setToIconSite(parent, parentSite)
                 reorderexpr.reorderArithExpr(content)
     redrawRegion.add(win.layoutDirtyIcons(filterRedundantParens=True))
     win.refresh(redrawRegion.get())
Exemplo n.º 5
0
 def arrowKeyWithSelection(self, evt, selectedIcons):
     """Process arrow key pressed with no cursor but selected icons."""
     direction = evt.keysym
     shiftPressed = evt.state & python_g.SHIFT_MASK
     if not shiftPressed:
         self.window.unselectAll()
     selectedRects = comn.AccumRects()
     for ic in selectedIcons:
         selectedRects.add(ic.selectionRect())
     selectedRect = selectedRects.get()
     l, t, r, b = selectedRect
     l -= 10
     t -= 10
     r += 10
     b += 10
     searchRect = l, t, r, b
     cursorSites = []
     for ic in self.window.findIconsInRegion(searchRect):
         snapLists = ic.snapLists(forCursor=True)
         for ic, (x, y), name in snapLists.get("input", []):
             cursorSites.append((x, y, ic, name))
         for ic, (x, y), name in snapLists.get("attrIn", []):
             cursorSites.append((x, y - icon.ATTR_SITE_OFFSET, ic, name))
         outSites = snapLists.get("output", [])
         if len(outSites) > 0:
             cursorSites.append((*outSites[0][1], ic, "output"))
     if len(cursorSites) == 0:
         return  # It is possible to have icons with no viable cursor sites
     selLeft, selTop, selRight, selBottom = selectedRect
     bestDist = None
     for siteData in cursorSites:
         x, y = siteData[:2]
         if direction == "Left":  # distance from left edge
             dist = abs(x - selLeft) + max(0, selBottom - y) + max(
                 0, y - selTop)
         elif direction == "Right":  # distance from right edge
             dist = abs(x - selRight) + max(0, selBottom - y) + max(
                 0, y - selTop)
         elif direction == "Up":  # distance from top edge
             dist = abs(y - selTop) + max(0, selLeft - x) + max(
                 0, x - selRight)
         elif direction == "Down":  # distance from bottom edge
             dist = abs(y - selBottom) + max(0, selLeft - x) + max(
                 0, x - selRight)
         if bestDist is None or dist < bestDist:
             bestSiteData = siteData
             bestDist = dist
     x, y, ic, site = bestSiteData
     if site == "output":
         parent = ic.parent()
         if parent is not None:
             self.setToIconSite(parent, parent.siteOf(ic))
             return
     self.moveToIconSite(ic, site, evt)
Exemplo n.º 6
0
 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())
Exemplo n.º 7
0
 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()