[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r23728: {arm} Cursor selection for entries in the config state. (in arm/trunk/src: . interface util)
Author: atagar
Date: 2010-10-31 08:13:38 +0000 (Sun, 31 Oct 2010)
New Revision: 23728
Modified:
arm/trunk/src/interface/configStatePanel.py
arm/trunk/src/starter.py
arm/trunk/src/util/uiTools.py
Log:
Cursor selection for entries in the config state.
Modified: arm/trunk/src/interface/configStatePanel.py
===================================================================
--- arm/trunk/src/interface/configStatePanel.py 2010-10-31 03:44:46 UTC (rev 23727)
+++ arm/trunk/src/interface/configStatePanel.py 2010-10-31 08:13:38 UTC (rev 23728)
@@ -60,7 +60,7 @@
self.configType = configType
self.confContents = []
- self.scroll = 0
+ self.scroller = uiTools.Scroller(True)
self.valsLock = threading.RLock()
# TODO: this will need to be able to listen for SETCONF events (arg!)
@@ -98,11 +98,8 @@
self.valsLock.acquire()
if uiTools.isScrollKey(key):
pageHeight = self.getPreferredSize()[0] - 1
- newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, len(self.confContents))
-
- if self.scroll != newScroll:
- self.scroll = newScroll
- self.redraw(True)
+ isChanged = self.scroller.handleKey(key, self.confContents, pageHeight)
+ if isChanged: self.redraw(True)
def draw(self, subwindow, width, height):
self.valsLock.acquire()
@@ -111,11 +108,14 @@
sourceLabel = "Tor" if self.configType == TOR_STATE else "Arm"
self.addstr(0, 0, "%s Config:" % sourceLabel, curses.A_STANDOUT)
+ scrollLoc = self.scroller.getScrollLoc(self.confContents, height - 1)
+ cursorSelection = self.scroller.getCursorSelection(self.confContents)
+
# draws left-hand scroll bar if content's longer than the height
scrollOffset = 0
if len(self.confContents) > height - 1:
scrollOffset = 3
- self.addScrollBar(self.scroll, self.scroll + height - 1, len(self.confContents), 1)
+ self.addScrollBar(scrollLoc, scrollLoc + height - 1, len(self.confContents), 1)
# determines the width for the columns
optionColWidth, valueColWidth, typeColWidth = 0, 0, 0
@@ -130,29 +130,24 @@
optionColWidth = min(self._config["features.config.state.colWidth.option"], optionColWidth)
valueColWidth = min(self._config["features.config.state.colWidth.value"], valueColWidth)
+ descriptionColWidth = max(0, width - scrollOffset - optionColWidth - valueColWidth - typeColWidth - 3)
- for lineNum in range(self.scroll, len(self.confContents)):
+ for lineNum in range(scrollLoc, len(self.confContents)):
entry = self.confContents[lineNum]
- drawLine = lineNum + 1 - self.scroll
+ drawLine = lineNum + 1 - scrollLoc
+ # TODO: need to cut off description at the first newline
optionLabel = uiTools.cropStr(entry.option, optionColWidth)
valueLabel = uiTools.cropStr(entryToValues[entry], valueColWidth)
+ descriptionLabel = uiTools.cropStr(entry.description, descriptionColWidth, None)
lineFormat = uiTools.getColor("green") if entry.isDefault else curses.A_BOLD | uiTools.getColor("yellow")
- xOffset = scrollOffset
+ if entry == cursorSelection: lineFormat |= curses.A_STANDOUT
- self.addstr(drawLine, xOffset, optionLabel, lineFormat)
- xOffset += optionColWidth + 1
+ lineTextLayout = "%%-%is %%-%is %%-%is %%-%is" % (optionColWidth, valueColWidth, typeColWidth, descriptionColWidth)
+ lineText = lineTextLayout % (optionLabel, valueLabel, entry.type, descriptionLabel)
+ self.addstr(drawLine, scrollOffset, lineText, lineFormat)
- self.addstr(drawLine, xOffset, valueLabel, lineFormat)
- xOffset += valueColWidth + 1
-
- self.addstr(drawLine, xOffset, entry.type, lineFormat)
- xOffset += typeColWidth + 1
-
- descriptionLabel = uiTools.cropStr(entry.description, width - xOffset)
- self.addstr(drawLine, xOffset, descriptionLabel, lineFormat)
-
if drawLine >= height: break
self.valsLock.release()
Modified: arm/trunk/src/starter.py
===================================================================
--- arm/trunk/src/starter.py 2010-10-31 03:44:46 UTC (rev 23727)
+++ arm/trunk/src/starter.py 2010-10-31 08:13:38 UTC (rev 23728)
@@ -255,7 +255,7 @@
if conn == None: sys.exit(1)
# initializing the connection may require user input (for the password)
- # scewing the startup time results so this isn't counted
+ # skewing the startup time results so this isn't counted
initTime = time.time() - startTime
controller = util.torTools.getConn()
controller.init(conn)
Modified: arm/trunk/src/util/uiTools.py
===================================================================
--- arm/trunk/src/util/uiTools.py 2010-10-31 03:44:46 UTC (rev 23727)
+++ arm/trunk/src/util/uiTools.py 2010-10-31 08:13:38 UTC (rev 23728)
@@ -141,7 +141,7 @@
return key in SCROLL_KEYS
-def getScrollPosition(key, position, pageHeight, contentHeight):
+def getScrollPosition(key, position, pageHeight, contentHeight, isCursor = False):
"""
Parses navigation keys, providing the new scroll possition the panel should
use. Position is always between zero and (contentHeight - pageHeight). This
@@ -158,19 +158,21 @@
position - starting position
pageHeight - size of a single screen's worth of content
contentHeight - total lines of content that can be scrolled
+ isCursor - tracks a cursor position rather than scroll if true
"""
if isScrollKey(key):
shift = 0
if key == curses.KEY_UP: shift = -1
elif key == curses.KEY_DOWN: shift = 1
- elif key == curses.KEY_PPAGE: shift = -pageHeight
- elif key == curses.KEY_NPAGE: shift = pageHeight
+ elif key == curses.KEY_PPAGE: shift = -pageHeight + 1 if isCursor else -pageHeight
+ elif key == curses.KEY_NPAGE: shift = pageHeight - 1 if isCursor else pageHeight
elif key == curses.KEY_HOME: shift = -contentHeight
elif key == curses.KEY_END: shift = contentHeight
# returns the shift, restricted to valid bounds
- return max(0, min(position + shift, contentHeight - pageHeight))
+ maxLoc = contentHeight - 1 if isCursor else contentHeight - pageHeight
+ return max(0, min(position + shift, maxLoc))
else: return position
def getSizeLabel(bytes, decimal = 0, isLong = False, isBytes=True):
@@ -242,6 +244,90 @@
return timeLabels
+class Scroller:
+ """
+ Tracks the scrolling position when there might be a visible cursor. This
+ expects that there is a single line displayed per an entry in the contents.
+ """
+
+ def __init__(self, isCursorEnabled):
+ self.scrollLoc, self.cursorLoc = 0, 0
+ self.cursorSelection = None
+ self.isCursorEnabled = isCursorEnabled
+
+ def getScrollLoc(self, content, pageHeight):
+ """
+ Provides the scrolling location, taking into account its cursor's location
+ content size, and page height.
+
+ Arguments:
+ content - displayed content
+ pageHeight - height of the display area for the content
+ """
+
+ if content and pageHeight:
+ self.scrollLoc = max(0, min(self.scrollLoc, len(content) - pageHeight + 1))
+
+ if self.isCursorEnabled:
+ self.getCursorSelection(content) # resets the cursor location
+
+ if self.cursorLoc < self.scrollLoc:
+ self.scrollLoc = self.cursorLoc
+ elif self.cursorLoc > self.scrollLoc + pageHeight - 1:
+ self.scrollLoc = self.cursorLoc - pageHeight + 1
+
+ return self.scrollLoc
+
+ def getCursorSelection(self, content):
+ """
+ Provides the selected item in the content. This is the same entry until
+ the cursor moves or it's no longer available (in which case it moves on to
+ the next entry).
+
+ Arguments:
+ content - displayed content
+ """
+
+ # TODO: needs to handle duplicate entries when using this for the
+ # connection panel
+
+ if not self.isCursorEnabled: return None
+ elif not content:
+ self.cursorLoc, self.cursorSelection = 0, None
+ return None
+
+ self.cursorLoc = min(self.cursorLoc, len(content) - 1)
+ if self.cursorSelection != None and self.cursorSelection in content:
+ # moves cursor location to track the selection
+ self.cursorLoc = content.index(self.cursorSelection)
+ else:
+ # select the next closest entry
+ self.cursorSelection = content[self.cursorLoc]
+
+ return self.cursorSelection
+
+ def handleKey(self, key, content, pageHeight):
+ """
+ Moves either the scroll or cursor according to the given input.
+
+ Arguments:
+ key - key code of user input
+ content - displayed content
+ pageHeight - height of the display area for the content
+ """
+
+ if self.isCursorEnabled:
+ self.getCursorSelection(content) # resets the cursor location
+ startLoc = self.cursorLoc
+ else: startLoc = self.scrollLoc
+
+ newLoc = getScrollPosition(key, startLoc, pageHeight, len(content), self.isCursorEnabled)
+ if startLoc != newLoc:
+ if self.isCursorEnabled: self.cursorSelection = content[newLoc]
+ else: self.scrollLoc = newLoc
+ return True
+ else: return False
+
def _getLabel(units, count, decimal, isLong):
"""
Provides label corresponding to units of the highest significance in the