laurent@366: import wx, wx.grid laurent@366: import wx.stc as stc laurent@366: import keyword laurent@366: 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: def AppendMenu(parent, help, id, kind, text): laurent@366: if wx.VERSION >= (2, 6, 0): laurent@366: parent.Append(help=help, id=id, kind=kind, text=text) laurent@366: else: laurent@366: parent.Append(helpString=help, id=id, kind=kind, item=text) 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@366: class PythonEditor(stc.StyledTextCtrl): laurent@366: laurent@366: fold_symbols = 3 laurent@366: laurent@366: def __init__(self, parent, window, controler): laurent@366: stc.StyledTextCtrl.__init__(self, parent, ID_PYTHONEDITOR, wx.DefaultPosition, laurent@366: wx.DefaultSize, 0) laurent@366: laurent@366: self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) laurent@366: self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) laurent@366: laurent@366: self.SetLexer(stc.STC_LEX_PYTHON) laurent@366: self.SetKeyWords(0, " ".join(keyword.kwlist)) laurent@366: laurent@366: self.SetProperty("fold", "1") laurent@366: self.SetProperty("tab.timmy.whinge.level", "1") laurent@366: self.SetMargins(0,0) laurent@366: laurent@366: self.SetViewWhiteSpace(False) laurent@366: #self.SetBufferedDraw(False) laurent@366: #self.SetViewEOL(True) laurent@366: #self.SetEOLMode(stc.STC_EOL_CRLF) laurent@366: #self.SetUseAntiAliasing(True) laurent@366: laurent@366: self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) laurent@366: self.SetEdgeColumn(78) laurent@366: laurent@366: # Set up the numbers in the margin for margin #1 laurent@366: self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) laurent@366: # Reasonable value for, say, 4-5 digits using a mono font (40 pix) laurent@366: self.SetMarginWidth(1, 40) laurent@366: laurent@366: # Setup a margin to hold fold markers laurent@366: self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) laurent@366: self.SetMarginMask(2, stc.STC_MASK_FOLDERS) laurent@366: self.SetMarginSensitive(2, True) laurent@366: self.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@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") laurent@366: self.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@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") laurent@366: self.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@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") laurent@366: self.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@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") laurent@366: self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") laurent@366: laurent@366: laurent@366: self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) laurent@366: self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) laurent@366: self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) laurent@366: laurent@366: # Global default style laurent@366: if wx.Platform == '__WXMSW__': laurent@366: self.StyleSetSpec(stc.STC_STYLE_DEFAULT, laurent@366: '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@366: self.StyleSetSpec(stc.STC_STYLE_DEFAULT, laurent@366: 'fore:#000000,back:#FFFFFF,face:Monaco') laurent@366: else: laurent@366: defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize() laurent@366: self.StyleSetSpec(stc.STC_STYLE_DEFAULT, laurent@366: 'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize) laurent@366: laurent@366: # Clear styles and revert to default. laurent@366: self.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@366: self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') laurent@366: # Highlighted brace laurent@366: self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') laurent@366: # Unmatched brace laurent@366: self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') laurent@366: # Indentation guide laurent@366: self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") laurent@366: laurent@366: # Python styles laurent@366: self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') laurent@366: # Comments laurent@366: self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') laurent@366: self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') laurent@366: # Numbers laurent@366: self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') laurent@366: # Strings and characters laurent@366: self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') laurent@366: self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') laurent@366: # Keywords laurent@366: self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') laurent@366: # Triple quotes laurent@366: self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') laurent@366: self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') laurent@366: # Class names laurent@366: self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') laurent@366: # Function names laurent@366: self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') laurent@366: # Operators laurent@366: self.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@366: self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') laurent@366: laurent@366: # Caret color laurent@366: self.SetCaretForeground("BLUE") laurent@366: # Selection background laurent@366: self.SetSelBackground(1, '#66CCFF') laurent@366: laurent@366: self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) laurent@366: self.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@366: self.RegisterImage(1, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) laurent@366: self.RegisterImage(2, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) laurent@366: self.RegisterImage(3, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) laurent@366: laurent@366: # Indentation and tab stuff laurent@366: self.SetIndent(4) # Proscribed indent size for wx laurent@366: self.SetIndentationGuides(True) # Show indent guides laurent@366: self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space laurent@366: self.SetTabIndents(True) # Tab key indents laurent@366: self.SetTabWidth(4) # Proscribed tab size for wx laurent@366: self.SetUseTabs(False) # Use spaces rather than tabs, or laurent@366: # TabTimmy will complain! laurent@366: # White space laurent@366: self.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@366: self.SetEOLMode(wx.stc.STC_EOL_LF) laurent@366: self.SetViewEOL(False) laurent@366: laurent@366: # No right-edge mode indicator laurent@366: self.SetEdgeMode(stc.STC_EDGE_NONE) laurent@366: laurent@366: self.Controler = controler laurent@366: self.ParentWindow = window laurent@366: laurent@366: self.DisableEvents = True laurent@366: self.CurrentAction = None laurent@366: laurent@366: self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) laurent@366: laurent@366: self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR) laurent@366: self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) laurent@366: self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_PYTHONEDITOR) laurent@366: 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@366: if self.CurrentAction == 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@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@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: def IsViewing(self, name): laurent@366: return self.Name == name laurent@366: laurent@366: # Buffer the last model state laurent@366: def RefreshBuffer(self): laurent@366: self.Controler.BufferPython() laurent@366: if self.ParentWindow: laurent@366: self.ParentWindow.RefreshTitle() laurent@534: self.ParentWindow.RefreshFileMenu() laurent@366: self.ParentWindow.RefreshEditMenu() laurent@366: laurent@366: def StartBuffering(self): laurent@366: self.Controler.StartBuffering() laurent@366: if self.ParentWindow: laurent@366: self.ParentWindow.RefreshTitle() laurent@534: self.ParentWindow.RefreshFileMenu() laurent@366: self.ParentWindow.RefreshEditMenu() 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@366: self.ResetBuffer() laurent@366: self.DisableEvents = True laurent@366: old_cursor_pos = self.GetCurrentPos() laurent@366: old_text = self.GetText() laurent@366: new_text = self.Controler.GetPythonCode() laurent@366: self.SetText(new_text) laurent@366: new_cursor_pos = GetCursorPos(old_text, new_text) laurent@366: if new_cursor_pos != None: laurent@366: self.GotoPos(new_cursor_pos) laurent@366: else: laurent@366: self.GotoPos(old_cursor_pos) laurent@366: self.ScrollToColumn(0) laurent@366: self.EmptyUndoBuffer() laurent@366: self.DisableEvents = False laurent@366: laurent@366: self.Colourise(0, -1) laurent@366: laurent@366: def RefreshModel(self): laurent@366: self.Controler.SetPythonCode(self.GetText()) laurent@366: laurent@366: def OnKeyPressed(self, event): laurent@366: if self.CallTipActive(): laurent@366: self.CallTipCancel() laurent@366: key = event.GetKeyCode() laurent@366: laurent@366: if key == 32 and event.ControlDown(): laurent@366: pos = self.GetCurrentPos() laurent@366: laurent@366: # Tips laurent@366: if event.ShiftDown(): laurent@366: pass laurent@366: ## self.CallTipSetBackground("yellow") laurent@366: ## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n' laurent@366: ## 'show some suff, maybe parameters..\n\n' laurent@366: ## 'fubar(param1, param2)') laurent@366: # Code completion laurent@366: else: laurent@366: self.AutoCompSetIgnoreCase(False) # so this needs to match laurent@366: laurent@366: # Images are specified with a appended "?type" laurent@366: self.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist])) laurent@366: else: laurent@366: wx.CallAfter(self.RefreshModel) laurent@366: event.Skip() laurent@366: laurent@366: def OnKillFocus(self, event): laurent@366: self.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@366: caretPos = self.GetCurrentPos() laurent@366: laurent@366: if caretPos > 0: laurent@366: charBefore = self.GetCharAt(caretPos - 1) laurent@366: styleBefore = self.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@366: charAfter = self.GetCharAt(caretPos) laurent@366: styleAfter = self.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@366: braceOpposite = self.BraceMatch(braceAtCaret) laurent@366: laurent@366: if braceAtCaret != -1 and braceOpposite == -1: laurent@366: self.BraceBadLight(braceAtCaret) laurent@366: else: laurent@366: self.BraceHighlight(braceAtCaret, braceOpposite) laurent@366: #pt = self.PointFromPosition(braceOpposite) laurent@366: #self.Refresh(True, wxRect(pt.x, pt.y, 5,5)) laurent@366: #print pt laurent@366: #self.Refresh(False) laurent@366: 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@366: lineClicked = self.LineFromPosition(evt.GetPosition()) laurent@366: laurent@366: if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: if evt.GetShift(): laurent@366: self.SetFoldExpanded(lineClicked, True) laurent@366: self.Expand(lineClicked, True, True, 1) laurent@366: elif evt.GetControl(): laurent@366: if self.GetFoldExpanded(lineClicked): laurent@366: self.SetFoldExpanded(lineClicked, False) laurent@366: self.Expand(lineClicked, False, True, 0) laurent@366: else: laurent@366: self.SetFoldExpanded(lineClicked, True) laurent@366: self.Expand(lineClicked, True, True, 100) laurent@366: else: laurent@366: self.ToggleFold(lineClicked) laurent@366: laurent@366: laurent@366: def FoldAll(self): laurent@366: lineCount = self.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@366: if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: expanding = not self.GetFoldExpanded(lineNum) laurent@366: break laurent@366: laurent@366: lineNum = 0 laurent@366: laurent@366: while lineNum < lineCount: laurent@366: level = self.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@366: self.SetFoldExpanded(lineNum, True) laurent@366: lineNum = self.Expand(lineNum, True) laurent@366: lineNum = lineNum - 1 laurent@366: else: laurent@366: lastChild = self.GetLastChild(lineNum, -1) laurent@366: self.SetFoldExpanded(lineNum, False) laurent@366: laurent@366: if lastChild > lineNum: laurent@366: self.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@366: lastChild = self.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@366: self.ShowLines(line, line) laurent@366: else: laurent@366: self.HideLines(line, line) laurent@366: else: laurent@366: if doExpand: laurent@366: self.ShowLines(line, line) laurent@366: laurent@366: if level == -1: laurent@366: level = self.GetFoldLevel(line) laurent@366: laurent@366: if level & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: if force: laurent@366: if visLevels > 1: laurent@366: self.SetFoldExpanded(line, True) laurent@366: else: laurent@366: self.SetFoldExpanded(line, False) laurent@366: laurent@366: line = self.Expand(line, doExpand, force, visLevels-1) laurent@366: laurent@366: else: laurent@366: if doExpand and self.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@366: laurent@366: laurent@366: #------------------------------------------------------------------------------- laurent@366: # PythonEditor Main Frame Class laurent@366: #------------------------------------------------------------------------------- laurent@366: laurent@366: laurent@366: [ID_PYTHONEDITORFRAME, laurent@366: ] = [wx.NewId() for _init_ctrls in range(1)] laurent@366: laurent@366: class PythonEditorFrame(wx.Frame): laurent@366: laurent@366: if wx.VERSION < (2, 6, 0): laurent@366: def Bind(self, event, function, id = None): laurent@366: if id is not None: laurent@366: event(self, id, function) laurent@366: else: laurent@366: event(self, function) laurent@366: laurent@366: def _init_coll_EditMenu_Items(self, parent): laurent@366: AppendMenu(parent, help='', id=wx.ID_REFRESH, laurent@415: kind=wx.ITEM_NORMAL, text=_(u'Refresh\tCTRL+R')) laurent@366: AppendMenu(parent, help='', id=wx.ID_UNDO, laurent@415: kind=wx.ITEM_NORMAL, text=_(u'Undo\tCTRL+Z')) laurent@366: AppendMenu(parent, help='', id=wx.ID_REDO, laurent@415: kind=wx.ITEM_NORMAL, text=_(u'Redo\tCTRL+Y')) laurent@366: self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH) laurent@366: self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO) laurent@366: self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO) laurent@366: laurent@366: def _init_coll_MenuBar_Menus(self, parent): laurent@415: parent.Append(menu=self.EditMenu, title=_(u'&Edit')) laurent@366: laurent@366: def _init_utils(self): laurent@366: self.MenuBar = wx.MenuBar() laurent@366: laurent@366: self.EditMenu = wx.Menu(title='') laurent@366: laurent@366: self._init_coll_MenuBar_Menus(self.MenuBar) laurent@366: self._init_coll_EditMenu_Items(self.EditMenu) laurent@366: laurent@366: def _init_ctrls(self, prnt): laurent@366: wx.Frame.__init__(self, id=ID_PYTHONEDITORFRAME, name=u'PythonEditor', laurent@366: parent=prnt, pos=wx.DefaultPosition, size=wx.Size(800, 650), laurent@415: style=wx.DEFAULT_FRAME_STYLE, title=_(u'PythonEditor')) laurent@366: self._init_utils() laurent@366: self.SetClientSize(wx.Size(1000, 600)) laurent@366: self.SetMenuBar(self.MenuBar) laurent@366: self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) laurent@366: laurent@366: self.Bind(wx.EVT_MENU, self.OnSaveMenu, id=wx.ID_SAVE) laurent@366: accel = wx.AcceleratorTable([wx.AcceleratorEntry(wx.ACCEL_CTRL, 83, wx.ID_SAVE)]) laurent@366: self.SetAcceleratorTable(accel) laurent@366: laurent@366: if wx.VERSION >= (2, 8, 0): laurent@366: self.AUIManager = wx.aui.AuiManager(self) laurent@366: self.AUIManager.SetDockSizeConstraint(0.5, 0.5) laurent@366: laurent@366: self.PythonEdited = PythonEditor(self, self, self.Controler) laurent@366: if wx.VERSION < (2, 8, 0): laurent@366: self.MainSizer = wx.BoxSizer(wx.VERTICAL) laurent@366: self.MainSizer.AddWindow(self.PythonEdited, 0, border=0, flag=wx.GROW) laurent@366: self.SetSizer(self.MainSizer) laurent@366: else: laurent@366: self.AUIManager.AddPane(self.PythonEdited, wx.aui.AuiPaneInfo().CentrePane()) laurent@366: laurent@366: self.StatusBar = wx.StatusBar( name='HelpBar', laurent@366: parent=self, style=wx.ST_SIZEGRIP) laurent@366: self.SetStatusBar(self.StatusBar) laurent@366: laurent@366: if wx.VERSION >= (2, 8, 0): laurent@366: self.AUIManager.Update() laurent@366: laurent@366: def __init__(self, parent, controler): laurent@366: self.Controler = controler laurent@366: laurent@366: self._init_ctrls(parent) laurent@366: laurent@366: self.PythonEdited.RefreshView() laurent@366: self.RefreshTitle() laurent@366: self.RefreshEditMenu() laurent@366: laurent@366: def OnCloseFrame(self, event): laurent@366: if wx.VERSION >= (2, 8, 0): laurent@366: self.AUIManager.UnInit() laurent@366: if getattr(self, "_onclose", None) is not None: laurent@366: self._onclose() laurent@366: event.Skip() laurent@366: laurent@366: def OnSaveMenu(self, event): laurent@366: if getattr(self, "_onsave", None) != None: laurent@366: self._onsave() laurent@366: self.RefreshTitle() laurent@366: self.RefreshEditMenu() laurent@366: laurent@366: def RefreshTitle(self): laurent@415: title = _("PythonEditor") laurent@415: self.SetTitle("%s - %s"%(title, self.Controler.GetFilename())) laurent@366: laurent@366: #------------------------------------------------------------------------------- laurent@366: # Edit Project Menu Functions laurent@366: #------------------------------------------------------------------------------- laurent@366: laurent@654: def RefreshFileMenu(self): laurent@654: pass laurent@654: laurent@366: def RefreshEditMenu(self): laurent@366: undo, redo = self.Controler.GetBufferState() laurent@366: self.EditMenu.Enable(wx.ID_UNDO, undo) laurent@366: self.EditMenu.Enable(wx.ID_REDO, redo) laurent@366: laurent@366: def OnRefreshMenu(self, event): laurent@366: self.PythonEdited.RefreshView() laurent@366: laurent@366: def OnUndoMenu(self, event): laurent@366: self.Controler.LoadPrevious() laurent@366: self.PythonEdited.RefreshView() laurent@366: self.RefreshTitle() laurent@366: self.RefreshEditMenu() laurent@366: laurent@366: def OnRedoMenu(self, event): laurent@366: self.Controler.LoadNext() laurent@366: self.PythonEdited.RefreshView() laurent@366: self.RefreshTitle() laurent@366: self.RefreshEditMenu() greg@427: greg@427: