def nextSlide (self,event=None): c = self.c ; p = c.p if p == self.slide: p = self.slide.threadNext() oldSlide = self.slide else: oldSlide = None while p: h = p.h.strip() if self.ignored(p): p = p.threadNext() elif h.startswith('@slideshow'): self.select(p) return g.es('At %s of slide show' % g.choose(oldSlide,'end','start')) elif g.match_word(h,0,'@ignore') or g.match_word(h,0,'@noslide'): p = p.nodeAfterTree() else: return self.select(p) # elif h.startswith('@slide'): # return self.select(p) # else: p = p.threadNext() else: return g.es(g.choose(self.slideShowRoot, 'At end of slide show', 'Not in any slide show'))
def nextSlide(self, event=None): c = self.c p = c.p if p == self.slide: p = self.slide.threadNext() oldSlide = self.slide else: oldSlide = None while p: h = p.h.strip() if self.ignored(p): p = p.threadNext() elif h.startswith('@slideshow'): self.select(p) return g.es('At %s of slide show' % g.choose(oldSlide, 'end', 'start')) elif g.match_word(h, 0, '@ignore') or g.match_word( h, 0, '@noslide'): p = p.nodeAfterTree() else: return self.select(p) # elif h.startswith('@slide'): # return self.select(p) # else: p = p.threadNext() else: return g.es( g.choose(self.slideShowRoot, 'At end of slide show', 'Not in any slide show'))
def keysymHelper(self, event, kind): gui = self keycode = event.GetKeyCode() # g.trace(repr(keycode),kind) if keycode in (wx.WXK_SHIFT, wx.WXK_ALT, wx.WXK_CONTROL): return '' keysym = gui.wxKeyDict.get(keycode) or '' keyDownModifiers = hasattr( event, 'keyDownModifiers') and event.keyDownModifiers or None alt = event.AltDown() or keyDownModifiers == wx.MOD_ALT cmd = event.CmdDown() or keyDownModifiers == wx.MOD_CMD ctrl = event.ControlDown() or keyDownModifiers == wx.MOD_CONTROL meta = event.MetaDown() or keyDownModifiers == wx.MOD_META shift = event.ShiftDown() or keyDownModifiers == wx.MOD_SHIFT # Set the char field. char = keysym or '' if not char: # Avoid GetUnicodeKey if possible. It crashes on '.' (!) try: char = chr(keycode) except ValueError: char = '' if not char and hasattr(event, 'GetUnicodeKey'): i = event.GetUnicodeKey() if i is None: char = '' else: try: char = unichr(i) except Exception: g.es('No translation for', repr(i)) char = repr(i) # Adjust the case, but only for plain ascii characters characters. if len(char) == 1: if char.isalpha(): if shift: # Case is also important for ctrl keys. # or alt or cmd or ctrl or meta: char = char.upper() else: char = char.lower() elif shift: char = self.getShiftChar(char) else: char = self.getUnshiftChar(char) # Create a value compatible with Leo's core. val = ( g.choose(alt, 'Alt+', '') + # g.choose(cmd,'Cmd+','') + g.choose(ctrl, 'Ctrl+', '') + g.choose(meta, 'Meta+', '') + g.choose((alt or cmd or ctrl or meta) and shift, 'Shift+', '') + (char or '')) # if kind == 'char': g.trace(repr(keycode),repr(val)) # Tracing just val can crash! return val
def doOp (self): val = self.val outer = self.lineParenLevel <= 0 or (self.parenLevel == 0 and self.squareBracketLevel == 0) # New in Python 2.4: '@' is an operator, not an error token. if self.val == '@': self.array.append(self.val) # Preserve whitespace after @. i = g.skip_ws(self.s,self.scol+1) ws = self.s[self.scol+1:i] if ws: self.array.append(ws) elif val == '(': # Nothing added; strip leading blank before function calls but not before Python keywords. strip = self.lastName=='name' and not keyword.iskeyword(self.prevName) self.put('(',strip=strip) self.parenLevel += 1 ; self.lineParenLevel += 1 elif val in ('=','==','+=','-=','!=','<=','>=','<','>','<>','*','**','+','&','|','/','//'): # Add leading and trailing blank in outer mode. s = g.choose(outer,' %s ','%s') self.put(s % val) elif val in ('^','~','{','['): # Add leading blank in outer mode. s = g.choose(outer,' %s','%s') self.put(s % val) if val == '[': self.squareBracketLevel += 1 elif val in (',',':','}',']',')'): # Add trailing blank in outer mode. s = g.choose(outer,'%s ','%s') self.put(s % val) if val == ']': self.squareBracketLevel -= 1 if val == ')': self.parenLevel -= 1 ; self.lineParenLevel -= 1 # no difference between outer and inner modes elif val in (';','%'): # Add leading and trailing blank. self.put(' %s ' % val) elif val == '>>': # Add leading blank. self.put(' %s' % val) elif val == '<<': # Add trailing blank. self.put('%s ' % val) elif val in ('-'): # Could be binary or unary. Or could be a hyphen in a section name. # Add preceding blank only for non-id's. if outer: if self.array: prev = self.array[-1].rstrip() if prev and prev[-1] not in string.digits + string.letters: self.put(' %s' % val) else: self.put(val) else: self.put(val) # Try to leave whitespace unchanged. else: self.put(val) else: self.put(val)
def dump(self, title): g.pr(title) # g.pr('self.i',self.i) for i, line in enumerate(self.lines): marker = g.choose(i==self.i,'**',' ') g.pr("%s %3s:%s" % (marker, i, repr(line)),)
def dump(self, title): g.pr(title) # g.pr('self.i',self.i) for i, line in enumerate(self.lines): marker = g.choose(i == self.i, '**', ' ') g.pr("%s %3s:%s" % (marker, i, repr(line)), )
def cleanButtonText(self, s, minimal=False): '''Clean the text following @button or @command so that it is a valid name of a minibuffer command.''' # 2011/10/16: Delete {tag} s = s.strip() i, j = s.find('{'), s.find('}') if -1 < i < j: s = s[:i] + s[j + 1:] s = s.strip() if minimal: return s.lower() for tag in ( '@key', '@args', ): i = s.find(tag) if i > -1: j = s.find('@', i + 1) if i < j: s = s[:i] + s[j + 1:] else: s = s[:i] s = s.strip() if 1: # Not great, but spaces, etc. interfere with tab completion. # 2011/10/16 *do* allow '@' sign. chars = g.toUnicode(string.ascii_letters + string.digits + '@') aList = [g.choose(ch in chars, ch, '-') for ch in g.toUnicode(s)] s = ''.join(aList) s = s.replace('--', '-') while s.startswith('-'): s = s[1:] while s.endswith('-'): s = s[:-1] return s.lower()
def callZenity(title, multiple=False, save=False, test=False): command = ['zenity', '--file-selection', '--title=%s' % title] if save: command.append('--save') if multiple: command.append('--multiple') o = Popen(command, stdout=PIPE) o.wait() filename = o.communicate()[0].rstrip() ret = o.returncode if trace: g.trace('\n\tfiles', repr(filename)) print('\treturncode', ret) if ret: trace and g.trace(g.choose(save, 'save', 'open'), 'cancelled') return '' if multiple: return filename.split('|') return filename
def compare_files (self, name1, name2): if name1 == name2: self.show("File names are identical.\nPlease pick distinct files.") return f1 = f2 = None try: f1 = self.doOpen(name1) f2 = self.doOpen(name2) if self.outputFileName: self.openOutputFile() ok = self.outputFileName == None or self.outputFile ok = g.choose(ok and ok != 0,1,0) if f1 and f2 and ok: # Don't compare if there is an error opening the output file. self.compare_open_files(f1,f2,name1,name2) except: self.show("exception comparing files") g.es_exception() try: if f1: f1.close() if f2: f2.close() if self.outputFile: self.outputFile.close() ; self.outputFile = None except: self.show("exception closing files") g.es_exception()
def callZenity(title, multiple=False, save=False, test=False): command = [ 'zenity', '--file-selection', '--title=%s'%title] if save: command.append('--save') if multiple: command.append('--multiple') o = Popen(command, stdout=PIPE) o.wait() filename = o.communicate()[0].rstrip() ret = o.returncode if trace: g.trace('\n\tfiles', repr(filename)) print('\treturncode', ret) if ret: trace and g.trace(g.choose(save,'save','open'), 'cancelled') return '' if multiple: return filename.split('|') return filename
def compare_files(self, name1, name2): if name1 == name2: self.show("File names are identical.\nPlease pick distinct files.") return f1 = f2 = None try: f1 = self.doOpen(name1) f2 = self.doOpen(name2) if self.outputFileName: self.openOutputFile() ok = self.outputFileName == None or self.outputFile ok = g.choose(ok and ok != 0, 1, 0) if f1 and f2 and ok: # Don't compare if there is an error opening the output file. self.compare_open_files(f1, f2, name1, name2) except: self.show("exception comparing files") g.es_exception() try: if f1: f1.close() if f2: f2.close() if self.outputFile: self.outputFile.close() self.outputFile = None except: self.show("exception closing files") g.es_exception()
def cleanButtonText (self,s,minimal=False): '''Clean the text following @button or @command so that it is a valid name of a minibuffer command.''' # 2011/10/16: Delete {tag} s = s.strip() i,j = s.find('{'),s.find('}') if -1 < i < j: s = s[:i] + s[j+1:] s = s.strip() if minimal: return s.lower() for tag in ('@key','@args','@color',): i = s.find(tag) if i > -1: j = s.find('@',i+1) if i < j: s = s[:i] + s[j:] else: s = s[:i] s = s.strip() if 1: # Not great, but spaces, etc. interfere with tab completion. # 2011/10/16 *do* allow '@' sign. chars = g.toUnicode(string.ascii_letters + string.digits + '@') aList = [g.choose(ch in chars,ch,'-') for ch in g.toUnicode(s)] s = ''.join(aList) s = s.replace('--','-') while s.startswith('-'): s = s[1:] while s.endswith('-'): s = s[:-1] return s.lower()
def runAskYesNoDialog(self, c, title, message=None): """Create and run a wxPython askYesNo dialog.""" if g.app.unitTesting: return 'yes' d = wx.MessageDialog(self.root, message, "Leo", wx.YES_NO) answer = d.ShowModal() return g.choose(answer == wx.YES, "yes", "no")
def runAskYesNoDialog(self,c,title,message=None): """Create and run a wxPython askYesNo dialog.""" if g.app.unitTesting: return 'yes' d = wx.MessageDialog(self.root,message,"Leo",wx.YES_NO) answer = d.ShowModal() return g.choose(answer==wx.YES,"yes","no")
def draw_tree_helper (self,p,indent): for p in p.self_and_siblings(): if p.hasChildren(): box = g.choose(p.isExpanded(),'+','-') else: box = ' ' icons = '%s%s%s%s' % ( g.choose(p.v.t.hasBody(),'b',' '), g.choose(p.isMarked(),'m',' '), g.choose(p.isCloned(),'@',' '), g.choose(p.isDirty(),'*',' ')) g.pr(" " * indent * 2, icons, box, p.h) if p.isExpanded() and p.hasChildren(): self.draw_tree_helper(p.firstChild(),indent+1)
def findPositionInChapter (self,p1,strict=False): '''Return a valid position p such that p.v == v.''' trace = False and not g.unitTesting ; verbose = False c,cc = self.c,self.cc if trace: g.trace('%s exists: %s p: %s' % ( self.name,c.positionExists(p1),p1)) # Bug fix: 2012/05/24: Search without root arg in the main chapter. if self.name == 'main' and c.positionExists(p1): return p1 if not p1: if trace and verbose: g.trace('*** no p') return None root = g.choose(self.name=='main',c.rootPosition(),self.root()) if c.positionExists(p1,root=root): if trace and verbose: g.trace('found existing',p1.h) return p1 if strict: if trace: g.trace('strict test fails',p1.h) return None theIter = g.choose(self.name=='main', self.c.all_unique_positions, root.self_and_subtree) for p in theIter(): if p.v == p1.v: if trace: g.trace('*** found vnode match',p1.h) return p.copy() if trace: g.trace('*** not found',p1.h) return None
def split_parts(self, lines, showDocsAsParagraphs): '''Split a list of body lines into a list of tuples (kind,lines).''' kind, parts, part_lines = 'code', [], [] for s in lines: if g.match_word(s, 0, '@ @rst-markup'): if part_lines: parts.append((kind, part_lines[:]), ) kind = '@rst-markup' n = len('@ @rst-markup') after = s[n:].strip() part_lines = g.choose(after, [after], []) elif s.startswith('@ @rst-option'): if part_lines: parts.append((kind, part_lines[:]), ) kind, part_lines = '@rst-option', [ s ] # part_lines will be ignored. elif s.startswith('@ ') or s.startswith('@\n') or s.startswith( '@doc'): if showDocsAsParagraphs: if part_lines: parts.append((kind, part_lines[:]), ) kind = '@doc' # Put only what follows @ or @doc n = g.choose(s.startswith('@doc'), 4, 1) after = s[n:].lstrip() part_lines = g.choose(after, [after], []) else: part_lines.append(s) # still in code mode. elif g.match_word(s, 0, '@c') and kind != 'code': if kind == '@doc' and not showDocsAsParagraphs: part_lines.append(s) # Show the @c as code. parts.append((kind, part_lines[:]), ) kind, part_lines = 'code', [] else: part_lines.append(s) if part_lines: parts.append((kind, part_lines[:]), ) return parts
def init_s_ctrl(self, s, ins=None): t = self.s_ctrl t.delete("1.0", "end") t.insert("end", s) if ins is None: t.mark_set("insert", g.choose(self.reverse, "end", "1.0")) else: ins = t.toGuiIndex(ins) t.mark_set("insert", ins) return t
def init_s_ctrl (self,s,ins=None): t = self.s_ctrl t.delete("1.0","end") t.insert("end",s) if ins is None: t.mark_set("insert",g.choose(self.reverse,"end","1.0")) else: ins = t.toGuiIndex(ins) t.mark_set("insert",ins) return t
def split_parts (self,lines,showDocsAsParagraphs): '''Split a list of body lines into a list of tuples (kind,lines).''' kind,parts,part_lines = 'code',[],[] for s in lines: if g.match_word(s,0,'@ @rst-markup'): if part_lines: parts.append((kind,part_lines[:]),) kind = '@rst-markup' n = len('@ @rst-markup') after = s[n:].strip() part_lines = g.choose(after,[after],[]) elif s.startswith('@ @rst-option'): if part_lines: parts.append((kind,part_lines[:]),) kind,part_lines = '@rst-option',[s] # part_lines will be ignored. elif s.startswith('@ ') or s.startswith('@\n') or s.startswith('@doc'): if showDocsAsParagraphs: if part_lines: parts.append((kind,part_lines[:]),) kind = '@doc' # Put only what follows @ or @doc n = g.choose(s.startswith('@doc'),4,1) after = s[n:].lstrip() part_lines = g.choose(after,[after],[]) else: part_lines.append(s) # still in code mode. elif g.match_word(s,0,'@c') and kind != 'code': if kind == '@doc' and not showDocsAsParagraphs: part_lines.append(s) # Show the @c as code. parts.append((kind,part_lines[:]),) kind,part_lines = 'code',[] else: part_lines.append(s) if part_lines: parts.append((kind,part_lines[:]),) return parts
def setCachedStringPosition(self,str_pos): trace = False and not g.unitTesting c = self.c if not c: return g.internalError('no commander') globals_tag = g.choose(g.isPython3,'leo3k.globals','leo2k.globals') # globals_tag = g.toEncodedString(globals_tag,'ascii') key = self.fileKey(c.mFileName,globals_tag) self.db['current_position_%s' % key] = str_pos if trace: g.trace(str_pos,key)
def newMoreHead (self,firstLevel,useVerticalBar=True): useVerticalBar = True # Force the vertical bar v = self level = self.level() - firstLevel if level > 0: if useVerticalBar: s = " |\t" * level else: s = "\t" else: s = "" s += g.choose(v.hasChildren(), "+ ", "- ") s += v.h return s
def newMoreHead(self, firstLevel, useVerticalBar=True): useVerticalBar = True # Force the vertical bar v = self level = self.level() - firstLevel if level > 0: if useVerticalBar: s = " |\t" * level else: s = "\t" else: s = "" s += g.choose(v.hasChildren(), "+ ", "- ") s += v.h return s
def updateButtons(self): """Update nav buttons to reflect current state.""" c = self.c if not hasattr(c, 'nodeHistory') or not c.nodeHistory: return for b, b2, enabled_image, disabled_image, cond in ( (self.lt_nav_button, self.lt_nav_iconFrame_button, self.lt_nav_enabled_image, self.lt_nav_disabled_image, c.nodeHistory.canGoToPrevVisited()), (self.rt_nav_button, self.rt_nav_iconFrame_button, self.rt_nav_enabled_image, self.rt_nav_disabled_image, c.nodeHistory.canGoToNextVisited()), ): # Disabled state makes the icon look bad. image = g.choose(cond, enabled_image, disabled_image) b.configure(image=image, state='normal') b2.configure(image=image, state='normal')
def getCachedGlobalFileRatios (self): trace = False and not g.unitTesting c = self.c if not c: return g.internalError('no commander') globals_tag = g.choose(g.isPython3,'leo3k.globals','leo2k.globals') # globals_tag = g.toEncodedString(globals_tag,'ascii') key = self.fileKey(c.mFileName,globals_tag) ratio = float(self.db.get('body_outline_ratio_%s' % (key),'0.5')) ratio2 = float(self.db.get('body_secondary_ratio_%s' % (key),'0.5')) if trace: g.trace('key',key,'%1.2f %1.2f' % (ratio,ratio2)) return ratio,ratio2
def updateButtons (self): """Update nav buttons to reflect current state.""" c = self.c if not hasattr(c,'nodeHistory') or not c.nodeHistory: return for b,b2,enabled_image,disabled_image,cond in ( ( self.lt_nav_button,self.lt_nav_iconFrame_button, self.lt_nav_enabled_image,self.lt_nav_disabled_image, c.nodeHistory.canGoToPrevVisited()), ( self.rt_nav_button,self.rt_nav_iconFrame_button, self.rt_nav_enabled_image,self.rt_nav_disabled_image, c.nodeHistory.canGoToNextVisited()), ): # Disabled state makes the icon look bad. image = g.choose(cond,enabled_image,disabled_image) b.configure(image=image,state='normal') b2.configure(image=image,state='normal')
def onHoistChanged(self, tag, keywords): c = self.c if g.app.killed or g.app.unitTesting: return for b, f in ( (self.hoistButton, c.canHoist), (self.dehoistButton, c.canDehoist), ): state = g.choose(f(), "normal", "disabled") b.config(state=state) n = c.hoistLevel() if n > 0: self.hoistButton.config(bg=activeHoistColor, activebackground=activeHoistColor, text="Hoist %s" % n) else: self.hoistButton.config(bg=self.bgColor, activebackground=self.activeBgColor, text="Hoist")
def getCachedWindowPositionDict (self,fn): trace = False and not g.unitTesting c = self.c if not c: g.internalError('no commander') return {} globals_tag = g.choose(g.isPython3,'leo3k.globals','leo2k.globals') key = self.fileKey(fn,globals_tag) data = self.db.get('window_position_%s' % (key)) if data: top,left,height,width = data top,left,height,width = int(top),int(left),int(height),int(width) d = {'top':top,'left':left,'height':height,'width':width} else: d = {} if trace: g.trace(fn,key,data) return d
def onHoistChanged(self,tag,keywords): c = self.c if g.app.killed or g.app.unitTesting: return for b,f in ( (self.hoistButton,c.canHoist), (self.dehoistButton,c.canDehoist), ): state = g.choose(f(),"normal","disabled") b.config(state=state) n = c.hoistLevel() if n > 0: self.hoistButton.config(bg=activeHoistColor, activebackground=activeHoistColor, text="Hoist %s" % n) else: self.hoistButton.config(bg=self.bgColor, activebackground=self.activeBgColor, text="Hoist")
def setCachedGlobalsElement(self,fn): trace = False and not g.unitTesting c = self.c if not c: return g.internalError('no commander') globals_tag = g.choose(g.isPython3,'leo3k.globals','leo2k.globals') key = self.fileKey(fn,globals_tag) if trace: g.trace(c.mFileName,key,g.callers(5)) self.db['body_outline_ratio_%s' % key] = str(c.frame.ratio) self.db['body_secondary_ratio_%s' % key] = str(c.frame.secondary_ratio) if trace: g.trace('ratios: %1.2f %1.2f' % ( c.frame.ratio,c.frame.secondary_ratio)) width,height,left,top = c.frame.get_window_info() self.db['window_position_%s' % key] = ( str(top),str(left),str(height),str(width)) if trace: g.trace('top',top,'left',left,'height',height,'width',width)
def cvt(s): return g.choose(g.isUnicode(s),s,g.toUnicode(s,self.encoding))
def doOp(self): val = self.val outer = self.lineParenLevel <= 0 or (self.parenLevel == 0 and self.squareBracketLevel == 0) # New in Python 2.4: '@' is an operator, not an error token. if self.val == '@': self.array.append(self.val) # Preserve whitespace after @. i = g.skip_ws(self.s, self.scol + 1) ws = self.s[self.scol + 1:i] if ws: self.array.append(ws) elif val == '(': # Nothing added; strip leading blank before function calls but not before Python keywords. strip = self.lastName == 'name' and not keyword.iskeyword( self.prevName) self.put('(', strip=strip) self.parenLevel += 1 self.lineParenLevel += 1 elif val in ('=', '==', '+=', '-=', '!=', '<=', '>=', '<', '>', '<>', '*', '**', '+', '&', '|', '/', '//'): # Add leading and trailing blank in outer mode. s = g.choose(outer, ' %s ', '%s') self.put(s % val) elif val in ('^', '~', '{', '['): # Add leading blank in outer mode. s = g.choose(outer, ' %s', '%s') self.put(s % val) if val == '[': self.squareBracketLevel += 1 elif val in (',', ':', '}', ']', ')'): # Add trailing blank in outer mode. s = g.choose(outer, '%s ', '%s') self.put(s % val) if val == ']': self.squareBracketLevel -= 1 if val == ')': self.parenLevel -= 1 self.lineParenLevel -= 1 # no difference between outer and inner modes elif val in (';', '%'): # Add leading and trailing blank. self.put(' %s ' % val) elif val == '>>': # Add leading blank. self.put(' %s' % val) elif val == '<<': # Add trailing blank. self.put('%s ' % val) elif val in ('-'): # Could be binary or unary. Or could be a hyphen in a section name. # Add preceding blank only for non-id's. if outer: if self.array: prev = self.array[-1].rstrip() if prev and prev[ -1] not in string.digits + string.letters: self.put(' %s' % val) else: self.put(val) else: self.put(val) # Try to leave whitespace unchanged. else: self.put(val) else: self.put(val)
def cvt(s): return g.choose(g.isUnicode(s), s, g.toUnicode(s, self.encoding))
def addButton (self, first, type_="move", v=None, parent=None): '''Add a button that creates a target for future moves.''' c = self.c p = c.p if v is None: v = p.v sc = scriptingController(c) mb = quickMoveButton(self,v,first,type_=type_) txt=self.txts[type_] if parent: # find parent button for i in self.buttons: if i[0].target.gnx == parent: parent = i[1] break else: g.es('Move to button parent not found, placing at top level') parent = None header = v.anyAtFileNodeName() or v.h # drop @auto etc. text = txt + ":" + header if txt else header # createButton truncates text. if parent and g.app.gui.guiName() == "qt": # see qtGui.py/class leoQtFrame/class qtIconBarClass/setCommandForButton pb = parent.button rc = QtGui.QAction(text, pb) rc.connect(rc, QtCore.SIGNAL("triggered()"), mb.moveCurrentNodeToTarget) pb.insertAction(pb.actions()[0], rc) # insert at top b = None mb.has_parent = True t = QtCore.QString(c.config.getString('mod_scripting_subtext') or '') if not unicode(pb.text()).endswith(unicode(t)): pb.setText(pb.text()+t) else: b = sc.createIconButton( text, command = mb.moveCurrentNodeToTarget, statusLine = 'Move current node to %s child of %s' % ( g.choose(first,'first','last'),v.h), bg = "LightBlue" ) if g.app.gui.guiName() == "qt": def cb_goto_target(event=None, c=c, v=v): p = c.vnode2position(v) c.selectPosition(p) c.redraw() def cb_set_parent(event=None, c=c, v=v, first=first, type_=type_): c.quickMove.set_parent(v, first, type_) def cb_permanent(event=None, c=c, v=v, type_=type_, first=first): c.quickMove.permanentButton(v=v, type_=type_, first=first) # def cb_clear(event=None, c=c, v=v): # c.quickMove.clearButton(v) for cb, txt in [ (cb_goto_target, 'Goto target'), (cb_permanent, 'Make permanent'), # (cb_clear, 'Clear permanent'), (cb_set_parent, 'Set parent'), ]: but = b.button rc = QtGui.QAction(txt, but) rc.connect(rc, QtCore.SIGNAL("triggered()"), cb) but.insertAction(but.actions()[-1], rc) # insert rc before Remove Button self.buttons.append((mb,b))
def addButton(self, first, type_="move", v=None, parent=None): '''Add a button that creates a target for future moves.''' c = self.c p = c.p if v is None: v = p.v sc = scriptingController(c) mb = quickMoveButton(self, v, first, type_=type_) txt = self.txts[type_] if parent: # find parent button for i in self.buttons: if i[0].target.gnx == parent: parent = i[1] break else: g.es('Move to button parent not found, placing at top level') parent = None header = v.anyAtFileNodeName() or v.h # drop @auto etc. text = txt + ":" + header if txt else header # createButton truncates text. if parent and g.app.gui.guiName() == "qt": # see qtGui.py/class leoQtFrame/class qtIconBarClass/setCommandForButton pb = parent.button rc = QtGui.QAction(text, pb) rc.connect(rc, QtCore.SIGNAL("triggered()"), mb.moveCurrentNodeToTarget) pb.insertAction(pb.actions()[0], rc) # insert at top b = None mb.has_parent = True t = QtCore.QString( c.config.getString('mod_scripting_subtext') or '') if not unicode(pb.text()).endswith(unicode(t)): pb.setText(pb.text() + t) else: b = sc.createIconButton( text, command=mb.moveCurrentNodeToTarget, statusLine='Move current node to %s child of %s' % (g.choose(first, 'first', 'last'), v.h), kind="quick-move") if g.app.gui.guiName() == "qt": def cb_goto_target(event=None, c=c, v=v): p = c.vnode2position(v) c.selectPosition(p) c.redraw() def cb_set_parent(event=None, c=c, v=v, first=first, type_=type_): c.quickMove.set_parent(v, first, type_) def cb_permanent(event=None, c=c, v=v, type_=type_, first=first): c.quickMove.permanentButton(v=v, type_=type_, first=first) # def cb_clear(event=None, c=c, v=v): # c.quickMove.clearButton(v) for cb, txt in [ (cb_goto_target, 'Goto target'), (cb_permanent, 'Make permanent'), # (cb_clear, 'Clear permanent'), (cb_set_parent, 'Set parent'), ]: but = b.button rc = QtGui.QAction(txt, but) rc.connect(rc, QtCore.SIGNAL("triggered()"), cb) but.insertAction(but.actions()[-1], rc) # insert rc before Remove Button self.buttons.append((mb, b))
def keysymHelper (self,event,kind): gui = self keycode = event.GetKeyCode() # g.trace(repr(keycode),kind) if keycode in (wx.WXK_SHIFT,wx.WXK_ALT,wx.WXK_CONTROL): return '' keysym = gui.wxKeyDict.get(keycode) or '' keyDownModifiers = hasattr(event,'keyDownModifiers') and event.keyDownModifiers or None alt = event.AltDown() or keyDownModifiers == wx.MOD_ALT cmd = event.CmdDown() or keyDownModifiers == wx.MOD_CMD ctrl = event.ControlDown()or keyDownModifiers == wx.MOD_CONTROL meta = event.MetaDown() or keyDownModifiers == wx.MOD_META shift = event.ShiftDown() or keyDownModifiers == wx.MOD_SHIFT # Set the char field. char = keysym or '' if not char: # Avoid GetUnicodeKey if possible. It crashes on '.' (!) try: char = chr(keycode) except ValueError: char = '' if not char and hasattr(event,'GetUnicodeKey'): i = event.GetUnicodeKey() if i is None: char = '' else: try: char = unichr(i) except Exception: g.es('No translation for', repr(i)) char = repr(i) # Adjust the case, but only for plain ascii characters characters. if len(char) == 1: if char.isalpha(): if shift: # Case is also important for ctrl keys. # or alt or cmd or ctrl or meta: char = char.upper() else: char = char.lower() elif shift: char = self.getShiftChar(char) else: char = self.getUnshiftChar(char) # Create a value compatible with Leo's core. val = ( g.choose(alt,'Alt+','') + # g.choose(cmd,'Cmd+','') + g.choose(ctrl,'Ctrl+','') + g.choose(meta,'Meta+','') + g.choose((alt or cmd or ctrl or meta) and shift,'Shift+','') + (char or '') ) # if kind == 'char': g.trace(repr(keycode),repr(val)) # Tracing just val can crash! return val