⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 widget.py

📁 Urwid is a Python library for making text console applications. It has many features including fluid
💻 PY
📖 第 1 页 / 共 5 页
字号:
		"""Set the part of the frame that is in focus.		part -- 'header', 'footer' or 'body'		"""		assert part in ('header', 'footer', 'body')		self.focus_part = part		self._invalidate()	def frame_top_bottom(self, (maxcol,maxrow), focus):		"""Calculate the number of rows for the header and footer.		Returns (head rows, foot rows),(orig head, orig foot).		orig head/foot are from rows() calls.		"""		frows = hrows = 0				if self.header:			hrows = self.header.rows((maxcol,),				self.focus_part=='header' and focus)				if self.footer:			frows = self.footer.rows((maxcol,),				self.focus_part=='footer' and focus)				remaining = maxrow				if self.focus_part == 'footer':			if frows >= remaining:				return (0, remaining),(hrows, frows)							remaining -= frows			if hrows >= remaining:				return (remaining, frows),(hrows, frows)		elif self.focus_part == 'header':			if hrows >= maxrow:				return (remaining, 0),(hrows, frows)						remaining -= hrows			if frows >= remaining:				return (hrows, remaining),(hrows, frows)		elif hrows + frows >= remaining:			# self.focus_part == 'body'			rless1 = max(0, remaining-1)			if frows >= remaining-1:				return (0, rless1),(hrows, frows)						remaining -= frows			rless1 = max(0, remaining-1)			return (rless1,frows),(hrows, frows)				return (hrows, frows),(hrows, frows)				def render(self, (maxcol,maxrow), focus=False):		"""Render frame and return it."""		(htrim, ftrim),(hrows, frows) = self.frame_top_bottom(			(maxcol, maxrow), focus)				combinelist = []		depends_on = []				head = None		if htrim and htrim < hrows:			head = Filler(self.header, 'top').render(				(maxcol, htrim), 				focus and self.focus_part == 'header')		elif htrim:			head = self.header.render((maxcol,),				focus and self.focus_part == 'header')			assert head.rows() == hrows, "rows, render mismatch"		if head:			combinelist.append((head, 'header', 				self.focus_part == 'header'))			depends_on.append(self.header)		if ftrim+htrim < maxrow:			body = self.body.render((maxcol, maxrow-ftrim-htrim),				focus and self.focus_part == 'body')			combinelist.append((body, 'body', 				self.focus_part == 'body'))			depends_on.append(self.body)				foot = None			if ftrim and ftrim < frows:			foot = Filler(self.footer, 'bottom').render(				(maxcol, ftrim), 				focus and self.focus_part == 'footer')		elif ftrim:			foot = self.footer.render((maxcol,),				focus and self.focus_part == 'footer')			assert foot.rows() == frows, "rows, render mismatch"		if foot:			combinelist.append((foot, 'footer', 				self.focus_part == 'footer'))			depends_on.append(self.footer)		return CanvasCombine(combinelist)	def keypress(self, (maxcol,maxrow), key):		"""Pass keypress to widget in focus."""				if self.focus_part == 'header' and self.header is not None:			if not self.header.selectable():				return key			return self.header.keypress((maxcol,),key) 		if self.focus_part == 'footer' and self.footer is not None:			if not self.footer.selectable():				return key			return self.footer.keypress((maxcol,),key)		if self.focus_part != 'body':			return key		remaining = maxrow		if self.header is not None:			remaining -= self.header.rows((maxcol,))		if self.footer is not None:			remaining -= self.footer.rows((maxcol,))		if remaining <= 0: return key			if not self.body.selectable():			return key		return self.body.keypress( (maxcol, remaining), key )	def mouse_event(self, (maxcol, maxrow), event, button, col, row, focus):		"""		Pass mouse event to appropriate part of frame.		Focus may be changed on button 1 press.		"""		(htrim, ftrim),(hrows, frows) = self.frame_top_bottom(			(maxcol, maxrow), focus)				if row < htrim: # within header			focus = focus and self.focus_part == 'header'			if is_mouse_press(event) and button==1:				if self.header.selectable():					self.set_focus('header')			if not hasattr(self.header, 'mouse_event'):				return False			return self.header.mouse_event( (maxcol,), event,				button, col, row, focus )				if row >= maxrow-ftrim: # within footer			focus = focus and self.focus_part == 'footer'			if is_mouse_press(event) and button==1:				if self.footer.selectable():					self.set_focus('footer')			if not hasattr(self.footer, 'mouse_event'):				return False			return self.footer.mouse_event( (maxcol,), event,				button, col, row-maxrow+frows, focus )				# within body		focus = focus and self.focus_part == 'body'		if is_mouse_press(event) and button==1:			if self.body.selectable():				self.set_focus('body')				if not hasattr(self.body, 'mouse_event'):			return False		return self.body.mouse_event( (maxcol, maxrow-htrim-ftrim),			event, button, col, row-htrim, focus )		class AttrWrap(Widget):	"""	AttrWrap is a decorator that changes the default attribute for a 	FlowWidget or BoxWidget	"""	def __init__(self, w, attr, focus_attr = None):		"""		w -- widget to wrap		attr -- attribute to apply to w		focus_attr -- attribute to apply when in focus, if None use attr				This object will pass all function calls and variable references		to the wrapped widget.		"""		self._w = w		self._attr = attr		self._focus_attr = focus_attr		def get_w(self):		return self._w	def set_w(self, w):		self._w = w		self._invalidate()	w = property(get_w, set_w)		def get_attr(self):		return self._attr	def set_attr(self, attr):		self._attr = attr		self._invalidate()	attr = property(get_attr, set_attr)		def get_focus_attr(self):		return self._focus_attr	def set_focus_attr(self, focus_attr):		self._focus_attr = focus_attr		self._invalidate()	focus_attr = property(get_focus_attr, set_focus_attr)			def render(self, size, focus = False ):		"""Render self.w and apply attribute. Return canvas.				size -- (maxcol,) if self.w contains a flow widget or			(maxcol, maxrow) if it contains a box widget.		"""		attr = self.attr		if focus and self.focus_attr is not None:			attr = self.focus_attr		canv = self.w.render(size, focus=focus)		canv = CompositeCanvas(canv)		canv.fill_attr(attr)		return canv	def selectable(self):		return self.w.selectable()	def __getattr__(self,name):		"""Call getattr on wrapped widget."""		return getattr(self.w, name)class PileError(Exception):	pass		class Pile(Widget): # either FlowWidget or BoxWidget	def __init__(self, widget_list, focus_item=None):		"""		widget_list -- list of widgets		focus_item -- widget or integer index, if None the first			selectable widget will be chosen.		widget_list may also contain tuples such as:		('flow', widget) always treat widget as a flow widget		('fixed', height, widget) give this box widget a fixed height		('weight', weight, widget) if the pile is treated as a box			widget then treat widget as a box widget with a			height based on its relative weight value, otherwise			treat widget as a flow widget				widgets not in a tuple are the same as ('weight', 1, widget)		If the pile is treated as a box widget there must be at least		one 'weight' tuple in widget_list.		"""		self.__super.__init__()		self.widget_list = MonitoredList(widget_list)		self.item_types = []		for i in range(len(widget_list)):			w = widget_list[i]			if type(w) != type(()):				self.item_types.append(('weight',1))			elif w[0] == 'flow':				f, widget = w				self.widget_list[i] = widget				self.item_types.append((f,None))				w = widget			elif w[0] in ('fixed', 'weight'):				f, height, widget = w				self.widget_list[i] = widget				self.item_types.append((f,height))				w = widget			else:				raise PileError, "widget list item invalid %s" % `w`			if focus_item is None and w.selectable():				focus_item = i		self.widget_list.set_modified_callback(self._invalidate)				if focus_item is None:			focus_item = 0		self.set_focus(focus_item)		self.pref_col = 0	def selectable(self):		"""Return True if the focus item is selectable."""		return self.focus_item.selectable()	def set_focus(self, item):		"""Set the item in focus.  				item -- widget or integer index"""		if type(item) == type(0):			assert item>=0 and item<len(self.widget_list)			self.focus_item = self.widget_list[item]		else:			assert item in self.widget_list			self.focus_item = item		self._invalidate()	def get_focus(self):		"""Return the widget in focus."""		return self.focus_item	def get_pref_col(self, size):		"""Return the preferred column for the cursor, or None."""		if not self.selectable():			return None		self._update_pref_col_from_focus(size)		return self.pref_col			def get_item_size(self, size, i, focus, item_rows=None):		"""		Return a size appropriate for passing to self.widget_list[i]		"""		maxcol = size[0]		f, height = self.item_types[i]		if f=='fixed':			return (maxcol, height)		elif f=='weight' and len(size)==2:			if not item_rows:				item_rows = self.get_item_rows(size, focus)			return (maxcol, item_rows[i])		else:			return (maxcol,)						def get_item_rows(self, size, focus):		"""		Return a list of the number of rows used by each widget		in self.item_list.		"""		remaining = None		maxcol = size[0]		if len(size)==2:			remaining = size[1]				l = []				if remaining is None:			# pile is a flow widget			for (f, height), w in zip(				self.item_types, self.widget_list):				if f == 'fixed':					l.append( height )				else:					l.append( w.rows( (maxcol,), focus=focus						and self.focus_item == w ))			return l					# pile is a box widget		# do an extra pass to calculate rows for each widget		wtotal = 0		for (f, height), w in zip(self.item_types, self.widget_list):			if f == 'flow':				rows = w.rows((maxcol,), focus=focus and					self.focus_item == w )				l.append(rows)				remaining -= rows			elif f == 'fixed':				l.append(height)				remaining -= height			else:				l.append(None)				wtotal += height		if wtotal == 0:			raise PileError, "No weighted widgets found for Pile treated as a box widget"		if remaining < 0: 			remaining = 0		i = 0		for (f, height), li in zip(self.item_types, l):			if li is None:				rows = int(float(remaining)*height					/wtotal+0.5)				l[i] = rows				remaining -= rows				wtotal -= height			i += 1		return l				def render(self, size, focus=False):		"""		Render all widgets in self.widget_list and return the results		stacked one on top of the next.		"""		maxcol = size[0]		item_rows = None				combinelist = []		i = 0		for (f, height), w in zip(self.item_types, self.widget_list):			item_focus = self.focus_item == w			canv = None			if f == 'fixed':				canv = w.render( (maxcol, height),					focus=focus and item_focus)			elif f == 'flow' or len(size)==1:				canv = w.render( (maxcol,), 					focus=focus and	item_focus)			else:					if item_rows is None:					item_rows = self.get_item_rows(size, 						focus)				rows = item_rows[i]				if rows>0:					canv = w.render( (maxcol, rows),						focus=focus and	item_focus )			if canv:				combinelist.append((canv, i, item_focus))			i+=1		return CanvasCombine(combinelist)		def get_cursor_coords(self, size):		"""Return the cursor coordinates of the focus widget."""		if not self.focus_item.selectable():			return None		if not hasattr(self.focus_item,'get_cursor_coords'):			return None				i = self.widget_list.index(self.focus_item)		f, height = self.item_types[i]		item_rows = None		maxcol = size[0]		if f == 'fixed' or (f=='weight' and len(size)==2):			if f == 'fixed':				maxrow = height			else:				if item_rows is None:					item_rows = self.get_item_rows(size, 					focus=True)				maxrow = item_rows[i]			coords = self.focus_item.get_cursor_coords(				(maxcol,maxrow))		else:			coords = self.focus_item.get_cursor_coords((maxcol,))		if coords is None:			return None		x,y = coords		if i > 0:			if item_rows is None:				item_rows = self.get_item_rows(size, focus=True)			for r in item_rows[:i]:				y += r		return x, y				def rows(self, (maxcol,), focus=False ):		"""Return the number of rows required for this widget."""		return sum( self.get_item_rows( (maxcol,), focus ) )	def keypress(self, size, key ):		"""Pass the keypress to the widget in focus.		Unhandled 'up' and 'down' keys may cause a focus change."""		maxcol = size[0]		item_rows = None		if len(size)==2:			item_rows = self.get_item_rows( size, focus=True )		i = self.widget_list.index(self.focus_item)		f, height = self.item_types[i]		if self.focus_item.selectable():			tsize = self.get_item_size(size,i,True,item_rows)			key = self.focus_item.keypress( tsize, key )			if key not in ('up', 'down'):				return key		if key == 'up':			candidates = range(i-1, -1, -1) # count backwards to 0		else: # key == 'down'			candidates = range(i

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -