def OnHelpViewer(self, event=None, topic=None, topic_str=None, pos=None): """ topic: object topic_str: string that can be evaluated to get topic object pos: With topic_str, the pos argument can be used to search for a Python object name within topic_str. When the user asks for help in the shell or editor, the topic_str is the current line and pos is the caret position. """ if self.help_viewer: if self.help_viewer.IsShown(): self.help_viewer.Raise() else: self.help_viewer.Show(True) else: # x, y, w, h = self.GetRect().Get() x_min, y_min, x_max, y_max = wx.Display().GetGeometry() hx = x_max-650 #min(x + w, x_max-600) hw = 650 hh = y_max-y_min-22 # min(800, y_max-y_min-21) hy = 22 logging.debug("help viewer: size=(%s,%s), pos=(%s,%s)"%(hw,hh,hx,hy)) self.help_viewer = HelpViewer(self, size=(hw,hh), pos=(hx,hy)) self.help_viewer.Show() if topic_str: if pos is not None: # find the python command around pos in the line topic_scan = topic_str.replace('.', 'a') start = pos n_max = len(topic_str) end = min(pos, n_max) while (end < n_max) and is_py_char(topic_scan[end]): end += 1 while is_py_char(topic_scan[start-1]) and start > 0: start -= 1 topic_str = topic_str[start:end] self.help_viewer.text_lookup(topic_str) else: self.help_viewer.Help_Lookup(topic)
class ShellFrame(wx.py.shell.ShellFrame): bufferOpen = 1 # Dummy attr so that py.frame enables Open menu bufferNew = 1 # same for New menu # bufferClose = 1 def __init__(self, parent, namespace, *args, **kwargs): app = wx.GetApp() # --- set up PREFERENCES --- # http://wiki.wxpython.org/FileHistory self.wx_config = wx.Config("eelbrain", style=wx.CONFIG_USE_LOCAL_FILE) """ Options ------- use: config.Read(name, default_value) config.Write(name, value) """ self.filehistory = wx.FileHistory(10) self.filehistory.Load(self.wx_config) # stdp = wx.StandardPaths.Get() # pref_p = wx.StandardPaths.GetUserConfigDir(stdp) # SHELL initialization # put my Shell into wx.py.shell and init wx.py.shell.Shell = Shell kwargs.update(locals=namespace, title='Eelbrain Shell') # if "wxMac" not in wx.PlatformInfo: # del self.bufferClose dataDir = self.wx_config.Read("dataDir") #os.path.expanduser('~/Documents/eelbrain') if os.path.exists(dataDir): kwargs['dataDir'] = dataDir wx.py.shell.ShellFrame.__init__(self, parent, *args, **kwargs) self.SetStatusText('Eelbrain %s' % __version__) droptarget.set_for_strings(self.shell) # config # stdout = wx.py.shell.PseudoFileOut(self.shell_message) # wx.py.shell.sys.stdout = stdout # sys.stdout = stdout # self.shell.stdout = stdout # self.shell.autoCompleteIncludeSingle = False # self.shell.autoCompleteIncludeDouble = False # self.shell.autoCompleteIncludeMagic = True # attr self.global_namespace = namespace self.editors = [] self.active_editor = None # editor last used; updated by Editor.OnActivate and Editor.__init__ self.tables = [] self.experiments = [] # keep track of ExperimentFrames self._attached_items = {} self.help_viewer = None # child windows x_min, y_min, x_max, y_max = wx.Display().GetGeometry() self.P_mgr = mpl_tools.PyplotManager(self, pos=(x_max-100, y_min+22+4)) # --- MENUS --- # menus first defined in wx.py.frame.Frame.__createMenus() menus = dict((self.menuBar.GetMenuLabel(i), i) for i in xrange(self.menuBar.GetMenuCount())) # recent menu recent_menu = self.recent_menu = wx.Menu() self.filehistory.UseMenu(recent_menu) self.filehistory.AddFilesToMenu() # add icons self.recent_menu_update_icons() self.Bind(wx.EVT_MENU_RANGE, self.OnRecentItemLoad, id=wx.ID_FILE1, id2=wx.ID_FILE9) # add menu item (can only add it to one menu apparently) help_txt = "Load an experiment or Python script from a list of recently used items" self.fileMenu.InsertMenu(0, wx.ID_ANY, 'Recent Files', recent_menu, help_txt) # self.menuBar.Insert(menus['&Edit'], recent_menu, 'Recent') # NOTE this messes up other menu insertion points (-> line 377) # menus['&Help'] += 1 # preferences menu if wx.Platform == '__WXMAC__': ID_PREFERENCES = app.GetMacPreferencesMenuItemId() else: # although these seem to be the same -- 5022 ID_PREFERENCES = wx.ID_PREFERENCES self.optionsMenu.Append(ID_PREFERENCES, "&Preferences...\tCtrl+,") self.Bind(wx.EVT_MENU, self.OnPreferences, id=wx.ID_PREFERENCES) # WINDOW MENU m = self.windowMenu = wx.Menu()#"&Window") m.SetTitle("&Window") # name is used below in OnOpenWindowMenu to recognize Window menu self.Bind(wx.EVT_MENU_OPEN, self.OnOpenWindowMenu) m.Append(ID.P_MGR, "Pyplot Manager", "Toggle Pyplot Manager Panel.")#, wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.OnTogglePyplotMgr, id=ID.P_MGR) m.Append(ID.PYPLOT_CLOSEALL, "Close All Plots", "Closes all Matplotlib plots.") self.Bind(wx.EVT_MENU, self.OnP_CloseAll, id=ID.PYPLOT_CLOSEALL) # shell resizing m.AppendSeparator() m.Append(ID.SHELL_Maximize, 'Maximize Shell', "Expand the Shell to use the full screen height.") self.Bind(wx.EVT_MENU, self.OnResize_Max, id=ID.SHELL_Maximize) m.Append(ID.SHELL_HalfScreen, 'Half Screen Shell', "Expand Shell to use the left half of the screen") self.Bind(wx.EVT_MENU, self.OnResize_HalfScreen, id=ID.SHELL_HalfScreen) m.Append(ID.SHELL_Window, 'Window Shell', "Resize the Shell to window with standard width.") self.Bind(wx.EVT_MENU, self.OnResize_Win, id=ID.SHELL_Window) m.Append(ID.SHELL_Mini, 'Mini-Shell', "Resize the Shell to a small " "window (e.g. for use as pocket calculator).") self.Bind(wx.EVT_MENU, self.OnResize_Min, id=ID.SHELL_Mini) # section with all open windows m.AppendSeparator() item = m.Append(self.GetId(), "Shell", "Bring shell to the front.") self.Bind(wx.EVT_MENU, self.OnWindowMenuActivateWindow, item) self.windowMenuWindows = {self.GetId(): self} self.windowMenuMenuItems = {} # this can be done with edit->empty buffer # m.AppendSeparator() # m.Append(ID.SHELL_Clear, 'Clear Shell', # "Clear all the Text in the Shell") # self.Bind(wx.EVT_MENU, self.OnClear, id=ID.SHELL_Clear) logging.debug(str(menus)) self.menuBar.Insert(menus['&Help'], m, 'Window') # INSERT MENU m = self.insertMenu = wx.Menu() m.Append(ID.INSERT_Color, "Color", "Insert color as (r, g, b)-tuple.") # self.Bind(wx.EVT_MENU, self.OnInsertColor, id=ID.INSERT_Color) # this function only works for the colorpicker linked to the button # path submenu m = self.pathMenu = wx.Menu() m.Append(ID.INSERT_Path_file, "File", "Insert path to an existing File (You can also simply " "drag a file on the shell or an editor).") m.Append(ID.INSERT_Path_dir, "Directory", "Insert path to an existing Directory (You can also " "simply drag a file on the shell or an editor).") m.Append(ID.INSERT_Path_new, "New", "Insert path to a non-existing object.") self.insertMenu.AppendSubMenu(m, "Path", "Insert a path as string.") self.menuBar.Insert(menus['&View'], self.insertMenu, "Insert") self.Bind(wx.EVT_MENU, self.OnInsertPath_File, id=ID.INSERT_Path_file) self.Bind(wx.EVT_MENU, self.OnInsertPath_Dir, id=ID.INSERT_Path_dir) self.Bind(wx.EVT_MENU, self.OnInsertPath_New, id=ID.INSERT_Path_new) # HELP menu self.helpMenu.AppendSeparator() self.helpMenu.Append(ID.HELP_PYTHON, "Python (web)", "Open the official Python documentation page in an external browser.") self.Bind(wx.EVT_MENU, self.OnHelpExternal, id=ID.HELP_PYTHON) self.helpMenu.Append(ID.HELP_MPL, "Matplotlib (web)", "Open the Matplotlib homepage in an external browser.") self.Bind(wx.EVT_MENU, self.OnHelpExternal, id=ID.HELP_MPL) self.helpMenu.Append(ID.HELP_MDP, "mdp (web)", "Open the mdp Documentation page in an external browser.") self.Bind(wx.EVT_MENU, self.OnHelpExternal, id=ID.HELP_MDP) # --- TOOLBAR --- tb = self.CreateToolBar(wx.TB_HORIZONTAL) tb.SetToolBitmapSize(size=wx.Size(32,32)) # windows/tools tb.AddLabelTool(wx.ID_HELP, "Help", Icon("tango/apps/help-browser"), shortHelp="Open the Help-Viewer", longHelp="Open the Help-Viewer") self.Bind(wx.EVT_TOOL, self.OnHelpViewer, id=wx.ID_HELP) tb.AddLabelTool(ID.P_MGR, "Pyplot Manager", Icon("tango/mimetypes/x-office-presentation"), shortHelp="Toggle display of the Pyplot manager tool") self.Bind(wx.EVT_TOOL, self.OnTogglePyplotMgr, id=ID.P_MGR) tb.AddSeparator() # File Operations tb.AddLabelTool(wx.ID_OPEN, "Load", Icon("tango/actions/document-open"), shortHelp="Load " "a Python document (*.py)") tb.AddLabelTool(ID.PYDOC_EXEC, "Exec", Icon("documents/pydoc-openrun"), shortHelp="Run an existing Python script (without " "opening it in an editor)") self.Bind(wx.EVT_TOOL, self.OnExecFile, id=ID.PYDOC_EXEC) # tb.AddLabelTool(ID.EXPERIMENT_NEW, "New", Icon("documents/experiment-new"), # shortHelp="Create a new experiment") # self.Bind(wx.EVT_TOOL, self.OnNewExperiment, id=ID.EXPERIMENT_NEW) tb.AddLabelTool(wx.ID_NEW, "New .Py Document", Icon("documents/pydoc-new"), shortHelp="Open a new Python script editor") tb.AddLabelTool(ID.TABLE, "Table", Icon("documents/table"), shortHelp="Open a new table") self.Bind(wx.EVT_TOOL, self.OnTableNew, id=ID.TABLE) tb.AddSeparator() # inserting (these controls have no shortHelp) fn_ctrl = wx.Choice(tb, wx.ID_FIND, (100,50), choices=['File', 'Dir', 'New']) self.Bind(wx.EVT_CHOICE, self.OnInsertPath, id=wx.ID_FIND) tb.AddControl(fn_ctrl) b = wx.lib.colourselect.ColourSelect(tb, -1, "Color", (0, 255, 0), size=wx.DefaultSize) b.Bind(wx.lib.colourselect.EVT_COLOURSELECT, self.OnInsertColor) self.color_selector = b # bind the 'insert color' menu entry self.Bind(wx.EVT_MENU, self.color_selector.Command, id=ID.INSERT_Color) tb.AddControl(b) #tb.AddLabelTool(ID.COLOUR_CHOOSER, "Color", Icon('apps.preferences-desktop-locale')) #self.Bind(wx.EVT_TOOL, self.OnSelectColourAlt, id=ID.COLOUR_CHOOSER) if wx.__version__ >= '2.9': tb.AddStretchableSpace() else: tb.AddSeparator() # TODO: clear only the last command + output tb.AddLabelTool(ID.CLEAR_TERMINAL, "Clear Text", Icon("tango/actions/edit-clear"), shortHelp="Clear all text from the terminal") self.Bind(wx.EVT_TOOL, self.OnClearTerminal, id=ID.CLEAR_TERMINAL) tb.AddLabelTool(wx.ID_EXIT, "Quit", Icon("tango/actions/system-log-out"), shortHelp="Quit eelbrain") self.Bind(wx.EVT_TOOL, self.OnQuit, id=wx.ID_EXIT) tb.Realize() # --- Finalize --- # add commands to the shell self.global_namespace['attach'] = self.attach self.global_namespace['detach'] = self.detach self.global_namespace['help'] = self.help_lookup self.global_namespace['printdict'] = print_funcs.printdict self.global_namespace['printlist'] = print_funcs.printlist # other Bindings self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize) self.Bind(wx.EVT_ACTIVATE, self.OnActivate) self.shell.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) # my shell customization self.SetColours(self.shell) self.OnResize_HalfScreen(None) # icon if sys.platform != 'darwin': self.eelbrain_icon = Icon('eelbrain', asicon=True) self.SetIcon(self.eelbrain_icon) self.Bind(wx.EVT_CLOSE, self.OnDestroyIcon) # add help text from wx.py.shell text = wx.py.shell.HELP_TEXT self.__doc__ = text def OnAbout(self, event): """Display an About window.""" about = about_dialog.AboutFrame(self) if wx.__version__ >= '2.9': about.ShowWithEffect(wx.SHOW_EFFECT_BLEND) else: about.Show() about.SetFocus() return about def OnActivate(self, event=None): #logging.debug(" Shell Activate Event: {0}".format(event.Active)) if hasattr(self.shell, 'Destroy'): # if alive if event.Active: self.shell.SetCaretForeground(wx.Colour(255,0,0)) self.shell.SetCaretPeriod(500) else: self.shell.SetCaretForeground(wx.Colour(200,200,200)) self.shell.SetCaretPeriod(0) # ATTACHING--- def attach(self, dictionary): """ Adds a dictionary to the globals and keeps track of the items so that they can be removed safely with the detach function. """ # self._attached_items = {id(dict_like) -> {key -> value}} present = [] for k in dictionary: if k in self.global_namespace: if id(self.global_namespace[k]) != id(dictionary[k]): present.append(k) if present: title = "Overwrite Items?" message = ("The following items are associated with different " "objects in global namespace. Should we replace them?" + os.linesep) message = os.linesep.join((message, ', '.join(repr(k) for k in present))) answer = ui.ask(title, message, True) if answer is None: return elif answer: attach = dictionary else: attach = dict((k,v) for k,v in dictionary.iteritems() if k not in present) else: attach = dictionary self.global_namespace.update(attach) items = self._attached_items.setdefault(id(dictionary), {}) items.update(attach) msg = "attached: %s" % str(attach.keys()) print msg def detach(self, dictionary=None): """ Removes the contents of `dictionary` from the global namespace. Neither the item itself is removed, nor are any references that were not created through the :func:`attach` function. `dictionary`: dict-like Dictionary which to detach; `None`: detach everything """ if dictionary is None: dIDs = self._attached_items.keys() else: dIDs = [id(dictionary)] detach = {} for dID in dIDs: detach.update(self._attached_items.pop(dID)) for k,v in detach.iteritems(): if id(self.global_namespace[k]) == id(v): del self.global_namespace[k] def hasBuffer(self): return True def bufferClose(self): "to catch an distribute menu command 'close' in Os-X" win = self.get_active_window() if win and win is not self: win.Close() def bufferSave(self): "to catch an distribute menu command 'save' in Os-X" if self.IsActive(): wx.py.shell.ShellFrame.bufferSave(self) else: for e in self.editors: if e.IsActive(): e.bufferSave() def bufferSaveAs(self): "to catch an distribute menu command 'save as' in Os-X" if self.IsActive(): wx.py.shell.ShellFrame.bufferSave(self) else: for e in self.editors: if e.IsActive(): e.bufferSaveAs() def OnClearTerminal(self, event=None): self.shell.clear() self.shell.prompt() def OnDestroyIcon(self, evt): logging.debug("DESTROY ICON CALLED") self.eelbrain_icon.Destroy() evt.Skip() def OnExecFile(self, event=None): """ Execute a file in the shell. filename: if None, will ask isolate: execute with separate globals, do not touch the shell's globals """ dialog = wx.FileDialog(self, style=wx.FD_OPEN) dialog.SetMessage("Select Python File") dialog.SetWildcard("Python files (*.py)|*.py") if dialog.ShowModal(): filename = dialog.GetPath() self.ExecFile(filename) def ExecFile(self, filename, shell_globals=True): """ Execute a file in the shell. shell_globals determines wheter the shell's globals are submitted to the call to execfile or not. (!) A problem currently (also with the commented-out version below) is that __file__ and sys.argv[0] point to eelbrain.__main__ instead of the executed file. """ if filename and os.path.exists(filename): os.chdir(os.path.dirname(filename)) if shell_globals: self.global_namespace['__file__'] = filename self.shell.Execute("execfile(%r)" % filename) else: if float(sys.version[:3]) >= 2.7: if 'runpy' not in self.global_namespace: self.shell.Execute("import runpy") self.shell.Execute("out_globals = runpy.run_path(%r)" % filename) else: command = "execfile(%r, dict(__file__=%r))" self.shell.Execute(command % (filename, filename)) self.pyplot_draw() # save_stdout = sys.stdout # save_stderr = sys.stderr # save_stdin = sys.stdin # # sys.stdout = self.shell.interp.stdout # sys.stderr = self.shell.interp.stderr # sys.stdin = self.shell.interp.stdin # # self.shell.start_exec() # execfile(filename) # self.shell.end_exec() # # sys.stdout = save_stdout # sys.stderr = save_stderr # sys.stdin = save_stdin # self.shell.setFocus() else: logging.error("shell.ExecFile: invalid filename (%r)"%filename) def ExecText(self, txt, out=False, title="unknown source", comment=None, shell_globals=True, filedir=None, internal_call=False): """ Compile txt and Execute it in the shell. kwargs ------ out: shell.Execute title: is displayed in the shell and should identify the source of the code. comment: displayed after title shell_globals: determines wheter the shell's globals are submitted to the call to execfile or not. filedir: perform os.chdir before executing """ if comment is None: msg = 'exec <%r>' % title else: msg = 'exec <%r, %s>' % (title, comment) self.shell_message(msg, ascommand=True, internal_call=internal_call) if filedir: os.chdir(filedir) if out: self.shell.Execute(txt) else: self.shell.start_exec() # this does not work # self.shell.interp.runsource(txt) # prepare txt txt = self.shell.fixLineEndings(txt) txt += os.linesep # 1 cmd = "exec(compile(r'''{txt}''', '{title}', 'exec'), {globals})" if shell_globals: exec_globals = "globals()" else: exec_globals = '{}' code = cmd.format(txt=txt, title=os.path.split(title)[-1], globals=exec_globals) self.shell.push(code, silent=True) # 2 # cmp = compile(txt, os.path.split(title)[-1], 'exec') # self.shell.push(cmp, silent=True) # 3 (runs onliy first line) # self.shell.interp.runsource(txt) self.shell.end_exec() # self.Raise() # (causes Shell to raise above new plots) self.pyplot_draw() def OnFileNew(self, event=None): self.OnPyEd_New(event) def OnFileOpen(self, event=None): self.FileOpen(internal_call=True) def FileOpen_shellcommand(self, path=None): """ Open a file (Experiment or Python script). If path is None, the function will ask for a filename. TODO: fix shell interaction. At current, the function does not return the experiment. """ self.FileOpen(path=path) def FileOpen(self, path=None, internal_call=False): if path is None: path = ui.ask_file(title="Open File", message="Open a Python script in an editor", ext=[('py', 'Python script')]) if not path: return if isinstance(path, basestring) and os.path.isfile(path): ext = path.split(os.extsep)[-1].lower() if ext == 'py': self.create_py_editor(pyfile=path) else: msg = "Error: %r is no known file extension." % ext self.shell_message(msg, internal_call=internal_call) else: msg = "No valid file path: %r" % path self.shell_message(msg, internal_call=internal_call) def OnFindPath(self, event=None): filenames = ui.ask_file(wildcard='', mult=True) if filenames: if len(filenames) == 1: filenames = '"'+filenames[0]+'"' else: filenames = str(filenames) self.shell.ReplaceSelection(filenames) def get_active_window(self): "returns the active window (self, editor, help viewer, ...)" if self.IsActive(): return self for c in self.Children: if hasattr(c, 'IsActive') and c.IsActive(): return c return None def GetCurLine(self): return self.shell.GetCurLine() # HELP def OnHelp(self, event): "Help invoked through the Shell Menu" win = self.get_active_window() # check that the active window has a GetCurLine method if hasattr(win, 'GetCurLine'): text, pos = win.GetCurLine() else: dlg = wx.MessageDialog(self, "The active window does not have a " "GetCurLine function", "Help Call Failed", wx.OK|wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return logging.debug("Shell: help called for : %s (%i)" % (text, pos)) self.OnHelpViewer(topic_str=text, pos=pos) def OnHelpExternal(self, event): "Called from the Help menu to open external resources" Id = event.GetId() if Id == ID.HELP_MPL: webbrowser.open("http://matplotlib.sourceforge.net/") elif Id == ID.HELP_MDP: webbrowser.open("http://mdp-toolkit.sourceforge.net/documentation.html") elif Id == ID.HELP_PYTHON: webbrowser.open("http://docs.python.org/") else: raise ValueError("Invalid help ID") def OnHelpViewer(self, event=None, topic=None, topic_str=None, pos=None): """ topic: object topic_str: string that can be evaluated to get topic object pos: With topic_str, the pos argument can be used to search for a Python object name within topic_str. When the user asks for help in the shell or editor, the topic_str is the current line and pos is the caret position. """ if self.help_viewer: if self.help_viewer.IsShown(): self.help_viewer.Raise() else: self.help_viewer.Show(True) else: # x, y, w, h = self.GetRect().Get() x_min, y_min, x_max, y_max = wx.Display().GetGeometry() hx = x_max-650 #min(x + w, x_max-600) hw = 650 hh = y_max-y_min-22 # min(800, y_max-y_min-21) hy = 22 logging.debug("help viewer: size=(%s,%s), pos=(%s,%s)"%(hw,hh,hx,hy)) self.help_viewer = HelpViewer(self, size=(hw,hh), pos=(hx,hy)) self.help_viewer.Show() if topic_str: if pos is not None: # find the python command around pos in the line topic_scan = topic_str.replace('.', 'a') start = pos n_max = len(topic_str) end = min(pos, n_max) while (end < n_max) and is_py_char(topic_scan[end]): end += 1 while is_py_char(topic_scan[start-1]) and start > 0: start -= 1 topic_str = topic_str[start:end] self.help_viewer.text_lookup(topic_str) else: self.help_viewer.Help_Lookup(topic) def help_lookup(self, what=None): """ what = object whose docstring should be displayed """ # this is the function that is pulled into the shell as help() self.OnHelpViewer(topic=what) def OnInsertColor(self, event=None): ctup = event.GetValue() mplc = tuple([round(c/256., 3) for c in ctup[:3]]) self.InsertStr(str(mplc)) def OnInsertPath_File(self, event): self.OnInsertPath(event, t=0) def OnInsertPath_Dir(self, event): self.OnInsertPath(event, t=1) def OnInsertPath_New(self, event): self.OnInsertPath(event, t=2) def OnInsertPath(self, event, t=None): if t is None: t = event.GetSelection() # get if t == 0: # File filenames = ui.ask_file(mult=True) elif t == 1: # Dir filenames = ui.ask_dir() elif t == 2: # New filenames = ui.ask_saveas(title = "Get New File Name", message = "Please Pick a File Name", ext = None) # put to terminal if filenames: if len(filenames) == 1: filenames = '"'+filenames[0]+'"' else: filenames = '"'+str(filenames)+'"' if 'wxMSW' in wx.PlatformInfo: filenames = 'r'+filenames self.InsertStr(filenames) def InsertStr(self, text): """ Inserts the text in the active window (can be the shell or an editor) """ for editor in self.editors: if hasattr(editor, 'IsActive') and editor.IsActive(): editor.editor.window.ReplaceSelection(text) return self.shell.ReplaceSelection(text) def OnKeyDown(self, event): key = event.GetKeyCode() mod = wxutils.key_mod(event) # logging.debug("app.shell.OnKeyDown(): key=%r, mod=%r" % (key, mod)) if key == 68: # 'd' if mod == [1, 0, 1]: # alt -> also include output mod = [1, 0, 0] duplicate_output = True else: duplicate_output = False # copy selection to first editor if mod == [1, 0, 0]: # [command] if key==80: # 'p' plt.draw() if plt.get_backend() == 'WXAgg': plt.show() elif key==68: # 'd' # make sure we have a target editor if not hasattr(self.active_editor, 'InsertLine'): self.OnPyEd_New(event) self.active_editor = self.editors[-1] editor = self.active_editor # prepare text for transfer text = self.shell.GetSelectedText() lines = [line for line in text.split(os.linesep) if len(line)>0] # FIXME: alt for line in lines: line_stripped = self.shell.lstripPrompt(line) if duplicate_output or len(line_stripped) < len(line): try: editor.InsertLine(line_stripped) except: logging.debug("'Duplicate to Editor' failed") else: event.Skip() else: # logging.info("shell key: %s"%key) event.Skip() def OnMaximize(self, event=None): logging.debug("SHELLFRAME Maximize received") self.OnResize_Max(event) def OnPreferences(self, event=None): dlg = preferences_dialog.PreferencesDialog(self) # dlg = wx.MessageDialog(self, "Test", 'test', wx.OK) dlg.Show() # dlg.Destroy() def OnP_CloseAll(self, event=None): plt.close('all') def pyplot_draw(self): # update plots if mpl Backend does not do that automatically if mpl.get_backend() in ['WXAgg']: if len(plt._pylab_helpers.Gcf.get_all_fig_managers()) > 0: plt.draw() plt.show() def OnQuit(self, event=None): logging.debug(" QUIT") if self.help_viewer: self.help_viewer.Close() unsaved = [] for ed in self.editors: if hasattr(ed, 'editor'): # check if alife if hasattr (ed.editor, 'hasChanged'): # editor without doc if ed.editor.hasChanged(): unsaved.append(ed) else: ed.Close() if len(unsaved) == 1: unsaved[0].OnClose(event) elif len(unsaved) > 0: txt = '\n'.join([u.Title for u in unsaved]) msg = wx.MessageDialog(None, txt, "Review Unsaved Py-Docs?", wx.ICON_QUESTION|wx.YES_NO|wx.YES_DEFAULT|\ wx.CANCEL) command = msg.ShowModal() if command == wx.ID_CANCEL: return else: for ed in unsaved: if command == wx.ID_YES: # ed.bufferSave() ed.Close() else: ed.Destroy() self.OnP_CloseAll() self.Close() def OnRecentItemLoad(self, event): fileNum = event.GetId() - wx.ID_FILE1 logging.debug("History Load: %s"%fileNum) path = self.filehistory.GetHistoryFile(fileNum) logging.debug("History Load: %s"%path) self.FileOpen(path=path, internal_call=True) def recent_item_add(self, path, t): "t is 'e' or 'pydoc'" self.filehistory.AddFileToHistory(path) self.filehistory.Save(self.wx_config) self.wx_config.Flush() self.recent_menu_update_icons() # path_list = self.recent_files[t] # menu = self.recent_menus[t] # # if path in path_list: # i = path_list.index(path) # if i == 0: # return # path_list.pop(i) # menu_item = menu.GetMenuItems()[i] # menu.RemoveItem(menu_item) # else: # # remove old item # if len(path_list) > 10: # path_list.pop(-1) # n = menu.GetMenuItemCount() # old_menu_item = menu.GetMenuItems()[n-1] # menu.RemoveItem(old_menu_item) # # new item # if t == 'e': # id = ID.RECENT_LOAD_E # elif t =='pydoc': # id = ID.RECENT_LOAD_PYDOC # else: # raise ValueError("t == %s"%t) # name = os.path.basename(path) # menu_item = wx.MenuItem(menu, id, name, path) # menu.InsertItem(0, menu_item) # # path list # path_list.insert(0, path) # with open(self.recent_files_path, 'w') as file: # pickle.dump(self.recent_files, file) def recent_menu_update_icons(self): py_icon = Icon('documents/pydoc') e_icon = Icon('documents/experiment') for item in self.recent_menu.GetMenuItems(): text = item.GetItemLabelText() if text.endswith('.py'): item.SetBitmap(py_icon) elif text.endswith(_extension): item.SetBitmap(e_icon) def RemovePyEditor(self, editor): if editor in self.editors: self.editors.remove(editor) ID = editor.GetId() self.windowMenuWindows.pop(ID) self.windowMenuMenuItems.pop(ID) self.windowMenu.Remove(ID) def OnResize_Max(self, event): x_min, y_min, x_max, y_max = wx.Display().GetGeometry() x_size = min(x_max-x_min, 800) + x_min self.SetPosition((x_min, y_min)) self.SetSize((x_size, y_max)) def OnResize_HalfScreen(self, event): x_min, y_min, x_max, y_max = wx.Display().GetGeometry() self.SetPosition((x_min, y_min)) x_size = min(x_max//2, 800) - x_min y_size = y_max - y_min self.SetSize((x_size, y_size)) def OnResize_Win(self, event): x_min, y_min, x_max, y_max = wx.Display().GetGeometry() self.SetPosition((x_min, y_min+50)) x_size = 800 + x_min y_size = y_max - y_min - 100 self.SetSize((x_size, y_size)) def OnResize_Min(self, event): self.SetPosition((50, 200)) self.SetSize((350, 600)) def pos_for_new_window(self, size=(200, 400)): x, y, w, h = self.GetRect().Get() x_min, y_min, x_max, y_max = wx.Display().GetGeometry() e_x = x + w if e_x + size[0] > x_max: e_x = x_max - size[0] return (e_x, y_min + 26) def OnTogglePyplotMgr(self, event=None): if self.P_mgr.IsShown(): self.P_mgr.Show(False) else: self.P_mgr.Show() def OnSelectColourAlt(self, event=None): if hasattr(self, 'c_dlg'): if hasattr(self.c_dlg, 'GetColourData'): c = self.c_dlg.GetColourData() c = c.GetColour() self.shell.ReplaceSelection(str(c)) else: del self.c_dlg if not hasattr(self, 'c_dlg'): self.c_dlg = wx.ColourDialog(self) def OnPyEd_New(self, event=None): self.create_py_editor() def create_py_editor(self, pyfile=None): """ Creates and returns a new py_editor object. :arg pyfile: filename as string, or True in order to display an "open file" dialog (None creates an empty editor) :arg openfile: True if an 'open file' dialog should be shown after the editor is cerated """ editor = py_editor.Editor(self, self, pos=self.pos_for_new_window(), pyfile=pyfile) editor.Show() self.editors.append(editor) # add to window menu ID = editor.GetId() m = self.windowMenu.Append(ID, "a", "Bring window to the front.") self.Bind(wx.EVT_MENU, self.OnWindowMenuActivateWindow, m) self.windowMenuWindows[ID] = editor self.windowMenuMenuItems[ID] = m return editor def OnTableNew(self, event=None): self.FrameTable(None) def OnOpenWindowMenu(self, event): "Updates open windows to the menu" menu = event.GetMenu() # ID = event.GetMenuId() (is always 0) name = menu.GetTitle() if name == "&Window": logging.debug("Window Menu Open") # update names for ID, m in self.windowMenuMenuItems.iteritems(): window = self.windowMenuWindows[ID] title = window.GetTitle() m.SetText(title) def OnWindowMenuActivateWindow(self, event): ID = event.GetId() window = self.windowMenuWindows[ID] window.SetFocus() def FrameTable(self, table=None): pos = self.pos_for_new_window() t = TableFrame(self, table, pos=pos) self.tables.append(t) def shell_message(self, message, sep=False, ascommand=False, endline=True, internal_call=False): """ Proxy for shell.writeOut method kwargs ------ sep = False: adds linebreaks at the top and at the bottom of message ascommand = False: adds the prompt in front of the message to mimmick command internal_call: notification that the call is made by the app mainloop rather than form the shell """ ls = os.linesep if message != ls: message = message.rstrip(ls) if ascommand: message = sys.ps1 + message endline = True if endline: if internal_call: message = message + ls elif sep: if message[0] != ls: message = ls + message if message[-1] != ls: message = message + ls if message[-2] != ls: message = message + ls if internal_call:# ascommand: logging.debug("internal shell_msg: %r" % message) self.shell.start_exec() self.shell.writeOut(message) self.shell.end_exec() else: logging.debug("external shell_msg: %r" % message) print message def SetColours(self, obj): obj.SetCaretWidth(2) if 'wxMac' in wx.PlatformInfo: # --> wx.py.shell.editwindow.EditWindow.__config() FACES = { 'times' : 'Lucida Grande', 'mono' : 'Courier New',#'Monaco', 'helv' : 'Geneva', 'other' : 'new century schoolbook', 'size' : 12, 'lnsize' : 16, 'backcol' : '#F0F0F0',#'#000010', 'calltipbg' : '#101010', 'calltipfg' : '#F09090', } obj.StyleClearAll() obj.setStyles(FACES) obj.CallTipSetBackground(FACES['calltipbg']) obj.CallTipSetForeground(FACES['calltipfg']) if True: obj.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "fore:#FFFF00")#,back:#666666") obj.StyleSetSpec(wx.stc.STC_P_DEFAULT, # '\' "fore:#000000") obj.StyleSetSpec(wx.stc.STC_P_NUMBER, "fore:#0000FF") obj.StyleSetSpec(wx.stc.STC_STYLE_CONTROLCHAR, "fore:#FF0000") obj.StyleSetSpec(wx.stc.STC_P_STRING, "fore:#FF0000") obj.StyleSetSpec(wx.stc.STC_P_CHARACTER, "fore:#0000FF") obj.StyleSetSpec(wx.stc.STC_P_OPERATOR, "fore:#000010") obj.StyleSetSpec(wx.stc.STC_P_DECORATOR, "fore:#FF00FF") obj.StyleSetSpec(wx.stc.STC_P_WORD, "fore:#FF00FF") obj.StyleSetSpec(wx.stc.STC_STYLE_MAX, "fore:#0000FF")