def __init__(self, master, proc, title, long_description=None, autoclose=True): self._proc = proc self.stdout = "" self.stderr = "" self._stdout_thread = None self._stderr_thread = None self.returncode = None self.cancelled = False self._autoclose = autoclose self._event_queue = collections.deque() tk.Toplevel.__init__(self, master) self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) main_frame = ttk.Frame(self) # To get styled background main_frame.grid(sticky="nsew") text_font=tk.font.nametofont("TkFixedFont").copy() #text_font["size"] = int(text_font["size"] * 0.9) text_font["family"] = "Courier" if running_on_mac_os() else "Courier New" text_frame = tktextext.TextFrame(main_frame, read_only=True, horizontal_scrollbar=False, #vertical_scrollbar=False, background=get_main_background(), font=text_font, wrap="word") text_frame.grid(row=0, column=0, sticky=tk.NSEW, padx=15, pady=15) self.text = text_frame.text self.text["width"] = 60 self.text["height"] = 12 if long_description is not None: self.text.direct_insert("1.0", long_description + "\n\n") self.button = ttk.Button(main_frame, text="Cancel", command=self._close) self.button.grid(row=1, column=0, pady=(0,15)) main_frame.rowconfigure(0, weight=1) main_frame.columnconfigure(0, weight=1) self.title(title) if misc_utils.running_on_mac_os(): self.configure(background="systemSheetBackground") #self.resizable(height=tk.FALSE, width=tk.FALSE) self.transient(master) self.grab_set() # to make it active and modal self.text.focus_set() self.bind('<Escape>', self._close_if_done, True) # escape-close only if process has completed self.protocol("WM_DELETE_WINDOW", self._close) center_window(self, master) self._start_listening()
def handle_vm_message(self, msg): debug("ExpressionView.handle_vm_message %s", (msg.state, msg.focus)) if msg.state in ("before_expression", "before_expression_again"): # (re)load stuff if self._main_range is None or msg.focus.not_smaller_eq_in(self._main_range): self._load_expression(msg.filename, msg.focus) self._update_position(msg.focus) self._update_size() self._highlight_range(msg.focus, msg.state) elif msg.state == "after_expression": debug("EV: after_expression %s", msg) self.tag_configure('after', background="#BBEDB2", borderwidth=1, relief=tk.FLAT) start_mark = self._get_mark_name(msg.focus.lineno, msg.focus.col_offset) end_mark = self._get_mark_name(msg.focus.end_lineno, msg.focus.end_col_offset) if hasattr(msg, "value"): debug("EV: replacing expression with value") #print("del", start_mark, end_mark) self.delete(start_mark, end_mark) id_str = memory.format_object_id(msg.value.id) if self._workbench.get_option("view.values_in_heap"): value_str = id_str else: value_str = shorten_repr(msg.value.repr, 100) #print("ins", start_mark, value_str) object_tag = "object_" + str(msg.value.id) self.insert(start_mark, value_str, ('value', 'after', object_tag)) if misc_utils.running_on_mac_os(): sequence = "<Command-Button-1>" else: sequence = "<Control-Button-1>" self.tag_bind(object_tag, sequence, lambda _: self._workbench.event_generate("ObjectSelect", object_id=msg.value.id)) self._update_size() else: debug("EV: got exc: %s", msg) "TODO: make it red" elif (msg.state == "before_statement_again" and self._main_range is not None # TODO: shouldn't need this and self._main_range.is_smaller_eq_in(msg.focus)): # we're at final stage of executing parent statement # (eg. assignment after the LHS has been evaluated) # don't close yet self.tag_configure('after', background="#DCEDF2", borderwidth=1, relief=tk.FLAT) else: # hide and clear on non-expression events self.clear_debug_view() if hasattr(msg, "focus"): self._last_focus = msg.focus
def get_busy_cursor(): if running_on_windows(): return "wait" elif running_on_mac_os(): return "spinning" else: return "watch"
def _cmd_interrupt_with_shortcut(self, event=None): if not self._cmd_interrupt_enabled(): return None if not running_on_mac_os(): # on Mac Ctrl+C is not used for Copy. # Disable Ctrl+C interrupt in editor and shell, when some text is selected # (assuming user intended to copy instead of interrupting) widget = get_workbench().focus_get() if isinstance(widget, tk.Text): if len(widget.tag_ranges("sel")) > 0: # this test is reliable, unlike selection_get below return None elif isinstance(widget, (tk.Listbox, ttk.Entry, tk.Entry, tk.Spinbox)): try: selection = widget.selection_get() if isinstance(selection, str) and len(selection) > 0: # Assuming user meant to copy, not interrupt # (IDLE seems to follow same logic) # NB! This is not perfect, as in Linux the selection can be in another app # ie. there may be no selection in Thonny actually. # In other words, Ctrl+C interrupt may be dropped without reason # when given inside the widgets listed above. return None except Exception: # widget either doesn't have selection_get or it # gave error (can happen without selection on Ubuntu) pass self._cmd_interrupt() return "break"
def update_fonts(self): editor_font_size = self._guard_font_size( self.get_option("view.editor_font_size")) editor_font_family = self.get_option("view.editor_font_family") io_font_family = self.get_option("view.io_font_family") self.get_font("IOFont").configure(family=io_font_family, size=min( editor_font_size - 2, int(editor_font_size * 0.8 + 3))) self.get_font("EditorFont").configure(family=editor_font_family, size=editor_font_size) self.get_font("BoldEditorFont").configure(family=editor_font_family, size=editor_font_size) self.get_font("ItalicEditorFont").configure(family=editor_font_family, size=editor_font_size) self.get_font("BoldItalicEditorFont").configure( family=editor_font_family, size=editor_font_size) style = ttk.Style() if running_on_mac_os(): treeview_font_size = int(editor_font_size * 0.7 + 4) rowheight = int(treeview_font_size * 1.2 + 4) else: treeview_font_size = int(editor_font_size * 0.7 + 2) rowheight = int(treeview_font_size * 2.0 + 6) self.get_font("TreeviewFont").configure(size=treeview_font_size) style.configure("Treeview", rowheight=rowheight) if self._editor_notebook is not None: self._editor_notebook.update_appearance()
def __init__(self, master, only_user=False): self._state = None # possible values: "listing", "fetching", "idle" self._process = None self._installed_versions = {} self._only_user = only_user self.current_package_data = None tk.Toplevel.__init__(self, master) main_frame = ttk.Frame(self) main_frame.grid(sticky=tk.NSEW, ipadx=15, ipady=15) self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.title(self._get_title()) if misc_utils.running_on_mac_os(): self.configure(background="systemSheetBackground") self.transient(master) self.grab_set() # to make it active #self.grab_release() # to allow eg. copy something from the editor self._create_widgets(main_frame) self.search_box.focus_set() self.bind('<Escape>', self._on_close, True) self.protocol("WM_DELETE_WINDOW", self._on_close) self._show_instructions() ui_utils.center_window(self, master) self._start_update_list()
def __init__(self, master, spin_options, mode="text", **kw): super().__init__(master=master, **kw) self.frame = ttk.Frame(self, width=50) if len(spin_options) == 0: raise ValueError("spin_options must be a non empty list") self.options = spin_options self.option_val = tk.StringVar(self) self.option_val.set(self.options[0]) self.hint_str = tk.StringVar(self) self.text = tk.Text(self.frame, height=1, width=50) """ tk.Option used because thonny themes hide the option to change the value of the default list """ if running_on_mac_os(): self.option_box = tk.OptionMenu(self.frame, self.option_val, *spin_options) else: self.option_box = ttk.OptionMenu(self.frame, self.option_val, *spin_options) self.hint_label = ttk.Label(self, textvariable=self.hint_str) self.frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) if mode == "text": self.text.pack(side=tk.TOP, fill=tk.X, expand=True) else: self.option_box.pack(side=tk.TOP, fill=tk.X, expand=True) self.text.bind("<<Modified>>", self._on_value_change) self.option_val.trace("w", self._on_value_change)
def _treeview_settings() -> BasicUiThemeSettings: light_blue = "#ADD8E6" light_grey = "#D3D3D3" if running_on_linux() or running_on_mac_os(): bg_sel_focus = light_blue fg_sel_focus = "black" fg_sel_notfocus = "black" else: bg_sel_focus = "SystemHighlight" fg_sel_focus = "SystemHighlightText" fg_sel_notfocus = "SystemWindowText" return { "Treeview": { "configure": {"font": "TreeviewFont"}, "map": { "background": [ ("selected", "focus", bg_sel_focus), ("selected", "!focus", light_grey), ], "foreground": [ ("selected", "focus", fg_sel_focus), ("selected", "!focus", fg_sel_notfocus), ], }, "layout": [ # get rid of borders ("Treeview.treearea", {"sticky": "nswe"}) ], }, "treearea": {"configure": {"borderwidth": 0}}, }
def __init__(self, master): super().__init__(master) runscript_label = ttk.Label(self, text="Running current script in terminal:") runscript_label.grid(row=0, column=0, sticky="w") self.add_checkbox( "run.run_in_terminal_python_repl", "Present Python REPL after program ends", row=1, padx=(12, 0), ) self.add_checkbox( "run.run_in_terminal_keep_open", "Keep terminal window open after Python process ends", row=2, padx=(12, 0), ) exit_remark = " " if running_on_mac_os(): exit_remark = ( "NB! Automatic closing needs to be enabled in Terminal's settings\n" + "(Profiles → Shell → When the shell exits)") remark_label = ttk.Label(self, text=exit_remark) remark_label.grid(row=3, column=0, sticky="w", padx=(12, 0), pady=(0, 10))
def show_file(self, filename, text_range=None, set_focus=True, propose_dialog=True): # self.close_single_untitled_unmodified_editor() try: editor = self.get_editor(filename, True) except PermissionError: logger.exception("Loading " + filename) msg = "Got permission error when trying to load\n" + filename if running_on_mac_os() and propose_dialog: msg += "\n\nTry opening it with File => Open." messagebox.showerror("Permission error", msg, master=self) return None if editor is None: return self.select(editor) if set_focus: editor.focus_set() if text_range is not None: editor.select_range(text_range) return editor
def _replace(self, focus, value): start_mark = self._get_mark_name(focus.lineno, focus.col_offset) end_mark = self._get_mark_name(focus.end_lineno, focus.end_col_offset) self.delete(start_mark, end_mark) id_str = memory.format_object_id(value.id) if get_workbench().in_heap_mode(): value_str = id_str else: value_str = shorten_repr(value.repr, 100) object_tag = "object_" + str(value.id) self.insert(start_mark, value_str, ("value", object_tag)) if misc_utils.running_on_mac_os(): sequence = "<Command-Button-1>" else: sequence = "<Control-Button-1>" self.tag_bind( object_tag, sequence, lambda _: get_workbench().event_generate( "ObjectSelect", object_id=value.id ), )
def load_plugin(workbench): workbench.add_command("about", "Thonny" if running_on_mac_os() else "help", "About Thonny", lambda: AboutDialog(workbench, workbench.get_version()))
def open_with_default_app(path): if running_on_windows(): os.startfile(path) elif running_on_mac_os(): subprocess.run(["open", path]) else: subprocess.run(["xdg-open", path])
def open_path_in_system_file_manager(path): if running_on_mac_os(): # http://stackoverflow.com/a/3520693/261181 subprocess.Popen(["open", "-R", path]) elif running_on_linux(): subprocess.Popen(["xdg-open", path]) else: assert running_on_windows() subprocess.Popen(["explorer", path])
def _set_window_attributes(self): if running_on_mac_os(): try: # Must be the first thing to do after creating window # https://wiki.tcl-lang.org/page/MacWindowStyle self.tk.call("::tk::unsupported::MacWindowStyle", "style", self._w, "help", "noActivates") if get_tk_version_info() >= (8, 6, 10) and running_on_mac_os(): self.wm_overrideredirect(1) except tk.TclError: pass else: self.wm_overrideredirect(1) self.wm_transient(get_workbench()) # From IDLE # TODO: self.update_idletasks() # Need for tk8.6.8 on macOS: #40128. self.lift()
def select_sequence(win_version, mac_version, linux_version=None): if running_on_windows(): return win_version elif running_on_mac_os(): return mac_version elif running_on_linux() and linux_version: return linux_version else: return win_version
def __init__(self, master, show_hidden_files=False, last_folder_setting_name=None, breadcrumbs_pady=(5, 7)): self._cached_dir_data = {} ttk.Frame.__init__(self, master, borderwidth=0, relief="flat") self.vert_scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL, style=scrollbar_style("Vertical")) self.vert_scrollbar.grid(row=0, column=1, sticky=tk.NSEW, rowspan=3) tktextext.fixwordbreaks(tk._default_root) self.building_breadcrumbs = False self.init_header(row=0, column=0) spacer = ttk.Frame(self, height=1) spacer.grid(row=1, sticky="nsew") self.tree = ttk.Treeview( self, columns=["#0", "kind", "path"], displaycolumns=(0, ), yscrollcommand=self.vert_scrollbar.set, ) self.tree["show"] = "headings" self.tree.grid(row=2, column=0, sticky=tk.NSEW) self.vert_scrollbar["command"] = self.tree.yview self.columnconfigure(0, weight=1) self.rowconfigure(2, weight=1) self.show_hidden_files = show_hidden_files self.tree["show"] = ("tree", ) self.tree.bind("<3>", self.on_secondary_click, True) if misc_utils.running_on_mac_os(): self.tree.bind("<2>", self.on_secondary_click, True) self.tree.bind("<Control-1>", self.on_secondary_click, True) self.tree.bind('<Double-Button-1>', self.on_double_click, True) self.tree.bind("<<TreeviewOpen>>", self.on_open_node) wb = get_workbench() self.folder_icon = wb.get_image("folder") self.python_file_icon = wb.get_image("python-file") self.text_file_icon = wb.get_image("text-file") self.generic_file_icon = wb.get_image("generic-file") self.hard_drive_icon = wb.get_image("hard-drive") self.tree.column("#0", width=500, anchor=tk.W) # set-up root node self.tree.set("", "kind", "root") self.menu = tk.Menu(self.tree, tearoff=False) self._last_folder_setting_name = last_folder_setting_name self.focus_into_saved_folder()
def __init__(self, master, show_hidden_files=False): BaseFileBrowser.__init__(self, master, show_hidden_files, "file.last_browser_folder") self.menu = tk.Menu(tk._default_root, tearoff=False) self.menu.add_command(label="Create new file", command=self.create_new_file) self.tree.bind('<3>', self.on_secondary_click, True) if misc_utils.running_on_mac_os(): self.tree.bind('<2>', self.on_secondary_click, True) self.tree.bind('<Control-1>', self.on_secondary_click, True)
def __init__(self): wb = get_workbench() wb.bind_class("EditorCodeViewText", "<1>", self.request_definitions, True) wb.bind_class("EditorCodeViewText", "<Any-Motion>", self.on_motion, True) wb.bind_class("EditorCodeViewText", "<Any-Leave>", self.remove_underline, True) if running_on_mac_os(): wb.bind_class("EditorCodeViewText", "<Command-KeyRelease>", self.remove_underline, True) else: wb.bind_class("EditorCodeViewText", "<Control-KeyRelease>", self.remove_underline, True) wb.bind("get_definitions_response", self.handle_definitions_response, True)
def _handle_toplevel_response(self, msg: ToplevelResponse) -> None: if msg.get("error"): self._insert_text_directly(msg["error"] + "\n", ("toplevel", "stderr")) self._ensure_visible() if "user_exception" in msg: self._show_user_exception(msg["user_exception"]) self._ensure_visible() welcome_text = msg.get("welcome_text") if welcome_text and welcome_text != self._last_welcome_text: self._insert_text_directly(welcome_text, ("comment", )) self._last_welcome_text = welcome_text if "value_info" in msg: num_stripped_question_marks = getattr( msg, "num_stripped_question_marks", 0) if num_stripped_question_marks > 0: # show the value in object inspector get_workbench().event_generate("ObjectSelect", object_id=msg["value_info"].id) else: # show the value in shell value_repr = shorten_repr(msg["value_info"].repr, 10000) if value_repr != "None": if get_workbench().in_heap_mode(): value_repr = memory.format_object_id( msg["value_info"].id) object_tag = "object_" + str(msg["value_info"].id) self._insert_text_directly( value_repr + "\n", ("toplevel", "value", object_tag)) if running_on_mac_os(): sequence = "<Command-Button-1>" else: sequence = "<Control-Button-1>" self.tag_bind( object_tag, sequence, lambda _: get_workbench().event_generate( "ObjectSelect", object_id=msg["value_info"].id), ) self.active_object_tags.add(object_tag) self.mark_set("output_end", self.index("end-1c")) self._discard_old_content() self._update_visible_io(None) self._reset_ansi_attributes() self._io_cursor_offset = 0 self._insert_prompt() self._try_submit_input( ) # Trying to submit leftover code (eg. second magic command) self.see("end")
def _get_interpreters(cls): result = set() if running_on_windows(): # registry result.update(CPythonProxy._get_interpreters_from_windows_registry()) # Common locations for dir_ in ["C:\\Python34", "C:\\Python35", "C:\\Program Files\\Python 3.5", "C:\\Program Files (x86)\\Python 3.5", "C:\\Python36", "C:\\Program Files\\Python 3.6", "C:\\Program Files (x86)\\Python 3.6", ]: path = os.path.join(dir_, "pythonw.exe") if os.path.exists(path): result.add(os.path.realpath(path)) else: # Common unix locations for dir_ in ["/bin", "/usr/bin", "/usr/local/bin", os.path.expanduser("~/.local/bin")]: for name in ["python3", "python3.4", "python3.5", "python3.6"]: path = os.path.join(dir_, name) if os.path.exists(path): result.add(path) if running_on_mac_os(): for version in ["3.4", "3.5", "3.6"]: dir_ = os.path.join("/Library/Frameworks/Python.framework/Versions", version, "bin") path = os.path.join(dir_, "python3") if os.path.exists(path): result.add(path) for command in ["pythonw", "python3", "python3.4", "python3.5", "python3.6"]: path = which(command) if path is not None: result.add(path) current_configuration = get_workbench().get_option("run.backend_configuration") backend, configuration_option = parse_configuration(current_configuration) if backend == "Python" and configuration_option and os.path.exists(configuration_option): result.add(os.path.realpath(configuration_option)) for path in get_workbench().get_option("run.used_interpreters"): if os.path.exists(path): result.add(os.path.realpath(path)) return sorted(result)
def _init_fonts(self): self.set_default("view.io_font_family", "Courier" if running_on_mac_os() else "Courier New") default_editor_family = "Courier New" families = tk_font.families() for family in ["Consolas", "Ubuntu Mono", "Menlo", "DejaVu Sans Mono"]: if family in families: default_editor_family = family break self.set_default("view.editor_font_family", default_editor_family) self.set_default("view.editor_font_size", 14 if running_on_mac_os() else 11) default_font = tk_font.nametofont("TkDefaultFont") self._fonts = { 'IOFont': tk_font.Font(family=self.get_option("view.io_font_family")), 'EditorFont': tk_font.Font(family=self.get_option("view.editor_font_family")), 'BoldEditorFont': tk_font.Font(family=self.get_option("view.editor_font_family"), weight="bold"), 'ItalicEditorFont': tk_font.Font(family=self.get_option("view.editor_font_family"), slant="italic"), 'BoldItalicEditorFont': tk_font.Font(family=self.get_option("view.editor_font_family"), weight="bold", slant="italic"), 'TreeviewFont': tk_font.Font(family=default_font.cget("family"), size=default_font.cget("size")) } self.update_fonts()
def __init__(self, codeview): tk.Toplevel.__init__(self, codeview.winfo_toplevel()) text = tk.Text(self, **self.get_text_options()) BaseExpressionBox.__init__(self, codeview, text) self.text.grid() if running_on_mac_os(): try: # NB! Must be the first thing to do after creation # https://wiki.tcl-lang.org/page/MacWindowStyle self.tk.call("::tk::unsupported::MacWindowStyle", "style", self._w, "help", "noActivates") except TclError: pass else: raise RuntimeError("Should be used only on Mac") self.resizable(False, False) if get_tk_version_info() >= (8, 6, 10) and running_on_mac_os(): self.wm_overrideredirect(1) self.wm_transient(codeview.winfo_toplevel()) self.lift()
def _cmd_interrupt_enabled(self): widget = get_workbench().focus_get() if not running_on_mac_os(): # on Mac Ctrl+C is not used for Copy if hasattr(widget, "selection_get"): try: if widget.selection_get() != "": # assuming user meant to copy, not interrupt # (IDLE seems to follow same logic) return False except: # selection_get() gives error when calling without selection on Ubuntu pass return get_runner().get_state() != "waiting_toplevel_command"
def __init__(self, master): tk.Toplevel.__init__(self, master) self.title(_("Configure shell macro")) if misc_utils.running_on_mac_os(): self.configure(background="systemSheetBackground") self.transient(master) self.grab_set() # to make it active # self.grab_release() # to allow eg. copy something from the editor self._create_widgets() self.bind("<Escape>", self._on_close, True) self.protocol("WM_DELETE_WINDOW", self._on_close) self.main_command_text.focus_set()
def _preview_submission_data(self, event=None): temp_path = os.path.join( tempfile.mkdtemp(), "ThonnyAssistantFeedback_" + datetime.datetime.now().isoformat().replace(":", ".")[:19] + ".txt", ) data = self._collect_submission_data() with open(temp_path, "w", encoding="ascii") as fp: fp.write(data) if running_on_mac_os(): subprocess.Popen(["open", "-e", temp_path]) else: webbrowser.open(temp_path)
def __init__(self, master, show_hidden_files=False): BaseFileBrowser.__init__(self, master, show_hidden_files, "file.last_browser_folder") self.menu = tk.Menu(tk._default_root, tearoff=False) self.menu.add_command(label="Create new file", command=self.create_new_file) self.tree.bind("<3>", self.on_secondary_click, True) if misc_utils.running_on_mac_os(): self.tree.bind("<2>", self.on_secondary_click, True) self.tree.bind("<Control-1>", self.on_secondary_click, True) self.set_breadcrumbs( "C:\\Users\\Aivar\\Documents\\Python\\PyGame\\NikaNaka")
def __init__(self, master): super().__init__(master) self._configuration_variable = create_string_var( get_workbench().get_option("CustomInterpreter.path")) entry_label = ttk.Label(self, text=tr("Python executable")) entry_label.grid(row=0, column=1, columnspan=2, sticky=tk.W) self._entry = ttk.Combobox( self, exportselection=False, textvariable=self._configuration_variable, values=_get_interpreters(), ) self._entry.grid(row=1, column=1, sticky=tk.NSEW) self._select_button = ttk.Button( self, text="...", width=3, command=self._select_executable, ) self._select_button.grid(row=1, column=2, sticky="e", padx=(10, 0)) self.columnconfigure(1, weight=1) extra_text = tr("NB! Thonny only supports Python 3.5 and later") if running_on_mac_os(): extra_text += "\n\n" + tr( "NB! File selection button may not work properly when selecting executables\n" + "from a virtual environment. In this case choose the 'activate' script instead\n" + "of the interpreter (or enter the path directly to the box)!") extra_label = ttk.Label(self, text=extra_text) extra_label.grid(row=2, column=1, columnspan=2, pady=10, sticky="w") last_row = ttk.Frame(self) last_row.grid(row=100, sticky="swe", column=1, columnspan=2) self.rowconfigure(100, weight=1) last_row.columnconfigure(1, weight=1) new_venv_link = ui_utils.create_action_label( last_row, "New virtual environment", self._create_venv, ) new_venv_link.grid(row=0, column=1, sticky="e", pady=10)
def _handle_toplevel_result(self, msg): self["font"] = get_workbench().get_font("EditorFont") self._before_io = True if hasattr(msg, "error"): self._insert_text_directly(msg.error + "\n", ("toplevel", "error")) if hasattr(msg, "welcome_text"): configuration = get_workbench().get_option( "run.backend_configuration") welcome_text = msg.welcome_text if hasattr( msg, "executable" ) and msg.executable != thonny.running.get_private_venv_executable( ): welcome_text += " (" + msg.executable + ")" if (configuration != self._last_configuration and not (self._last_configuration is None and not configuration)): self._insert_text_directly(welcome_text, ("welcome", )) self._last_configuration = get_workbench().get_option( "run.backend_configuration") if hasattr(msg, "value_info"): value_repr = shorten_repr(msg.value_info["repr"], 10000) if value_repr != "None": if get_workbench().in_heap_mode(): value_repr = memory.format_object_id(msg.value_info["id"]) object_tag = "object_" + str(msg.value_info["id"]) self._insert_text_directly(value_repr + "\n", ("toplevel", "value", object_tag)) if running_on_mac_os(): sequence = "<Command-Button-1>" else: sequence = "<Control-Button-1>" self.tag_bind( object_tag, sequence, lambda _: get_workbench().event_generate( "ObjectSelect", object_id=msg.value_info["id"])) self.active_object_tags.add(object_tag) self.mark_set("output_end", self.index("end-1c")) self._insert_prompt() self._try_submit_input( ) # Trying to submit leftover code (eg. second magic command) self.see("end")
def __init__(self, text_frame, frame_info): self._text_frame = text_frame self._text = text_frame.text self._frame_info = frame_info self._frame_id = frame_info.id self._filename = frame_info.filename self._firstlineno = None if running_on_mac_os(): self._expression_box = ToplevelExpressionBox(text_frame) else: self._expression_box = PlacedExpressionBox(text_frame) self._note_box = ui_utils.NoteBox(text_frame.winfo_toplevel()) self._next_frame_visualizer = None self._prev_frame_visualizer = None self._text.set_read_only(True) self._line_debug = frame_info.current_statement is None self._reconfigure_tags()
def _cmd_interrupt_enabled(self) -> bool: if not self._proxy or not self._proxy.is_functional(): return False # TODO: distinguish command and Ctrl+C shortcut widget = get_workbench().focus_get() if not running_on_mac_os(): # on Mac Ctrl+C is not used for Copy if widget is not None and hasattr(widget, "selection_get"): try: selection = widget.selection_get() if isinstance(selection, str) and len(selection) > 0: # assuming user meant to copy, not interrupt # (IDLE seems to follow same logic) return False except Exception: # selection_get() gives error when calling without selection on Ubuntu pass return self.is_running() or self.is_waiting_toplevel_command()
def _check_connection(self, port): proxy = get_runner().get_backend_proxy() if isinstance(proxy, MicroPythonProxy): # Most likely it is using the same port proxy.disconnect() time.sleep(1.5) # Maybe another program is connected # or the user doesn't have sufficient permissions? try: conn = SerialConnection(port, 115200, skip_reader=True) conn.close() return True except Exception as e: messagebox.showerror("Can't connect", str(e), master=None if running_on_mac_os() else self) return False
def __init__(self, master, workbench, show_hidden_files=False): # TODO: refactor universal file browser TreeFrame.__init__(self, master, ["#0", "kind", "path"], displaycolumns=(0,)) #print(self.get_toplevel_items()) self._workbench = workbench self.editor_notebook = workbench.get_editor_notebook() self.show_hidden_files = show_hidden_files self.tree['show'] = ('tree',) self.hor_scrollbar = ttk.Scrollbar(self, orient=tk.HORIZONTAL) self.tree.config(xscrollcommand=self.hor_scrollbar.set) self.hor_scrollbar['command'] = self.tree.xview self.hor_scrollbar.grid(row=1, column=0, sticky="nsew") self.folder_icon = tk.PhotoImage(file=misc_utils.get_res_path("folder.gif")) self.python_file_icon = tk.PhotoImage(file=misc_utils.get_res_path("python_file.gif")) self.text_file_icon = tk.PhotoImage(file=misc_utils.get_res_path("text_file.gif")) self.generic_file_icon = tk.PhotoImage(file=misc_utils.get_res_path("generic_file.gif")) self.hard_drive_icon = tk.PhotoImage(file=misc_utils.get_res_path("hard_drive2.gif")) self.tree.column('#0', width=500, anchor=tk.W) # set-up root node self.tree.set("", "kind", "root") self.tree.set("", "path", "") self.refresh_tree() self.tree.bind("<<TreeviewOpen>>", self.on_open_node) self.menu = tk.Menu(tk._default_root, tearoff=False) self.menu.add_command(label="Create new file", command=self.create_new_file) self.tree.bind('<3>', self.on_secondary_click) if misc_utils.running_on_mac_os(): self.tree.bind('<2>', self.on_secondary_click) self.tree.bind('<Control-1>', self.on_secondary_click) self.open_initial_folder()
def _handle_vm_message(self, msg): if isinstance(msg, InputRequest): self.text_mode = "io" self.text["font"] = self._workbench.get_font("IOFont") # otherwise the cursor is of toplevel size self.text.focus_set() self.text.mark_set("insert", "end") self.text.tag_remove("sel", "1.0", tk.END) self._try_submit_input() # try to use leftovers from previous request self.text.see("end") elif isinstance(msg, OutputEvent): self.text_mode = "io" self.text["font"] = self._workbench.get_font("IOFont") # mark first line of io if self._before_io: self._insert_text_directly(msg.data[0], ("io", msg.stream_name, "vertically_spaced")) self._before_io = False self._insert_text_directly(msg.data[1:], ("io", msg.stream_name)) else: self._insert_text_directly(msg.data, ("io", msg.stream_name)) self.text.mark_set("output_end", self.text.index("end-1c")) self.text.see("end") elif isinstance(msg, ToplevelResponse): self.text_mode = "toplevel" self.text["font"] = self._workbench.get_font("EditorFont") self._before_io = True if hasattr(msg, "error"): self._insert_text_directly(msg.error + "\n", ("toplevel", "error")) if hasattr(msg, "value_info"): value_repr = shorten_repr(msg.value_info.repr, 10000) if value_repr != "None": if self._workbench.in_heap_mode(): value_repr = memory.format_object_id(msg.value_info.id) object_tag = "object_" + str(msg.value_info.id) self._insert_text_directly(value_repr + "\n", ("toplevel", "value", object_tag)) if running_on_mac_os(): sequence = "<Command-Button-1>" else: sequence = "<Control-Button-1>" self.text.tag_bind(object_tag, sequence, lambda _: self._workbench.event_generate( "ObjectSelect", object_id=msg.value_info.id)) self.active_object_tags.add(object_tag) self.text.mark_set("output_end", self.text.index("end-1c")) self._insert_prompt() self._try_submit_input() self.text.see("end") # TODO: show cwd if it has changed """ if hasattr(msg, "event") and msg.event == "reset": # make current dir visible (again) self.submit_magic_command("%cd " + self._workbench.get_runner().get_cwd() + "\n") """ else: pass
def __init__(self, master, workbench): tk.Toplevel.__init__(self, master, borderwidth=15, takefocus=1) self._workbench = workbench self.codeview = master; self._init_found_tag_styles(); #sets up the styles used to highlight found strings #references to the current set of passive found tags e.g. all words that match the searched term but are not the active string self.passive_found_tags = set() self.active_found_tag = None #reference to the currently active (centered) found string #if find dialog was used earlier then put the previous search word to the Find entry field #TODO - refactor this, there must be a better way try: #if find dialog was used earlier then this is present FindDialog.last_searched_word = FindDialog.last_searched_word except: FindDialog.last_searched_word = None #if this variable does not exist then this is the first time find dialog has been launched #a tuple containing the start and indexes of the last processed string #if the last action was find, then the end index is start index + 1 #if the last action was replace, then the indexes correspond to the start #and end of the inserted word self.last_processed_indexes = None self.last_search_case = None #case sensitivity value used during the last search #set up window display self.geometry("+%d+%d" % (master.winfo_rootx() + master.winfo_width() // 2, master.winfo_rooty() + master.winfo_height() // 2 - 150)) self.title("Find & Replace") if misc_utils.running_on_mac_os(): self.configure(background="systemSheetBackground") self.resizable(height=tk.FALSE, width=tk.FALSE) self.transient(master) self.grab_set() self.protocol("WM_DELETE_WINDOW", self._ok) #Find text label self.find_label = ttk.Label(self, text="Find:"); #TODO - text to resources package self.find_label.grid(column=0, row=0); #Find text field self.find_entry_var = tk.StringVar() self.find_entry = ttk.Entry(self, textvariable=self.find_entry_var); self.find_entry.grid(column=1, row=0, columnspan=2, padx=5); if FindDialog.last_searched_word is not None: self.find_entry.insert(0, FindDialog.last_searched_word) self.find_entry.focus_force(); #Replace text label self.replace_label = ttk.Label(self, text="Replace with:"); #TODO - text to resources package self.replace_label.grid(column=0, row=1); #Replace text field self.replace_entry = ttk.Entry(self); self.replace_entry.grid(column=1, row=1, columnspan=2, padx=5); #Info text label (invisible by default, used to tell user that searched string was not found etc) self.infotext_label_var = tk.StringVar(); self.infotext_label_var.set(""); self.infotext_label = ttk.Label(self, textvariable=self.infotext_label_var, foreground="red"); #TODO - style to conf self.infotext_label.grid(column=0, row=2, columnspan=3,pady=3); #Case checkbox self.case_var = tk.IntVar() self.case_checkbutton = ttk.Checkbutton(self,text="Case sensitive",variable=self.case_var); #TODO - text to resources self.case_checkbutton.grid(column=0, row=3) #Direction radiobuttons self.direction_var = tk.IntVar() self.up_radiobutton = ttk.Radiobutton(self, text="Up", variable=self.direction_var, value=1) self.up_radiobutton.grid(column=1, row=3) self.down_radiobutton = ttk.Radiobutton(self, text="Down", variable=self.direction_var, value=2) self.down_radiobutton.grid(column=2, row=3) self.down_radiobutton.invoke() #Find button - goes to the next occurrence self.find_button = ttk.Button(self, text="Find", command=self._perform_find) #TODO - text to resources self.find_button.grid(column=3, row=0, sticky=tk.W + tk.E); self.find_button.config(state='disabled') #Replace button - replaces the current occurrence, if it exists self.replace_button = ttk.Button(self, text="Replace", command=self._perform_replace) #TODO - text to resources self.replace_button.grid(column=3, row=1, sticky=tk.W + tk.E); self.replace_button.config(state='disabled') #Replace + find button - replaces the current occurence and goes to next self.replace_and_find_button = ttk.Button(self, text="Replace+Find", command=self._perform_replace_and_find) #TODO - text to resources self.replace_and_find_button.grid(column=3, row=2, sticky=tk.W + tk.E); self.replace_and_find_button.config(state='disabled') #Replace all button - replaces all occurrences self.replace_all_button = ttk.Button(self, text="Replace all", command=self._perform_replace_all) #TODO - text to resources self.replace_all_button.grid(column=3, row=3, sticky=tk.W + tk.E); if FindDialog.last_searched_word == None: self.replace_all_button.config(state='disabled') #create bindings self.bind('<Escape>', self._ok) self.find_entry.bind('<Return>', self._perform_find) self.find_entry.bind('<Return>', self._perform_find) self.find_entry_var.trace('w', self._update_button_statuses) self._update_button_statuses() self.wait_window()
def load_plugin(workbench): if running_on_mac_os(): _set_up_mac_specific_stuff()
def __init__(self, master, version): tk.Toplevel.__init__(self, master, borderwidth=15) #self.geometry("200x200") # TODO: position in the center of master self.geometry("+%d+%d" % (master.winfo_rootx() + master.winfo_width() // 2 - 50, master.winfo_rooty() + master.winfo_height() // 2 - 150)) self.title("About Thonny") if misc_utils.running_on_mac_os(): self.configure(background="systemSheetBackground") self.resizable(height=tk.FALSE, width=tk.FALSE) self.transient(master) self.grab_set() self.protocol("WM_DELETE_WINDOW", self._ok) #bg_frame = ttk.Frame(self) # gives proper color in aqua #bg_frame.grid() heading_font = font.nametofont("TkHeadingFont").copy() heading_font.configure(size=19, weight="bold") heading_label = ttk.Label(self, text="Thonny " + str(version), font=heading_font) heading_label.grid() url = "http://thonny.cs.ut.ee" url_font = font.nametofont("TkDefaultFont").copy() url_font.configure(underline=1) url_label = ttk.Label(self, text=url, cursor="hand2", foreground="blue", font=url_font,) url_label.grid() url_label.bind("<Button-1>", lambda _:webbrowser.open(url)) python_version = ".".join(map(str, sys.version_info[:3])) if sys.version_info[3] != "final": python_version += "-" + sys.version_info[3] platform_label = ttk.Label(self, justify=tk.CENTER, text=platform.system() + " " + platform.release() + " " + self.get_os_word_size_guess() + "\n" + "Python " + python_version + " (" + ("64" if sys.maxsize > 2**32 else "32")+ " bit)\n" + "Tk " + self.tk.call('info', 'patchlevel')) platform_label.grid(pady=20) license_font = font.nametofont("TkDefaultFont").copy() license_font.configure(size=7) license_label = ttk.Label(self, text="Coppyright (©) 2014 Aivar Annamaa\n" + "This program comes with\n" + "ABSOLUTELY NO WARRANTY!\n" + "It is free software, and you are welcome to\n" + "redistribute it under certain conditions, see\n" + "http://www.gnu.org/licenses/gpl-3.0.txt\n" + "for details\n", justify=tk.CENTER, font=license_font) license_label.grid() ok_button = ttk.Button(self, text="OK", command=self._ok) ok_button.grid() ok_button.focus_set() self.bind('<Return>', self._ok) self.bind('<Escape>', self._ok) self.wait_window()