class FileTransfer(object): def __init__(self, session, do_ask = True): self._transfer_task = None self._session = session self._transfered = 0 self._total = 1 self.__on_progress_task = Task(self._on_progress, .001, start=False) self._do_ask = do_ask def _upload(self, l_f, r_f, r_home = None, r_pwd = None): if not os.path.isfile(l_f): self._session.report_error("local file:{} is not existing, upload failed".format(l_f)) return if len(r_f) == 0: r_f = '/'.join([".", os.path.basename(l_f)]) elif len(os.path.basename(r_f)) == 0: r_f = '/'.join([r_f, os.path.basename(l_f)]) self._transfer_thread = MyThread(target=lambda: self._session.transfer_file(l_f, r_f, r_home, r_pwd, True, self.on_progress)) self._transfer_thread.start() def on_progress(self, transfered, total): self._transfered, self._total = transfered, total self.__on_progress_task.start() def _on_progress(self): pass def _download(self, l_f, r_f, r_home = None, r_pwd = None): if len(r_f) == 0: self._session.report_error("remote file is not existing, download failed") return if len(l_f) == 0: l_f = os.path.join('.', os.path.basename(r_f)) l_f = os.path.expandvars(os.path.expanduser(l_f)) if os.path.isdir(l_f): l_f = os.path.join(l_f, os.path.basename(r_f)) if self._do_ask and os.path.isfile(l_f): if ask(u'file:{} exists, overwrite?'.format(l_f)) != 1: return self._transfer_thread = MyThread(target=lambda: self._session.transfer_file(l_f, r_f, r_home, r_pwd, False, self.on_progress)) self._transfer_thread.start()
class DataControlWindow(Window): """Controls the data everyone sees.""" resizable = True item_width = 200 duration = datetime.timedelta(minutes=15) time = datetime.datetime(2011, 8, 8, 18, 0, 0) def __init__(self, manager): super(DataControlWindow, self).__init__(title="Data Control") self.manager = manager duration_text = ":".join( ( "%02d" % (self.duration.seconds // 3600), "%02d" % ((self.duration.seconds % 3600) // 60), "%02d" % (self.duration.seconds % 60), ) ) self.folder_label = Label(text=manager.folder) self.time_field = TextField( text=self.time.strftime("%Y/%m/%d %H:%M:%S"), width=self.item_width, enter_action=self.update ) self.duration_field = TextField(text=duration_text, width=self.item_width, enter_action=self.update) self.live_checkbox = CheckBox("Live", action=self.toggle_live) self.revsync_checkbox = CheckBox("Rev-sync", action=self.toggle_revsync) self.averaging_checkbox = CheckBox("Average data", action=self.toggle_averaging) self.convert_checkbox = CheckBox("Convert files", action=self.toggle_convert) self.update_button = Button(title="Refresh", action=self.update) self.auto_updater = Task(self.update, AUTO_UPDATE_INTERVAL, start=False, repeat=True) time_row = Row([Label("Start: "), self.time_field]) duration_row = Row([Label("Duration: "), self.duration_field]) self.place_column( [ self.folder_label, time_row, duration_row, self.live_checkbox, self.revsync_checkbox, self.averaging_checkbox, self.convert_checkbox, self.update_button, ], left=PADDING, top=PADDING, ) self.shrink_wrap() def toggle_live(self): self.update() if self.live_checkbox.value: self.time_field.enabled = False self.auto_updater.start() else: self.time_field.enabled = True self.auto_updater.stop() def toggle_revsync(self): TELESCOPE_10GHZ.sync = self.revsync_checkbox.value TELESCOPE_15GHZ.sync = self.revsync_checkbox.value def toggle_averaging(self): self.manager.averaging = self.averaging_checkbox.value self.manager.clear_cache() def toggle_convert(self): self.manager.set_convert(self.convert_checkbox.value) def update(self): try: duration = parse_timedelta(self.duration_field.text) if duration.seconds < 0: raise ValueError() self.duration = duration except ValueError: alert("stop", "Invalid duration. Requires 'hour:minute:second'.") return if self.live_checkbox.value: try: end = self.manager.get_last_filetime() except IndexError: print "No _ext.fits files exist in the given directory tree." return start = end - self.duration else: try: self.time = parse_datetime(self.time_field.text) except ValueError: alert("stop", "Invalid time. Requires 'year/month/day hour:minute:second'.") return start = self.time end = start + self.duration self.manager.set_interval(start, end) self.manager.read_data() self.update_plotwindow() def set_plotwindow(self, plotwindow): """Save reference to the plot window to trigger updates""" self._plotwindow = plotwindow def update_plotwindow(self): """Trigger update of the attached plot window""" self._plotwindow.plot_update()
class TerminalPyGUIViewBase(TerminalWidget): def __init__(self, **kwargs): self.padding_x = 5 self.padding_y = 5 self.session = None self.selection_color = [0.1843, 0.6549, 0.8313, .5] self._width_cache = {} self._lock = threading.Lock() self._refresh_task = Task(self.__refresh, .02, False, False) TerminalWidget.__init__(self, **kwargs) self._generic_tabbing = False def gen_render_color(self, color_spec): c = map(lambda x: x / 255, map(float, color_spec)) return c def __refresh(self): if self.session and not self.session.stopped: if pymterm.debug_log: logging.getLogger('term_pygui').debug('refresh called') self.invalidate() self.update() def refresh(self): self._refresh_task.start() def key_down(self, e): key_state = KeyState(e) if self.session.terminal.process_key(key_state): if pymterm.debug_log: logging.getLogger('term_pygui').debug(' processed by term_gui') return v, handled = term.term_keyboard.translate_key(self.session.terminal, key_state) if len(v) > 0: self.session.send(v) elif len(e.char) > 0: self.session.send(e.char) elif key_state.has_text(): self.session.send(key_state.get_text()) if pymterm.debug_log: logging.getLogger('term_pygui').debug( ' - translated %r, %d' % (v, handled)) # Return True to accept the key. Otherwise, it will be used by # the system. return def destroy(self): self.session.stop() super(TerminalPyGUIViewBase, self).destroy() def resized(self, delta): w, h = self.size if w <= 0 or h <= 0: return w -= self.padding_x * 2 h -= self.padding_y * 2 self._calculate_visible_rows(h) self._calculate_visible_cols(w) if pymterm.debug_log: logging.getLogger('term_pygui').debug('on size: cols={} rows={} width={} height={} size={} pos={}'.format(self.visible_cols, self.visible_rows, w, h, self.size, self.position)) if self.session: self.session.resize_pty(self.visible_cols, self.visible_rows, w, h) self.session.terminal.resize_terminal() if pymterm.debug_log: logging.getLogger('term_pygui').debug('on size done: cols={} rows={} width={} height={} size={} pos={}'.format(self.visible_cols, self.visible_rows, w, h, self.size, self.position)) def _calculate_visible_rows(self, h): self.visible_rows = int(h / self._get_line_height()) if self.visible_rows <= 0: self.visible_rows = 1 def _calculate_visible_cols(self, w): self.visible_cols = int(w / self._get_col_width()) if self.visible_cols <= 0: self.visible_cols = 1 def copy_to_clipboard(self, data): application().set_clipboard(data.encode('utf-8')) def paste_from_clipboard(self): return application().get_clipboard().decode('utf-8') def mouse_down(self, event): self.become_target() self.cancel_selection() self._selection_from = self._selection_to = \ self._get_cursor_from_xy(*event.position) mouse_tracker = self.track_mouse() while True: event = mouse_tracker.next() to = self._get_cursor_from_xy(*event.position) if to != self._selection_to: self._selection_to = to self.session.terminal.set_selection(self._selection_from, self._selection_to) self.refresh() if event.kind == 'mouse_up': try: mouse_tracker.next() except StopIteration: pass break def _get_cursor_from_xy(self, x, y): '''Return the (row, col) of the cursor from an (x, y) position. ''' padding_left = self.padding_x padding_top = self.padding_y l = self.lines dy = self._get_line_height() cx = x cy = y - padding_top cy = int(boundary(round(cy / dy - 0.5), 0, len(l) - 1)) if cy >= len(l) or cy < 0: return 0, 0 # reserve double width padding char to calculate width text = self.norm_text(l[cy].get_text(raw=True), False) width_before = 0 for i in range(0, len(text)): if text[i] == '\000': continue self_width = self._get_col_width() if i + 1 < len(text) and text[i + 1] == '\000': self_width += self._get_col_width() if width_before + self_width * 0.6 + padding_left > cx: return i, cy width_before += self_width return l[cy].cell_count(), cy def setup_menus(self, m): if self.session and self.session.terminal: m.copy_cmd.enabled = self.session.terminal.has_selection() m.paste_cmd.enabled = self.session.terminal.has_selection() or application().query_clipboard() m.clear_cmd.enabled = self.session.terminal.has_selection() m.transfer_file_cmd.enabled = hasattr(self.session, "transfer_file") else: m.transfer_file_cmd.enabled = False m.copy_cmd.enabled = False m.paste_cmd.enabled = False m.clear_cmd.enabled = False def next_handler(self): return application().target_window def copy_cmd(self): if self.session and self.session.terminal: self.session.terminal.copy_data() def paste_cmd(self): if self.session and self.session.terminal: self.session.terminal.paste_data() @lru_cache(1) def _get_col_width(self): f = self._get_font() col_width = max(map(lambda x:self._get_width(f, x), SINGLE_WIDE_CHARACTERS)) if pymterm.debug_log: logging.getLogger('term_pygui').debug('col_width:{}'.format(col_width)) return col_width def get_prefered_size(self): w = int(self._get_col_width() * self.visible_cols + self.padding_x * 2 + 0.5) h = int(self._get_line_height() * self.visible_rows + self.padding_y * 2 + 0.5) return (w, h) def _get_width(self, f = None, t = ''): w, h = self._get_size(f, t) return w def _get_cache_key(self, line): return line.get_hash_value() def _refresh_font(self, cfg): self.font_file, self.font_name, self.font_size = cfg.get_font_info() @lru_cache(1) def _get_line_height(self): f = self._get_font() w, h = self._get_size(f, SINGLE_WIDE_CHARACTERS) return h + 1 def _paint_line_surface(self, v_context, line_surf, x, y): pass def _prepare_line_context(self, line_surf, x, y, width, height): pass def _layout_line_text(self, context, text, font, l, t, w, h, cur_f_color): pass def _fill_line_background(self, line_context, cur_b_color, l, t, w, h): pass def _draw_layouted_line_text(self, line_context, layout, cur_f_color, l, t, w, h): pass def _do_cache(self): return True def _draw_canvas(self, v_context): def locked_draw_canvas(): self._real_draw_canvas(v_context) self.session.terminal.lock_display_data_exec(locked_draw_canvas) def _real_draw_canvas(self, v_context): x = self.padding_x b_x = self.padding_x y = self.padding_y lines = self.lines c_col, c_row = self.term_cursor font = self._get_font(); line_height = self._get_line_height() col_width = int(self._get_col_width()) width, height = self.size for i in range(len(lines)): x = b_x = self.padding_x line = lines[i] col = 0 last_col = 0 text = '' if self._do_cache(): key = self._get_cache_key(line) cached_line_surf = _get_surf(key, width, line_height) line_surf = cached_line_surf.surf if cached_line_surf.cached: self._paint_line_surface(v_context, line_surf, 0, y) y += line_height continue cached_line_surf.cached = self._do_cache() else: line_surf = create_line_surface(width, line_height) line_context = self._prepare_line_context(line_surf, x, y, width, line_height) def render_text(xxxx, cell): t = cell.get_char() if len(t) == 0: return xxxx t = self.norm_text(t) if len(t) == 0: return xxxx cur_f_color, cur_b_color = self.session.terminal.determin_colors(cell.get_attr()) wide_char = cell.is_widechar() t_w, t_h, layout = self._layout_line_text(line_context, t, font, xxxx, y, col_width * 2 if wide_char else col_width, line_height, cur_f_color) self._draw_layouted_line_text(line_context, layout, cur_f_color, xxxx, 0, t_w, t_h) if cell.get_attr().has_mode(TextMode.BOLD): self._draw_layouted_line_text(line_context, layout, cur_f_color, xxxx + 1, 1, t_w, t_h) return xxxx + t_w last_b_color = self.session.cfg.default_background_color last_col = 0 cur_col = 0 for cell in line.get_cells(): if cell.get_char() == '\000': cur_col += 1 continue cur_f_color, cur_b_color = self.session.terminal.determin_colors(cell.get_attr()) t_w, t_h, layout = self._layout_line_text(line_context, cell.get_char(), font, 0, 0, col_width * 2 if cell.is_widechar() else col_width, line_height, cur_f_color) if cur_b_color != last_b_color: if last_b_color != self.session.cfg.default_background_color and cur_col > last_col: self._fill_line_background(line_context, last_b_color, b_x + last_col * col_width, 0, col_width * (cur_col - last_col), line_height) last_b_color = cur_b_color last_col = cur_col cur_col += 1 if last_col < cur_col: if last_b_color != self.session.cfg.default_background_color: self._fill_line_background(line_context, last_b_color, b_x + last_col * col_width, 0, col_width * (cur_col - last_col), line_height) for cell in line.get_cells(): if cell.get_char() != ' ': render_text(b_x, cell) b_x += col_width self._paint_line_surface(v_context, line_surf, 0, y) y += line_height
class TerminalPyGUIViewBase(TerminalWidget): def __init__(self, **kwargs): self.padding_x = 5 self.padding_y = 5 self.session = None self.selection_color = [0.1843, 0.6549, 0.8313, .5] self._width_cache = {} self._lock = threading.Lock() self._refresh_task = Task(self.__refresh, .02, False, False) TerminalWidget.__init__(self, **kwargs) self._generic_tabbing = False def _get_color(self, color_spec): key = repr(color_spec) if key in _color_map: return _color_map[key] c = map(lambda x: x / 255, map(float, color_spec)) _color_map[key] = r = rgb(*c) return r def __refresh(self): if self.session and not self.session.stopped: logging.getLogger('term_pygui').debug('refresh called') self.invalidate() self.update() def refresh(self): self._refresh_task.start() def key_down(self, e): key = term_pygui_key_translate.translate_key(e) keycode = (e.char, key) text = key if len(key) == 1 and key[0] in string.printable else e.char if len(e.char) > 0 else None modifiers = [] if e.option: modifiers.append('alt') if e.control: modifiers.append('ctrl') if e.shift: modifiers.append('shift') logging.getLogger('term_pygui').debug('view key_down:{}'.format(e)) logging.getLogger('term_pygui').debug('view key_down:{}, {}, {}'.format(keycode, text, modifiers)) if self.session.terminal.process_key(keycode, text, modifiers): logging.getLogger('term_pygui').debug(' processed by term_gui') return v, handled = term.term_keyboard.translate_key(self.session.terminal, keycode, text, modifiers) if len(v) > 0: self.session.send(v) elif len(e.char) > 0: self.session.send(e.char) elif text: self.session.send(text) logging.getLogger('term_pygui').debug(' - translated %r, %d' % (v, handled)) # Return True to accept the key. Otherwise, it will be used by # the system. return def destroy(self): self.session.stop() super(TerminalPyGUIViewBase, self).destroy() def resized(self, delta): w, h = self.size if w <= 0 or h <=0: return w -= self.padding_x * 2 h -= self.padding_y * 2 self._calculate_visible_rows(h) self._calculate_visible_cols(w) logging.getLogger('term_pygui').debug('on size: cols={} rows={} width={} height={} size={} pos={}'.format(self.visible_cols, self.visible_rows, w, h, self.size, self.position)) if self.session: self.session.resize_pty(self.visible_cols, self.visible_rows, w, h) self.session.terminal.resize_terminal() logging.getLogger('term_pygui').debug('on size done: cols={} rows={} width={} height={} size={} pos={}'.format(self.visible_cols, self.visible_rows, w, h, self.size, self.position)) def _calculate_visible_rows(self, h): self.visible_rows = int(h / self._get_line_height()) if self.visible_rows <= 0: self.visible_rows = 1 def _calculate_visible_cols(self, w): self.visible_cols = int(w / self._get_col_width()) if self.visible_cols <= 0: self.visible_cols = 1 def copy_to_clipboard(self, data): application().set_clipboard(data.encode('utf-8')) def paste_from_clipboard(self): return application().get_clipboard().decode('utf-8') def mouse_down(self, event): self.become_target() self.cancel_selection() self._selection_from = self._selection_to = self._get_cursor_from_xy(*event.position) mouse_tracker = self.track_mouse() while True: event = mouse_tracker.next() self._selection_to = self._get_cursor_from_xy(*event.position) self.refresh() if event.kind == 'mouse_up': try: mouse_tracker.next() except StopIteration: pass break def _get_cursor_from_xy(self, x, y): '''Return the (row, col) of the cursor from an (x, y) position. ''' padding_left = self.padding_x padding_top = self.padding_y l = self.lines dy = self._get_line_height() cx = x cy = y - padding_top cy = int(boundary(round(cy / dy - 0.5), 0, len(l) - 1)) if cy >= len(l) or cy < 0: return 0, 0 text = self.norm_text(''.join(l[cy]), False)#reserve double width padding char to calculate width width_before = 0 for i in range(0, len(text)): if text[i] == '\000': continue self_width = self._get_col_width() if i + 1 < len(text) and text[i + 1] == '\000': self_width += self._get_col_width() if width_before + self_width * 0.6 + padding_left > cx: return i, cy width_before += self_width return len(l[cy]), cy def _merge_color(self, c1, c2): return [c1[i] * c2[i] for i in range(len(c1))] def setup_menus(self, m): if self.session and self.session.terminal: m.copy_cmd.enabled = self.session.terminal.has_selection() m.paste_cmd.enabled = self.session.terminal.has_selection() or application().query_clipboard() m.clear_cmd.enabled = self.session.terminal.has_selection() m.transfer_file_cmd.enabled = hasattr(self.session, "transfer_file") else: m.transfer_file_cmd.enabled = False m.copy_cmd.enabled = False m.paste_cmd.enabled = False m.clear_cmd.enabled = False def next_handler(self): return application().target_window def copy_cmd(self): if self.session and self.session.terminal: self.session.terminal.copy_data() def paste_cmd(self): if self.session and self.session.terminal: self.session.terminal.paste_data() @lru_cache(1) def _get_col_width(self): f = self._get_font() col_width = max(map(lambda x:self._get_width(f, x), SINGLE_WIDE_CHARACTERS)) logging.getLogger('term_pygui').info('col_width:{}'.format(col_width)) return col_width def get_prefered_size(self): w = int(self._get_col_width() * self.visible_cols + self.padding_x * 2 + 0.5) h = int(self._get_line_height() * self.visible_rows + self.padding_y * 2 + 0.5) return (w, h) def _get_width(self, f = None, t = ''): w, h = self._get_size(f, t) return w def _get_cache_key(self, line): return line.get_hash_value() def _get_line_cache_key(self, line): return repr(line) def _get_line_option_cache_key(self, line_option): return repr(line_option) def _refresh_font(self, cfg): self.font_file, self.font_name, self.font_size = cfg.get_font_info() @lru_cache(1) def _get_line_height(self): f = self._get_font() w, h = self._get_size(f, SINGLE_WIDE_CHARACTERS) return h + 1 def _paint_line_surface(self, v_context, line_surf, x, y): pass def _prepare_line_context(self, line_surf, x, y, width, height): pass def _layout_line_text(self, context, text, font, l, t, w, h, cur_f_color): pass def _fill_line_background(self, line_context, cur_b_color, l, t, w, h): pass def _draw_layouted_line_text(self, line_context, layout, cur_f_color, l, t, w, h): pass def _do_cache(self): return True def _draw_canvas(self, v_context): x = self.padding_x b_x = self.padding_x y = self.padding_y lines = [line[:] for line in self.lines] line_options = [line_option[:] for line_option in self.line_options] c_col, c_row = self.term_cursor s_f, s_t = self.get_selection() s_f_c, s_f_r = s_f s_t_c, s_t_r = s_t last_f_color = self.session.cfg.default_foreground_color last_b_color = self.session.cfg.default_background_color last_mode = 0 font = self._get_font(); line_height = self._get_line_height() col_width = int(self._get_col_width()) width, height = self.size for i in range(len(lines)): x = b_x = self.padding_x line = lines[i] line_option = line_options[i] if i < len(line_options) else [] last_mode &= ~TextMode.CURSOR last_mode &= ~TextMode.SELECTION # temprary add cusor and selection mode if self.cursor_visible and i == c_row: reserve(line_option, c_col + 1, TextAttribute(None, None, None)) reserve(line, c_col + 1, ' ') line_option[c_col].set_mode(TextMode.CURSOR) if s_f != s_t: if s_f_r == s_t_r and i == s_f_r: reserve(line_option, s_t_c, TextAttribute(None, None, None)) for mm in range(s_f_c, s_t_c): line_option[mm].set_mode(TextMode.SELECTION) else: if i == s_f_r: reserve(line_option, len(line), TextAttribute(None, None, None)) for mm in range(s_f_c, len(line)): line_option[mm].set_mode(TextMode.SELECTION) elif i == s_t_r: reserve(line_option, s_t_c, TextAttribute(None, None, None)) for mm in range(0, s_t_c): line_option[mm].set_mode(TextMode.SELECTION) elif i > s_f_r and i < s_t_r: reserve(line_option, len(line), TextAttribute(None, None, None)) for mm in range(len(line)): line_option[mm].set_mode(TextMode.SELECTION) col = 0 last_col = 0 text = '' last_option = None if self._do_cache(): key = self._get_cache_key(line, line_option) cached_line_surf = _get_surf(key, width, line_height) line_surf = cached_line_surf.surf if cached_line_surf.cached: self._paint_line_surface(v_context, line_surf, 0, y) y += line_height continue cached_line_surf.cached = self._do_cache() else: line_surf = create_line_surface(width, line_height) line_context = self._prepare_line_context(line_surf, x, y, width, line_height) def render_text(t, xxxx, wide_char): cur_f_color, cur_b_color = last_f_color, last_b_color if len(t) == 0: return xxxx t = self.norm_text(t) if len(t) == 0: return xxxx if last_mode & TextMode.REVERSE: cur_f_color, cur_b_color = last_b_color, last_f_color if last_mode & TextMode.CURSOR: cur_f_color, cur_b_color = cur_b_color, self.session.cfg.default_cursor_color if last_mode & TextMode.SELECTION: cur_f_color = self._merge_color(cur_f_color, self.selection_color) cur_b_color = self._merge_color(cur_b_color, self.selection_color) t_w, t_h, layout = self._layout_line_text(line_context, t, font, xxxx, y, col_width * 2 if wide_char else col_width, line_height, cur_f_color) if cur_b_color != self.session.cfg.default_background_color: self._fill_line_background(line_context, cur_b_color, xxxx, 0, max(t_w, col_width * 2 if wide_char else col_width), t_h) self._draw_layouted_line_text(line_context, layout, cur_f_color, xxxx, 0, t_w, t_h) return xxxx + t_w for col in range(len(line_option)): if line_option[col] is None: continue if last_option == line_option[col]: continue f_color, b_color, mode = line_option[col] n_f_color, n_b_color, n_mode = last_f_color, last_b_color, last_mode # foreground if f_color and len(f_color) > 0: n_f_color = f_color elif f_color is None: n_f_color = self.session.cfg.default_foreground_color # background if b_color and len(b_color) > 0: n_b_color = b_color elif b_color is None: n_b_color = self.session.cfg.default_background_color #mode if mode is not None: n_mode = mode else: n_mode &= ~TextMode.CURSOR n_mode &= ~TextMode.SELECTION if (n_f_color, n_b_color, n_mode) == (last_f_color, last_b_color, last_mode): continue if last_col < col: for r_col in range(last_col, col): if r_col >= len(line): continue wide_char = False if r_col + 1 < len(line): wide_char = line[r_col + 1] == '\000' render_text(line[r_col], b_x, wide_char) b_x += col_width last_col = col last_option = line_option[col] last_f_color, last_b_color, last_mode = n_f_color, n_b_color, n_mode if last_col < len(line): for r_col in range(last_col, len(line)): wide_char = False if r_col + 1 < len(line): wide_char = line[r_col + 1] == '\000' render_text(line[r_col], b_x, wide_char) b_x += col_width self._paint_line_surface(v_context, line_surf, 0, y) y += line_height