about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/gui/widgets/titlebar.py189
1 files changed, 169 insertions, 20 deletions
diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py
index 0e1c0aff..36ed1168 100644
--- a/ranger/gui/widgets/titlebar.py
+++ b/ranger/gui/widgets/titlebar.py
@@ -2,37 +2,186 @@
 information."""
 
 from . import Widget
+from ranger import log
+from math import floor
 
 class TitleBar(Widget):
+	old_cf = None
+	old_keybuffer = None
+	old_wid = None
+	result = None
 	def draw(self):
-		import curses, socket, os
-		self.win.move(self.y, self.x)
+		if self.env.cf != self.old_cf or\
+				str(self.env.keybuffer) != str(self.old_keybuffer) or\
+				self.wid != self.old_wid:
+			self.old_wid = self.wid
+			self.old_cf = self.env.cf
+			self._calc_bar()
+		self._print_result(self.result)
 
-		self.color('in_titlebar', 'hostname')
-		string = os.getenv('LOGNAME') + '@' + socket.gethostname()
-		self.win.addnstr(string, self.wid)
+	def _calc_bar(self):
+		bar = Bar()
+		self._get_left_part(bar)
+		self._get_right_part(bar)
+		try:
+			bar.shrink_by_cutting(self.wid)
+		except ValueError:
+			bar.shrink_by_removing(self.wid)
+		self.result = bar.combine()
+	
+	def _get_left_part(self, bar):
+		import socket, os
+		
+		bar.add(os.getenv('LOGNAME'), 'hostname', fixedsize=True)
+		bar.add('@', 'hostname', fixedsize=True)
+		bar.add(socket.gethostname(), 'hostname', fixedsize=True)
 
 		for path in self.env.pathway:
-			currentx = self.win.getyx()[1]
-
 			if path.islink:
-				self.color('in_titlebar', 'link')
+				clr = 'link'
 			else:
-				self.color('in_titlebar', 'directory')
+				clr = 'directory'
 
-			self.win.addnstr(path.basename + '/', max(self.wid - currentx, 0))
-		if self.env.cf is not None:
-			currentx = self.win.getyx()[1]
-			self.color('in_titlebar', 'file')
-			self.win.addnstr(self.env.cf.basename, max(self.wid - currentx, 0))
+			bar.add(path.basename, clr)
+			bar.add('/', clr, fixedsize=True)
 
-		self.color('in_titlebar', 'keybuffer')
+		if self.env.cf is not None:
+			bar.add(self.env.cf.basename, 'file', fixedsize=True)
 
+	def _get_right_part(self, bar):
 		kb = str(self.env.keybuffer)
-		if self.wid + self.x - currentx > len(kb):
-			self.win.addstr(
-					self.y,
-					self.x + self.wid - len(kb) - 2,
-					kb)
+		self.old_keybuffer = kb
+		bar.addright(kb, 'keybuffer')
 
+	def _print_result(self, result):
+		import _curses
+		self.win.move(self.y, self.x)
+		for part in result:
+			self.color(*part.lst)
+			try:
+				self.win.addstr(part.string)
+			except _curses.error:
+				pass
 		self.color_reset()
+
+
+class Bar(object):
+	left = None
+	right = None
+	gap = None
+
+	def __init__(self):
+		self.left = BarSide()
+		self.right = BarSide()
+		self.gap = BarSide()
+
+	def add(self, *a, **kw):
+		self.left.add(*a, **kw)
+	
+	def addright(self, *a, **kw):
+		self.right.add(*a, **kw)
+
+	def sumsize(self):
+		return self.left.sumsize() + self.right.sumsize()
+
+	def fixedsize(self):
+		return self.left.fixedsize() + self.right.fixedsize()
+
+	def shrink_by_removing(self, wid):
+		leftsize = self.left.sumsize()
+		rightsize = self.right.sumsize()
+		sumsize = leftsize + rightsize
+
+		# remove elemets from the left until it fits
+		if sumsize > wid:
+			while len(self.left) > 0:
+				leftsize -= len(self.left.pop(-1).string)
+				if leftsize + rightsize <= wid:
+					break
+			sumsize = leftsize + rightsize
+
+			# remove elemets from the right until it fits
+			if sumsize > wid:
+				while len(self.right) > 0:
+					rightsize -= len(self.right.pop(0).string)
+					if leftsize + rightsize <= wid:
+						break
+				sumsize = leftsize + rightsize
+
+		if sumsize < wid:
+			self.fill_gap(' ', (wid - sumsize), gapwidth=True)
+	
+	def shrink_by_cutting(self, wid):
+		fixedsize = self.fixedsize()
+		if wid < fixedsize:
+			raise ValueError("Cannot shrink down to that size by cutting")
+
+		leftsize = self.left.sumsize()
+		rightsize = self.right.sumsize()
+		nonfixed_items = self.left.nonfixed_items()
+
+		log(leftsize, fixedsize, nonfixed_items)
+		itemsize = int(float(wid - rightsize - fixedsize) / nonfixed_items) + 1
+		log(itemsize)
+
+		for item in self.left:
+			if not item.fixed:
+				item.cut_off_to(itemsize)
+
+		self.fill_gap(' ', wid, gapwidth=False)
+
+	def fill_gap(self, char, wid, gapwidth=False):
+		del self.gap[:]
+
+		if not gapwidth:
+			wid = wid - self.sumsize()
+
+		if wid > 0:
+			self.gap.add(char * wid, 'space')
+	
+	def combine(self):
+		return self.left + self.gap + self.right
+
+
+class BarSide(list):
+	def add(self, string, *lst, **kw):
+		cs = ColoredString(string, 'in_titlebar', *lst)
+		if 'fixedsize' in kw:
+			cs.fixed = kw['fixedsize']
+		self.append(cs)
+	
+	def sumsize(self):
+		return sum(len(item) for item in self)
+
+	def fixedsize(self):
+		n = 0
+		for item in self:
+			if item.fixed:
+				n += len(item)
+			else:
+				n += 1
+		return n
+	
+	def nonfixed_items(self):
+		return sum(1 for item in self if not item.fixed)
+
+
+class ColoredString(object):
+	fixed = False
+
+	def __init__(self, string, *lst):
+		self.string = string
+		self.lst = lst
+	
+	def cut_off(self, n):
+		n = max(n, min(len(self.string), 1))
+		self.string = self.string[:-n]
+
+	def cut_off_to(self, n):
+		self.string = self.string[:n]
+	
+	def __len__(self):
+		return len(self.string)
+
+	def __str__(self):
+		return self.string