diff options
Diffstat (limited to 'ranger/gui/widgets/browsercolumn.py')
-rw-r--r-- | ranger/gui/widgets/browsercolumn.py | 758 |
1 files changed, 379 insertions, 379 deletions
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 3324d9a8..a6653070 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -13,382 +13,382 @@ from ranger.fsobject import BAD_INFO from ranger.ext.widestring import WideString class BrowserColumn(Pager): - main_column = False - display_infostring = False - scroll_begin = 0 - target = None - last_redraw_time = -1 - ellipsis = { False: '~', True: '…' } - - old_dir = None - old_thisfile = None - - def __init__(self, win, level): - """ - win = the curses window object of the BrowserView - level = what to display? - - level >0 => previews - level 0 => current file/directory - level <0 => parent directories - """ - Pager.__init__(self, win) - Widget.__init__(self, win) - self.level = level - self.original_level = level - - self.settings.signal_bind('setopt.display_size_in_main_column', - self.request_redraw, weak=True) - - def request_redraw(self): - self.need_redraw = True - - def resize(self, y, x, hei, wid): - Widget.resize(self, y, x, hei, wid) - - def click(self, event): - """Handle a MouseEvent""" - direction = event.mouse_wheel_direction() - if not (event.pressed(1) or event.pressed(3) or direction): - return False - - if self.target is None: - pass - - elif self.target.is_directory: - if self.target.accessible and self.target.content_loaded: - index = self.scroll_begin + event.y - self.y - - if direction: - if self.level == -1: - self.fm.move_parent(direction) - else: - return False - elif event.pressed(1): - if not self.main_column: - self.fm.enter_dir(self.target.path) - - if index < len(self.target): - self.fm.move(to=index) - elif event.pressed(3): - try: - clicked_file = self.target.files[index] - if clicked_file.is_directory: - self.fm.enter_dir(clicked_file.path) - elif self.level == 0: - self.fm.thisdir.move_to_obj(clicked_file) - self.fm.execute_file(clicked_file) - except: - pass - - else: - if self.level > 0 and not direction: - self.fm.move(right=0) - - return True - - def execute_curses_batch(self, line, commands): - """ - Executes a list of "commands" which can be easily cached. - - "commands" is a list of lists. Each element contains - a text and an attribute. First, the attribute will be - set with attrset, then the text is printed. - - Example: - execute_curses_batch(0, [["hello ", 0], ["world", curses.A_BOLD]]) - """ - try: - self.win.move(line, 0) - except: - return - for entry in commands: - text, attr = entry - self.addstr(text, attr) - - def has_preview(self): - if self.target is None: - return False - - if self.target.is_file: - if not self.target.has_preview(): - return False - - if self.target.is_directory: - if self.level > 0 and not self.settings.preview_directories: - return False - - return True - - def level_shift(self, amount): - self.level = self.original_level + amount - - def level_restore(self): - self.level = self.original_level - - def poke(self): - Widget.poke(self) - self.target = self.fm.thistab.at_level(self.level) - - def draw(self): - """Call either _draw_file() or _draw_directory()""" - if self.target != self.old_dir: - self.need_redraw = True - self.old_dir = self.target - - if self.target: # don't garbage collect this directory please - self.target.use() - - if self.target and self.target.is_directory \ - and (self.level <= 0 or self.settings.preview_directories): - if self.target.pointed_obj != self.old_thisfile: - self.need_redraw = True - self.old_thisfile = self.target.pointed_obj - - if self.target.load_content_if_outdated() \ - or self.target.sort_if_outdated() \ - or self.last_redraw_time < self.target.last_update_time: - self.need_redraw = True - - if self.need_redraw: - self.win.erase() - if self.target is None: - pass - elif self.target.is_file: - Pager.open(self) - self._draw_file() - elif self.target.is_directory: - self._draw_directory() - Widget.draw(self) - self.need_redraw = False - self.last_redraw_time = time() - - def _draw_file(self): - """Draw a preview of the file, if the settings allow it""" - self.win.move(0, 0) - if not self.target.accessible: - self.addnstr("not accessible", self.wid) - Pager.close(self) - return - - if self.target is None or not self.target.has_preview(): - Pager.close(self) - return - - if self.fm.settings.preview_images and self.target.image: - self.set_image(self.target.realpath) - Pager.draw(self) - else: - f = self.target.get_preview_source(self.wid, self.hei) - if f is None: - Pager.close(self) - else: - self.set_source(f) - Pager.draw(self) - - def _draw_directory(self): - """Draw the contents of a directory""" - if self.image: - self.image = None - self.need_clear_image = True - Pager.clear_image(self) - - if self.level > 0 and not self.settings.preview_directories: - return - - base_color = ['in_browser'] - - self.win.move(0, 0) - - if not self.target.content_loaded: - self.color(tuple(base_color)) - self.addnstr("...", self.wid) - self.color_reset() - return - - if self.main_column: - base_color.append('main_column') - - if not self.target.accessible: - self.color(tuple(base_color + ['error'])) - self.addnstr("not accessible", self.wid) - self.color_reset() - return - - if self.target.empty(): - self.color(tuple(base_color + ['empty'])) - self.addnstr("empty", self.wid) - self.color_reset() - return - - self._set_scroll_begin() - - copied = [f.path for f in self.fm.copy_buffer] - ellipsis = self.ellipsis[self.settings.unicode_ellipsis] - - selected_i = self.target.pointer - for line in range(self.hei): - i = line + self.scroll_begin - if line > self.hei: - break - - try: - drawn = self.target.files[i] - except IndexError: - break - - tagged = self.fm.tags and drawn.realpath in self.fm.tags - if tagged: - tagged_marker = self.fm.tags.marker(drawn.realpath) - else: - tagged_marker = " " - - key = (self.wid, selected_i == i, drawn.marked, self.main_column, - drawn.path in copied, tagged_marker, drawn.infostring, - self.fm.do_cut) - - if key in drawn.display_data: - self.execute_curses_batch(line, drawn.display_data[key]) - self.color_reset() - continue - - display_data = [] - drawn.display_data[key] = display_data - - if self.display_infostring and drawn.infostring \ - and self.settings.display_size_in_main_column: - infostring = str(drawn.infostring) + " " - else: - infostring = "" - - this_color = base_color + list(drawn.mimetype_tuple) - text = drawn.basename - - space = self.wid - len(infostring) - if self.main_column: - space -= 2 - elif self.settings.display_tags_in_all_columns: - space -= 1 - - if i == selected_i: - this_color.append('selected') - - if drawn.marked: - this_color.append('marked') - if self.main_column or self.settings.display_tags_in_all_columns: - text = " " + text - - if tagged: - this_color.append('tagged') - - if drawn.is_directory: - this_color.append('directory') - else: - this_color.append('file') - - if drawn.stat: - mode = drawn.stat.st_mode - if mode & stat.S_IXUSR: - this_color.append('executable') - if stat.S_ISFIFO(mode): - this_color.append('fifo') - if stat.S_ISSOCK(mode): - this_color.append('socket') - if drawn.is_device: - this_color.append('device') - - if drawn.path in copied: - this_color.append('cut' if self.fm.do_cut else 'copied') - - if drawn.is_link: - this_color.append('link') - this_color.append(drawn.exists and 'good' or 'bad') - - attr = self.settings.colorscheme.get_attr(*this_color) - - if (self.main_column or self.settings.display_tags_in_all_columns) \ - and tagged and self.wid > 2: - this_color.append('tag_marker') - tag_attr = self.settings.colorscheme.get_attr(*this_color) - display_data.append([tagged_marker, tag_attr]) - else: - text = " " + text - space += 1 - - wtext = WideString(text) - if len(wtext) > space: - wtext = wtext[:max(0, space - 1)] + ellipsis - text = str(wtext) - - display_data.append([text, attr]) - - padding = self.wid - len(wtext) - if tagged and (self.main_column or \ - self.settings.display_tags_in_all_columns): - padding -= 1 - if infostring: - if len(wtext) + 1 + len(infostring) > self.wid: - pass - else: - padding -= len(infostring) - padding = max(0, padding) - infostring = (" " * padding) + infostring - display_data.append([infostring, attr]) - else: - display_data.append([" " * max(0, padding), attr]) - - self.execute_curses_batch(line, display_data) - self.color_reset() - - def _get_scroll_begin(self): - """Determines scroll_begin (the position of the first displayed file)""" - offset = self.settings.scroll_offset - dirsize = len(self.target) - winsize = self.hei - halfwinsize = winsize // 2 - index = self.target.pointer or 0 - original = self.target.scroll_begin - projected = index - original - - upper_limit = winsize - 1 - offset - lower_limit = offset - - if original < 0: - return 0 - - if dirsize < winsize: - return 0 - - if halfwinsize < offset: - return min( dirsize - winsize, max( 0, index - halfwinsize )) - - if original > dirsize - winsize: - self.target.scroll_begin = dirsize - winsize - return self._get_scroll_begin() - - if projected < upper_limit and projected > lower_limit: - return original - - if projected > upper_limit: - return min( dirsize - winsize, - original + (projected - upper_limit)) - - if projected < upper_limit: - return max( 0, - original - (lower_limit - projected)) - - return original - - def _set_scroll_begin(self): - """Updates the scroll_begin value""" - self.scroll_begin = self._get_scroll_begin() - self.target.scroll_begin = self.scroll_begin - - def scroll(self, n): - """scroll down by n lines""" - self.need_redraw = True - self.target.move(down=n) - self.target.scroll_begin += 3 * n - - def __str__(self): - return self.__class__.__name__ + ' at level ' + str(self.level) + main_column = False + display_infostring = False + scroll_begin = 0 + target = None + last_redraw_time = -1 + ellipsis = { False: '~', True: '…' } + + old_dir = None + old_thisfile = None + + def __init__(self, win, level): + """ + win = the curses window object of the BrowserView + level = what to display? + + level >0 => previews + level 0 => current file/directory + level <0 => parent directories + """ + Pager.__init__(self, win) + Widget.__init__(self, win) + self.level = level + self.original_level = level + + self.settings.signal_bind('setopt.display_size_in_main_column', + self.request_redraw, weak=True) + + def request_redraw(self): + self.need_redraw = True + + def resize(self, y, x, hei, wid): + Widget.resize(self, y, x, hei, wid) + + def click(self, event): + """Handle a MouseEvent""" + direction = event.mouse_wheel_direction() + if not (event.pressed(1) or event.pressed(3) or direction): + return False + + if self.target is None: + pass + + elif self.target.is_directory: + if self.target.accessible and self.target.content_loaded: + index = self.scroll_begin + event.y - self.y + + if direction: + if self.level == -1: + self.fm.move_parent(direction) + else: + return False + elif event.pressed(1): + if not self.main_column: + self.fm.enter_dir(self.target.path) + + if index < len(self.target): + self.fm.move(to=index) + elif event.pressed(3): + try: + clicked_file = self.target.files[index] + if clicked_file.is_directory: + self.fm.enter_dir(clicked_file.path) + elif self.level == 0: + self.fm.thisdir.move_to_obj(clicked_file) + self.fm.execute_file(clicked_file) + except: + pass + + else: + if self.level > 0 and not direction: + self.fm.move(right=0) + + return True + + def execute_curses_batch(self, line, commands): + """ + Executes a list of "commands" which can be easily cached. + + "commands" is a list of lists. Each element contains + a text and an attribute. First, the attribute will be + set with attrset, then the text is printed. + + Example: + execute_curses_batch(0, [["hello ", 0], ["world", curses.A_BOLD]]) + """ + try: + self.win.move(line, 0) + except: + return + for entry in commands: + text, attr = entry + self.addstr(text, attr) + + def has_preview(self): + if self.target is None: + return False + + if self.target.is_file: + if not self.target.has_preview(): + return False + + if self.target.is_directory: + if self.level > 0 and not self.settings.preview_directories: + return False + + return True + + def level_shift(self, amount): + self.level = self.original_level + amount + + def level_restore(self): + self.level = self.original_level + + def poke(self): + Widget.poke(self) + self.target = self.fm.thistab.at_level(self.level) + + def draw(self): + """Call either _draw_file() or _draw_directory()""" + if self.target != self.old_dir: + self.need_redraw = True + self.old_dir = self.target + + if self.target: # don't garbage collect this directory please + self.target.use() + + if self.target and self.target.is_directory \ + and (self.level <= 0 or self.settings.preview_directories): + if self.target.pointed_obj != self.old_thisfile: + self.need_redraw = True + self.old_thisfile = self.target.pointed_obj + + if self.target.load_content_if_outdated() \ + or self.target.sort_if_outdated() \ + or self.last_redraw_time < self.target.last_update_time: + self.need_redraw = True + + if self.need_redraw: + self.win.erase() + if self.target is None: + pass + elif self.target.is_file: + Pager.open(self) + self._draw_file() + elif self.target.is_directory: + self._draw_directory() + Widget.draw(self) + self.need_redraw = False + self.last_redraw_time = time() + + def _draw_file(self): + """Draw a preview of the file, if the settings allow it""" + self.win.move(0, 0) + if not self.target.accessible: + self.addnstr("not accessible", self.wid) + Pager.close(self) + return + + if self.target is None or not self.target.has_preview(): + Pager.close(self) + return + + if self.fm.settings.preview_images and self.target.image: + self.set_image(self.target.realpath) + Pager.draw(self) + else: + f = self.target.get_preview_source(self.wid, self.hei) + if f is None: + Pager.close(self) + else: + self.set_source(f) + Pager.draw(self) + + def _draw_directory(self): + """Draw the contents of a directory""" + if self.image: + self.image = None + self.need_clear_image = True + Pager.clear_image(self) + + if self.level > 0 and not self.settings.preview_directories: + return + + base_color = ['in_browser'] + + self.win.move(0, 0) + + if not self.target.content_loaded: + self.color(tuple(base_color)) + self.addnstr("...", self.wid) + self.color_reset() + return + + if self.main_column: + base_color.append('main_column') + + if not self.target.accessible: + self.color(tuple(base_color + ['error'])) + self.addnstr("not accessible", self.wid) + self.color_reset() + return + + if self.target.empty(): + self.color(tuple(base_color + ['empty'])) + self.addnstr("empty", self.wid) + self.color_reset() + return + + self._set_scroll_begin() + + copied = [f.path for f in self.fm.copy_buffer] + ellipsis = self.ellipsis[self.settings.unicode_ellipsis] + + selected_i = self.target.pointer + for line in range(self.hei): + i = line + self.scroll_begin + if line > self.hei: + break + + try: + drawn = self.target.files[i] + except IndexError: + break + + tagged = self.fm.tags and drawn.realpath in self.fm.tags + if tagged: + tagged_marker = self.fm.tags.marker(drawn.realpath) + else: + tagged_marker = " " + + key = (self.wid, selected_i == i, drawn.marked, self.main_column, + drawn.path in copied, tagged_marker, drawn.infostring, + self.fm.do_cut) + + if key in drawn.display_data: + self.execute_curses_batch(line, drawn.display_data[key]) + self.color_reset() + continue + + display_data = [] + drawn.display_data[key] = display_data + + if self.display_infostring and drawn.infostring \ + and self.settings.display_size_in_main_column: + infostring = str(drawn.infostring) + " " + else: + infostring = "" + + this_color = base_color + list(drawn.mimetype_tuple) + text = drawn.basename + + space = self.wid - len(infostring) + if self.main_column: + space -= 2 + elif self.settings.display_tags_in_all_columns: + space -= 1 + + if i == selected_i: + this_color.append('selected') + + if drawn.marked: + this_color.append('marked') + if self.main_column or self.settings.display_tags_in_all_columns: + text = " " + text + + if tagged: + this_color.append('tagged') + + if drawn.is_directory: + this_color.append('directory') + else: + this_color.append('file') + + if drawn.stat: + mode = drawn.stat.st_mode + if mode & stat.S_IXUSR: + this_color.append('executable') + if stat.S_ISFIFO(mode): + this_color.append('fifo') + if stat.S_ISSOCK(mode): + this_color.append('socket') + if drawn.is_device: + this_color.append('device') + + if drawn.path in copied: + this_color.append('cut' if self.fm.do_cut else 'copied') + + if drawn.is_link: + this_color.append('link') + this_color.append(drawn.exists and 'good' or 'bad') + + attr = self.settings.colorscheme.get_attr(*this_color) + + if (self.main_column or self.settings.display_tags_in_all_columns) \ + and tagged and self.wid > 2: + this_color.append('tag_marker') + tag_attr = self.settings.colorscheme.get_attr(*this_color) + display_data.append([tagged_marker, tag_attr]) + else: + text = " " + text + space += 1 + + wtext = WideString(text) + if len(wtext) > space: + wtext = wtext[:max(0, space - 1)] + ellipsis + text = str(wtext) + + display_data.append([text, attr]) + + padding = self.wid - len(wtext) + if tagged and (self.main_column or \ + self.settings.display_tags_in_all_columns): + padding -= 1 + if infostring: + if len(wtext) + 1 + len(infostring) > self.wid: + pass + else: + padding -= len(infostring) + padding = max(0, padding) + infostring = (" " * padding) + infostring + display_data.append([infostring, attr]) + else: + display_data.append([" " * max(0, padding), attr]) + + self.execute_curses_batch(line, display_data) + self.color_reset() + + def _get_scroll_begin(self): + """Determines scroll_begin (the position of the first displayed file)""" + offset = self.settings.scroll_offset + dirsize = len(self.target) + winsize = self.hei + halfwinsize = winsize // 2 + index = self.target.pointer or 0 + original = self.target.scroll_begin + projected = index - original + + upper_limit = winsize - 1 - offset + lower_limit = offset + + if original < 0: + return 0 + + if dirsize < winsize: + return 0 + + if halfwinsize < offset: + return min( dirsize - winsize, max( 0, index - halfwinsize )) + + if original > dirsize - winsize: + self.target.scroll_begin = dirsize - winsize + return self._get_scroll_begin() + + if projected < upper_limit and projected > lower_limit: + return original + + if projected > upper_limit: + return min( dirsize - winsize, + original + (projected - upper_limit)) + + if projected < upper_limit: + return max( 0, + original - (lower_limit - projected)) + + return original + + def _set_scroll_begin(self): + """Updates the scroll_begin value""" + self.scroll_begin = self._get_scroll_begin() + self.target.scroll_begin = self.scroll_begin + + def scroll(self, n): + """scroll down by n lines""" + self.need_redraw = True + self.target.move(down=n) + self.target.scroll_begin += 3 * n + + def __str__(self): + return self.__class__.__name__ + ' at level ' + str(self.level) |