summary refs log blame commit diff stats
path: root/ranger/gui/widgets/browserview.py
blob: ebce990016b3f63987844b4e8cc97610dfb84c4e (plain) (tree)
1
2
3
4
5
6
7
                                                                 
 



                                                                      
 






                                                                       
 
                                                      
             
                    
                                        
                        

                                              
                                                

                      
                                
                             
                          


                                                        
                                    
                                      


                                         
 
                                   
                                              
                                                                  
 
                                         
                                                                  
                                                                                   
                                                                
 



                                                
                                                                    
                                          

                    
                                                                               
                                  
                                               
                     
                                                                  
                                                           
 
                                                           
                                          
                                          

                       



                                                                






                                                                                         



                                                       


                                                                                    
                                                       

                                                      


                                      



                                                                                           
                     
                            


                                                                                         


                                                         
 


                                      
                                                                              
                                                            
 
                                
                                                                     
 



                                                                                  




                                                             
                                                                             
 















                                                                  







                                                               








                                                                                  


                                                                                       

















                                                                               
                                         
                                                                         
                                                                 


                                                    
 

                                                                            

                                
                                                                  
                     
                                                          
 

                                             
                                          
                                                   
 
                                       
                                                                    
 
                                           
                                                                             
                                                                              
 
                            

                                                                                    

                                        
 
                                   
 


                                           
                                                              
                                                             
                                                             

                                                               
 
                             

                                         
                                      

                                 

                                                          

                                  
 
                              

                                          
                                      

                                  

                                                         

                                  
 

                                               
                                                                   
                                                                      

                                                                    
                                                                               
# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""The BrowserView manages a set of BrowserColumns."""
import curses
from . import Widget
from .browsercolumn import BrowserColumn
from .pager import Pager
from ..displayable import DisplayableContainer

class BrowserView(Widget, DisplayableContainer):
	ratios = None
	preview = True
	preview_available = True
	stretch_ratios = None
	need_clear = False

	def __init__(self, win, ratios, preview = True):
		DisplayableContainer.__init__(self, win)
		self.ratios = ratios
		self.preview = preview
		self.old_cf = self.env.cf
		self.old_prevfile = None
		self.old_prevdir = None

		# normalize ratios:
		ratio_sum = float(sum(ratios))
		self.ratios = tuple(x / ratio_sum for x in ratios)

		if len(self.ratios) >= 2:
			self.stretch_ratios = self.ratios[:-2] + \
					((self.ratios[-2] + self.ratios[-1] * 0.9),
					(self.ratios[-1] * 0.1))

		offset = 1 - len(ratios)
		if preview: offset += 1

		for level in range(len(ratios)):
			fl = BrowserColumn(self.win, level + offset)
			self.add_child(fl)

		try:
			self.main_column = self.container[preview and -2 or -1]
		except IndexError:
			self.main_column = None
		else:
			self.main_column.display_infostring = True
			self.main_column.main_column = True

		self.pager = Pager(self.win, embedded=True)
		self.pager.visible = False
		self.add_child(self.pager)

	def draw(self):
		try:
			if self.env.cmd.show_obj.draw_bookmarks:
				self._draw_bookmarks()
		except AttributeError:
			if self.old_cf != self.env.cf:
				self.need_clear = True
			if self.settings.draw_borders:
				if self.old_prevdir != self.settings.preview_directories:
					self.need_clear = True
				if self.old_prevfile != self.settings.preview_files:
					self.need_clear = True
			if self.need_clear:
				self.win.erase()
				self.need_redraw = True
				self.need_clear = False
				self.old_cf = self.env.cf
				self.old_prevfile = self.settings.preview_files
				self.old_prevdir = self.settings.preview_directories
			DisplayableContainer.draw(self)
			if self.settings.draw_borders:
				self._draw_borders()

	def finalize(self):
		if self.pager.visible:
			try:
				self.fm.ui.win.move(self.main_column.y, self.main_column.x)
			except:
				pass
		else:
			try:
				x = self.main_column.x
				y = self.main_column.y + self.main_column.target.pointer\
						- self.main_column.scroll_begin
				self.fm.ui.win.move(y, x)
			except:
				pass

	def _draw_bookmarks(self):
		self.need_clear = True

		sorted_bookmarks = sorted(item for item in self.fm.bookmarks \
				if '/.' not in item[1].path)

		def generator():
			return zip(range(self.hei), sorted_bookmarks)

		try:
			maxlen = max(len(item[1].path) for i, item in generator())
		except ValueError:
			return
		maxlen = min(maxlen + 5, self.wid)

		for line, items in generator():
			key, mark = items
			string = " " + key + ": " + mark.path
			self.addnstr(line, 0, string.ljust(maxlen), self.wid)

	def _draw_borders(self):
		win = self.win
		self.color('in_browser', 'border')

		left_start = 0
		right_end = self.wid - 1

		rows = [row for row in self.container \
				if isinstance(row, BrowserColumn)]
		rows.sort(key=lambda row: row.x)

		for child in rows:
			if not child.has_preview():
				left_start = child.x + child.wid
			else:
				break
		if not self.pager.visible:
			for child in reversed(rows):
				if not child.has_preview():
					right_end = child.x - 1
				else:
					break
			if right_end < left_start:
				right_end = self.wid - 1

		win.hline(0, left_start, curses.ACS_HLINE, right_end - left_start)
		win.hline(self.hei - 1, left_start, curses.ACS_HLINE,
				right_end - left_start)
		win.vline(1, left_start, curses.ACS_VLINE, self.hei - 2)

		for child in rows:
			if not child.has_preview():
				continue
			if child.main_column and self.pager.visible:
				win.vline(1, right_end, curses.ACS_VLINE, self.hei - 2)
				break
			x = child.x + child.wid
			y = self.hei - 1
			try:
				win.vline(1, x, curses.ACS_VLINE, y - 1)
				win.addch(0, x, curses.ACS_TTEE, 0)
				win.addch(y, x, curses.ACS_BTEE, 0)
			except:
				# in case it's off the boundaries
				pass

		win.addch(0, left_start, curses.ACS_ULCORNER)
		win.addch(self.hei - 1, left_start, curses.ACS_LLCORNER)
		win.addch(0, right_end, curses.ACS_URCORNER)
		try:
			win.addch(self.hei - 1, right_end, curses.ACS_LRCORNER)
		except:
			pass

	def resize(self, y, x, hei, wid):
		"""Resize all the columns according to the given ratio"""
		DisplayableContainer.resize(self, y, x, hei, wid)
		borders = self.settings.draw_borders
		pad = 1 if borders else 0
		left = pad

		cut_off_last = self.preview and not self.preview_available \
				and self.stretch_ratios

		if cut_off_last:
			generator = enumerate(self.stretch_ratios)
		else:
			generator = enumerate(self.ratios)

		last_i = len(self.ratios) - 1

		for i, ratio in generator:
			wid = int(ratio * self.wid)

			if i == last_i:
				wid = int(self.wid - left + 1 - pad)

			if i == last_i - 1:
				self.pager.resize(pad, left, hei - pad * 2, \
						max(1, self.wid - left - pad))

			try:
				self.container[i].resize(pad, left, hei - pad * 2, \
						max(1, wid - 1))
			except KeyError:
				pass

			left += wid

	def click(self, event):
		n = event.ctrl() and 1 or 3
		if event.pressed(4):
			self.main_column.scroll(relative = -n)
		elif event.pressed(2) or event.key_invalid():
			self.main_column.scroll(relative = n)
		else:
			DisplayableContainer.click(self, event)

	def open_pager(self):
		self.pager.visible = True
		self.pager.focused = True
		self.need_clear = True
		self.pager.open()
		try:
			self.container[-2].visible = False
			self.container[-3].visible = False
		except IndexError:
			pass

	def close_pager(self):
		self.pager.visible = False
		self.pager.focused = False
		self.need_clear = True
		self.pager.close()
		try:
			self.container[-2].visible = True
			self.container[-3].visible = True
		except IndexError:
			pass

	def poke(self):
		DisplayableContainer.poke(self)
		if self.settings.collapse_preview and self.preview:
			has_preview = self.container[-2].has_preview()
			if self.preview_available != has_preview:
				self.preview_available = has_preview
				self.resize(self.y, self.x, self.hei, self.wid)