laurent@738: import wx laurent@738: import wx.grid laurent@738: import wx.stc as stc laurent@366: import keyword laurent@366: Laurent@814: from editors.ConfTreeNodeEditor import ConfTreeNodeEditor laurent@657: laurent@366: if wx.Platform == '__WXMSW__': laurent@366: faces = { 'times': 'Times New Roman', laurent@366: 'mono' : 'Courier New', laurent@366: 'helv' : 'Arial', laurent@366: 'other': 'Comic Sans MS', laurent@366: 'size' : 10, laurent@366: 'size2': 8, laurent@366: } laurent@366: elif wx.Platform == '__WXMAC__': laurent@366: faces = { 'times': 'Times New Roman', laurent@366: 'mono' : 'Monaco', laurent@366: 'helv' : 'Arial', laurent@366: 'other': 'Comic Sans MS', laurent@366: 'size' : 12, laurent@366: 'size2': 10, laurent@366: } laurent@366: else: laurent@366: faces = { 'times': 'Times', laurent@366: 'mono' : 'Courier', laurent@366: 'helv' : 'Helvetica', laurent@366: 'other': 'new century schoolbook', laurent@366: 'size' : 12, laurent@366: 'size2': 10, laurent@366: } laurent@366: laurent@366: [ID_PYTHONEDITOR, laurent@366: ] = [wx.NewId() for _init_ctrls in range(1)] laurent@366: laurent@366: def GetCursorPos(old, new): laurent@366: old_length = len(old) laurent@366: new_length = len(new) laurent@366: common_length = min(old_length, new_length) laurent@366: i = 0 laurent@366: for i in xrange(common_length): laurent@366: if old[i] != new[i]: laurent@366: break laurent@366: if old_length < new_length: laurent@366: if common_length > 0 and old[i] != new[i]: laurent@366: return i + new_length - old_length laurent@366: else: laurent@366: return i + new_length - old_length + 1 laurent@366: elif old_length > new_length or i < min(old_length, new_length) - 1: laurent@366: if common_length > 0 and old[i] != new[i]: laurent@366: return i laurent@366: else: laurent@366: return i + 1 laurent@366: else: laurent@366: return None laurent@366: laurent@738: class PythonEditor(ConfTreeNodeEditor): laurent@366: laurent@366: fold_symbols = 3 Laurent@920: CONFNODEEDITOR_TABS = [ Laurent@920: (_("Python code"), "_create_PythonCodeEditor")] Laurent@920: Laurent@920: def _create_PythonCodeEditor(self, prnt): Laurent@920: self.PythonCodeEditor = stc.StyledTextCtrl(id=ID_PYTHONEDITOR, parent=prnt, laurent@657: name="TextViewer", pos=wx.DefaultPosition, laurent@657: size=wx.DefaultSize, style=0) Laurent@920: self.PythonCodeEditor.ParentWindow = self Laurent@920: Laurent@920: self.PythonCodeEditor.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) Laurent@920: self.PythonCodeEditor.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) Laurent@920: Laurent@920: self.PythonCodeEditor.SetLexer(stc.STC_LEX_PYTHON) Laurent@920: self.PythonCodeEditor.SetKeyWords(0, " ".join(keyword.kwlist)) Laurent@920: Laurent@920: self.PythonCodeEditor.SetProperty("fold", "1") Laurent@920: self.PythonCodeEditor.SetProperty("tab.timmy.whinge.level", "1") Laurent@920: self.PythonCodeEditor.SetMargins(0,0) Laurent@920: Laurent@920: self.PythonCodeEditor.SetViewWhiteSpace(False) Laurent@920: Laurent@920: self.PythonCodeEditor.SetEdgeMode(stc.STC_EDGE_BACKGROUND) Laurent@920: self.PythonCodeEditor.SetEdgeColumn(78) laurent@366: laurent@366: # Set up the numbers in the margin for margin #1 Laurent@920: self.PythonCodeEditor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) laurent@366: # Reasonable value for, say, 4-5 digits using a mono font (40 pix) Laurent@920: self.PythonCodeEditor.SetMarginWidth(1, 40) laurent@366: laurent@366: # Setup a margin to hold fold markers Laurent@920: self.PythonCodeEditor.SetMarginType(2, stc.STC_MARGIN_SYMBOL) Laurent@920: self.PythonCodeEditor.SetMarginMask(2, stc.STC_MASK_FOLDERS) Laurent@920: self.PythonCodeEditor.SetMarginSensitive(2, True) Laurent@920: self.PythonCodeEditor.SetMarginWidth(2, 12) laurent@366: laurent@366: if self.fold_symbols == 0: laurent@366: # Arrow pointing right for contracted folders, arrow pointing down for expanded Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") laurent@366: laurent@366: elif self.fold_symbols == 1: laurent@366: # Plus for contracted folders, minus for expanded Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") laurent@366: laurent@366: elif self.fold_symbols == 2: laurent@366: # Like a flattened tree control using circular headers and curved joins Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") laurent@366: laurent@366: elif self.fold_symbols == 3: laurent@366: # Like a flattened tree control using square headers Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") Laurent@920: self.PythonCodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") Laurent@920: Laurent@920: Laurent@920: self.PythonCodeEditor.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) Laurent@920: self.PythonCodeEditor.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) Laurent@920: self.PythonCodeEditor.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) laurent@366: laurent@366: # Global default style laurent@366: if wx.Platform == '__WXMSW__': Laurent@920: self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier New') laurent@366: elif wx.Platform == '__WXMAC__': laurent@366: # TODO: if this looks fine on Linux too, remove the Mac-specific case laurent@366: # and use this whenever OS != MSW. Laurent@920: self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Monaco') laurent@366: else: laurent@366: defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize() Laurent@920: self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize) laurent@366: laurent@366: # Clear styles and revert to default. Laurent@920: self.PythonCodeEditor.StyleClearAll() laurent@366: laurent@366: # Following style specs only indicate differences from default. laurent@366: # The rest remains unchanged. laurent@366: laurent@366: # Line numbers in margin Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') laurent@366: # Highlighted brace Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') laurent@366: # Unmatched brace Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') laurent@366: # Indentation guide Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") laurent@366: laurent@366: # Python styles Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') laurent@366: # Comments Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') laurent@366: # Numbers Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') laurent@366: # Strings and characters Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') laurent@366: # Keywords Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') laurent@366: # Triple quotes Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') laurent@366: # Class names Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') laurent@366: # Function names Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') laurent@366: # Operators Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold') laurent@366: # Identifiers. I leave this as not bold because everything seems laurent@366: # to be an identifier if it doesn't match the above criterae Laurent@920: self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') laurent@366: laurent@366: # Caret color Laurent@920: self.PythonCodeEditor.SetCaretForeground("BLUE") laurent@366: # Selection background Laurent@920: self.PythonCodeEditor.SetSelBackground(1, '#66CCFF') Laurent@920: Laurent@920: self.PythonCodeEditor.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) Laurent@920: self.PythonCodeEditor.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) laurent@366: laurent@366: # register some images for use in the AutoComplete box. laurent@366: #self.RegisterImage(1, images.getSmilesBitmap()) Laurent@920: self.PythonCodeEditor.RegisterImage(1, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) Laurent@920: self.PythonCodeEditor.RegisterImage(2, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) Laurent@920: self.PythonCodeEditor.RegisterImage(3, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) laurent@366: laurent@366: # Indentation and tab stuff Laurent@920: self.PythonCodeEditor.SetIndent(4) # Proscribed indent size for wx Laurent@920: self.PythonCodeEditor.SetIndentationGuides(True) # Show indent guides Laurent@920: self.PythonCodeEditor.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space Laurent@920: self.PythonCodeEditor.SetTabIndents(True) # Tab key indents Laurent@920: self.PythonCodeEditor.SetTabWidth(4) # Proscribed tab size for wx Laurent@920: self.PythonCodeEditor.SetUseTabs(False) # Use spaces rather than tabs, or laurent@366: # TabTimmy will complain! laurent@366: # White space Laurent@920: self.PythonCodeEditor.SetViewWhiteSpace(False) # Don't view white space laurent@366: laurent@366: # EOL: Since we are loading/saving ourselves, and the laurent@366: # strings will always have \n's in them, set the STC to laurent@366: # edit them that way. Laurent@920: self.PythonCodeEditor.SetEOLMode(wx.stc.STC_EOL_LF) Laurent@920: self.PythonCodeEditor.SetViewEOL(False) laurent@366: laurent@366: # No right-edge mode indicator Laurent@920: self.PythonCodeEditor.SetEdgeMode(stc.STC_EDGE_NONE) Laurent@920: Laurent@920: self.PythonCodeEditor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) Laurent@920: Laurent@920: self.PythonCodeEditor.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR) Laurent@920: self.PythonCodeEditor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) Laurent@920: self.PythonCodeEditor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_PYTHONEDITOR) Laurent@920: Laurent@920: return self.PythonCodeEditor laurent@657: laurent@657: def __init__(self, parent, controler, window): laurent@743: ConfTreeNodeEditor.__init__(self, parent, controler, window) laurent@657: laurent@657: self.DisableEvents = False laurent@366: self.CurrentAction = None laurent@657: laurent@657: def GetBufferState(self): laurent@657: return self.Controler.GetBufferState() laurent@657: laurent@657: def Undo(self): laurent@657: self.Controler.LoadPrevious() laurent@657: self.RefreshView() laurent@657: laurent@657: def Redo(self): laurent@657: self.Controler.LoadNext() laurent@657: self.RefreshView() laurent@657: laurent@366: def OnModification(self, event): laurent@366: if not self.DisableEvents: laurent@366: mod_type = event.GetModificationType() laurent@366: if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): laurent@366: if mod_type&wx.stc.STC_MOD_BEFOREINSERT: laurent@657: if self.CurrentAction is None: laurent@366: self.StartBuffering() laurent@366: elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1: laurent@366: self.Controler.EndBuffering() laurent@366: self.StartBuffering() laurent@366: self.CurrentAction = ("Add", event.GetPosition()) laurent@657: wx.CallAfter(self.RefreshModel) laurent@366: elif mod_type&wx.stc.STC_MOD_BEFOREDELETE: laurent@366: if self.CurrentAction == None: laurent@366: self.StartBuffering() laurent@366: elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1: laurent@366: self.Controler.EndBuffering() laurent@366: self.StartBuffering() laurent@366: self.CurrentAction = ("Delete", event.GetPosition()) laurent@657: wx.CallAfter(self.RefreshModel) laurent@366: event.Skip() laurent@366: laurent@366: def OnDoDrop(self, event): laurent@366: self.ResetBuffer() laurent@366: wx.CallAfter(self.RefreshModel) laurent@366: event.Skip() laurent@366: laurent@366: # Buffer the last model state laurent@366: def RefreshBuffer(self): laurent@366: self.Controler.BufferPython() laurent@657: if self.ParentWindow is not None: laurent@366: self.ParentWindow.RefreshTitle() laurent@534: self.ParentWindow.RefreshFileMenu() laurent@366: self.ParentWindow.RefreshEditMenu() laurent@657: self.ParentWindow.RefreshPageTitles() laurent@366: laurent@366: def StartBuffering(self): laurent@366: self.Controler.StartBuffering() laurent@657: if self.ParentWindow is not None: laurent@366: self.ParentWindow.RefreshTitle() laurent@534: self.ParentWindow.RefreshFileMenu() laurent@366: self.ParentWindow.RefreshEditMenu() laurent@657: self.ParentWindow.RefreshPageTitles() laurent@366: laurent@366: def ResetBuffer(self): laurent@366: if self.CurrentAction != None: laurent@366: self.Controler.EndBuffering() laurent@366: self.CurrentAction = None laurent@366: laurent@366: def RefreshView(self): laurent@751: ConfTreeNodeEditor.RefreshView(self) laurent@751: laurent@366: self.ResetBuffer() laurent@366: self.DisableEvents = True Laurent@920: old_cursor_pos = self.PythonCodeEditor.GetCurrentPos() Laurent@920: old_text = self.PythonCodeEditor.GetText() laurent@366: new_text = self.Controler.GetPythonCode() Laurent@920: self.PythonCodeEditor.SetText(new_text) laurent@366: new_cursor_pos = GetCursorPos(old_text, new_text) laurent@366: if new_cursor_pos != None: Laurent@920: self.PythonCodeEditor.GotoPos(new_cursor_pos) Laurent@920: else: Laurent@920: self.PythonCodeEditor.GotoPos(old_cursor_pos) Laurent@920: self.PythonCodeEditor.ScrollToColumn(0) Laurent@920: self.PythonCodeEditor.EmptyUndoBuffer() laurent@366: self.DisableEvents = False laurent@366: Laurent@920: self.PythonCodeEditor.Colourise(0, -1) laurent@366: laurent@366: def RefreshModel(self): Laurent@920: self.Controler.SetPythonCode(self.PythonCodeEditor.GetText()) laurent@366: laurent@366: def OnKeyPressed(self, event): Laurent@920: if self.PythonCodeEditor.CallTipActive(): Laurent@920: self.PythonCodeEditor.CallTipCancel() laurent@366: key = event.GetKeyCode() laurent@366: laurent@366: if key == 32 and event.ControlDown(): Laurent@920: pos = self.PythonCodeEditor.GetCurrentPos() laurent@738: laurent@366: # Code completion laurent@738: if not event.ShiftDown(): Laurent@920: self.PythonCodeEditor.AutoCompSetIgnoreCase(False) # so this needs to match laurent@366: laurent@366: # Images are specified with a appended "?type" Laurent@920: self.PythonCodeEditor.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist])) laurent@366: else: laurent@366: event.Skip() laurent@366: laurent@366: def OnKillFocus(self, event): Laurent@920: self.PythonCodeEditor.AutoCompCancel() laurent@366: event.Skip() laurent@366: laurent@366: def OnUpdateUI(self, evt): laurent@366: # check for matching braces laurent@366: braceAtCaret = -1 laurent@366: braceOpposite = -1 laurent@366: charBefore = None Laurent@920: caretPos = self.PythonCodeEditor.GetCurrentPos() laurent@366: laurent@366: if caretPos > 0: Laurent@920: charBefore = self.PythonCodeEditor.GetCharAt(caretPos - 1) Laurent@920: styleBefore = self.PythonCodeEditor.GetStyleAt(caretPos - 1) laurent@366: laurent@366: # check before laurent@366: if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: laurent@366: braceAtCaret = caretPos - 1 laurent@366: laurent@366: # check after laurent@366: if braceAtCaret < 0: Laurent@920: charAfter = self.PythonCodeEditor.GetCharAt(caretPos) Laurent@920: styleAfter = self.PythonCodeEditor.GetStyleAt(caretPos) laurent@366: laurent@366: if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: laurent@366: braceAtCaret = caretPos laurent@366: laurent@366: if braceAtCaret >= 0: Laurent@920: braceOpposite = self.PythonCodeEditor.BraceMatch(braceAtCaret) laurent@366: laurent@366: if braceAtCaret != -1 and braceOpposite == -1: Laurent@920: self.PythonCodeEditor.BraceBadLight(braceAtCaret) Laurent@920: else: Laurent@920: self.PythonCodeEditor.BraceHighlight(braceAtCaret, braceOpposite) laurent@366: laurent@366: def OnMarginClick(self, evt): laurent@366: # fold and unfold as needed laurent@366: if evt.GetMargin() == 2: laurent@366: if evt.GetShift() and evt.GetControl(): laurent@366: self.FoldAll() laurent@366: else: Laurent@920: lineClicked = self.PythonCodeEditor.LineFromPosition(evt.GetPosition()) Laurent@920: Laurent@920: if self.PythonCodeEditor.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: if evt.GetShift(): Laurent@920: self.PythonCodeEditor.SetFoldExpanded(lineClicked, True) laurent@366: self.Expand(lineClicked, True, True, 1) laurent@366: elif evt.GetControl(): Laurent@920: if self.PythonCodeEditor.GetFoldExpanded(lineClicked): Laurent@920: self.PythonCodeEditor.SetFoldExpanded(lineClicked, False) laurent@366: self.Expand(lineClicked, False, True, 0) laurent@366: else: Laurent@920: self.PythonCodeEditor.SetFoldExpanded(lineClicked, True) laurent@366: self.Expand(lineClicked, True, True, 100) laurent@366: else: Laurent@920: self.PythonCodeEditor.ToggleFold(lineClicked) laurent@366: laurent@366: laurent@366: def FoldAll(self): Laurent@920: lineCount = self.PythonCodeEditor.GetLineCount() laurent@366: expanding = True laurent@366: laurent@366: # find out if we are folding or unfolding laurent@366: for lineNum in range(lineCount): Laurent@920: if self.PythonCodeEditor.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: Laurent@920: expanding = not self.PythonCodeEditor.GetFoldExpanded(lineNum) laurent@366: break laurent@366: laurent@366: lineNum = 0 laurent@366: laurent@366: while lineNum < lineCount: Laurent@920: level = self.PythonCodeEditor.GetFoldLevel(lineNum) laurent@366: if level & stc.STC_FOLDLEVELHEADERFLAG and \ laurent@366: (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: laurent@366: laurent@366: if expanding: Laurent@920: self.PythonCodeEditor.SetFoldExpanded(lineNum, True) laurent@366: lineNum = self.Expand(lineNum, True) laurent@366: lineNum = lineNum - 1 laurent@366: else: Laurent@920: lastChild = self.PythonCodeEditor.GetLastChild(lineNum, -1) Laurent@920: self.PythonCodeEditor.SetFoldExpanded(lineNum, False) laurent@366: laurent@366: if lastChild > lineNum: Laurent@920: self.PythonCodeEditor.HideLines(lineNum+1, lastChild) laurent@366: laurent@366: lineNum = lineNum + 1 laurent@366: laurent@366: laurent@366: laurent@366: def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): Laurent@920: lastChild = self.PythonCodeEditor.GetLastChild(line, level) laurent@366: line = line + 1 laurent@366: laurent@366: while line <= lastChild: laurent@366: if force: laurent@366: if visLevels > 0: Laurent@920: self.PythonCodeEditor.ShowLines(line, line) laurent@366: else: Laurent@920: self.PythonCodeEditor.HideLines(line, line) laurent@366: else: laurent@366: if doExpand: Laurent@920: self.PythonCodeEditor.ShowLines(line, line) laurent@366: laurent@366: if level == -1: Laurent@920: level = self.PythonCodeEditor.GetFoldLevel(line) laurent@366: laurent@366: if level & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: if force: laurent@366: if visLevels > 1: Laurent@920: self.PythonCodeEditor.SetFoldExpanded(line, True) laurent@366: else: Laurent@920: self.PythonCodeEditor.SetFoldExpanded(line, False) laurent@366: laurent@366: line = self.Expand(line, doExpand, force, visLevels-1) laurent@366: laurent@366: else: Laurent@920: if doExpand and self.PythonCodeEditor.GetFoldExpanded(line): laurent@366: line = self.Expand(line, True, force, visLevels-1) laurent@366: else: laurent@366: line = self.Expand(line, False, force, visLevels-1) laurent@366: else: laurent@366: line = line + 1 laurent@366: laurent@366: return line laurent@657: laurent@657: def Cut(self): laurent@657: self.ResetBuffer() laurent@657: self.DisableEvents = True Laurent@920: self.PythonCodeEditor.CmdKeyExecute(wx.stc.STC_CMD_CUT) laurent@657: self.DisableEvents = False laurent@657: self.RefreshModel() laurent@657: self.RefreshBuffer() laurent@657: laurent@657: def Copy(self): Laurent@920: self.PythonCodeEditor.CmdKeyExecute(wx.stc.STC_CMD_COPY) laurent@657: laurent@657: def Paste(self): laurent@657: self.ResetBuffer() laurent@657: self.DisableEvents = True Laurent@920: self.PythonCodeEditor.CmdKeyExecute(wx.stc.STC_CMD_PASTE) laurent@657: self.DisableEvents = False laurent@657: self.RefreshModel() laurent@657: self.RefreshBuffer()