Another popup system upgrade: Preserve requested height on resize, do not fail if it's too much, add infinite and default options, add align option, slightly change SelectablePopup. Update rest of the code

This commit is contained in:
Asmageddon 2012-05-29 19:20:36 +02:00
parent 0df1255ae5
commit a8549ef882
3 changed files with 87 additions and 26 deletions

View File

@ -44,7 +44,7 @@ except ImportError:
import logging,os,os.path
from popup import Popup
from popup import Popup, ALIGN
from deluge.ui.console import colors
@ -768,13 +768,18 @@ class TextInput(InputField):
class InputPopup(Popup):
def __init__(self,parent_mode,title,width_req=-1,height_req=-1,close_cb=None, additional_formatting=True):
Popup.__init__(self,parent_mode,title,width_req,height_req,close_cb)
def __init__(self,parent_mode,title,width_req=0,height_req=0,
align=ALIGN.DEFAULT,
close_cb=None,
additional_formatting=True,
immediate_action=False):
Popup.__init__(self,parent_mode,title, width_req=width_req, height_req=height_req, align=align, close_cb=close_cb)
self.inputs = []
self.lines = []
self.current_input = 0
self.additional_formatting = additional_formatting
self.immediate_action = immediate_action
#We need to replicate some things in order to wrap our inputs
self.encoding = parent_mode.encoding
@ -896,6 +901,11 @@ class InputPopup(Popup):
return True
elif self.inputs:
self.inputs[self.current_input].handle_read(c)
if self.immediate_action:
vals = {}
for ipt in self.inputs:
vals[ipt.name] = ipt.get_value()
self.close_cb(vals)
self.refresh()
return False

View File

@ -44,8 +44,20 @@ import format_utils
import logging
log = logging.getLogger(__name__)
class ALIGN:
TOP_LEFT = 1
TOP_CENTER = 2
TOP_RIGHT = 3
MIDDLE_LEFT = 4
MIDDLE_CENTER= 5
MIDDLE_RIGHT = 6
BOTTOM_LEFT = 7
BOTTOM_CENTER= 8
BOTTOM_RIGHT = 9
DEFAULT = MIDDLE_CENTER
class Popup:
def __init__(self,parent_mode,title,width_req=-1,height_req=-1,close_cb=None,init_lines=None):
def __init__(self,parent_mode,title,width_req=0,height_req=0,align=ALIGN.DEFAULT, close_cb=None,init_lines=None):
"""
Init a new popup. The default constructor will handle sizing and borders and the like.
@ -69,17 +81,15 @@ class Popup:
"""
self.parent = parent_mode
if (height_req <= 0):
height_req = int(self.parent.rows/2)
if (width_req <= 0):
width_req = int(self.parent.cols/2)
by = (self.parent.rows/2)-(height_req/2)
bx = (self.parent.cols/2)-(width_req/2)
self.screen = curses.newwin(height_req,width_req,by,bx)
self.height_req = height_req
self.width_req = width_req
self.align = align
self.handle_resize()
self.title = title
self.close_cb = close_cb
self.height,self.width = self.screen.getmaxyx()
self.divider = None
self.lineoff = 0
if init_lines:
@ -96,15 +106,51 @@ class Popup:
crow+=1
def handle_resize(self):
log.debug("Resizing popup window (actually, just creating a new one)")
self.screen = curses.newwin((self.parent.rows/2),(self.parent.cols/2),(self.parent.rows/4),(self.parent.cols/4))
hr = self.height_req
wr = self.width_req
log.debug("Resizing(or creating) popup window")
#Height
if hr == 0:
hr = int(self.parent.rows/2)
elif hr == -1:
hr = self.parent.rows - 2
elif hr > self.parent.rows - 2:
hr = self.parent.rows - 2
#Width
if wr == 0:
wr = int(self.parent.cols/2)
elif wr == -1:
wr = self.parent.cols
elif wr >= self.parent.cols:
wr = self.parent.cols
if self.align in [ALIGN.TOP_CENTER, ALIGN.TOP_LEFT, ALIGN.TOP_RIGHT]:
by = 1
elif self.align in [ALIGN.MIDDLE_CENTER, ALIGN.MIDDLE_LEFT, ALIGN.MIDDLE_RIGHT]:
by = (self.parent.rows/2)-(hr/2)
elif self.align in [ALIGN.BOTTOM_CENTER, ALIGN.BOTTOM_LEFT, ALIGN.BOTTOM_RIGHT]:
by = self.parent.rows - hr - 1
if self.align in [ALIGN.TOP_LEFT, ALIGN.MIDDLE_LEFT, ALIGN.BOTTOM_LEFT]:
bx = 0
elif self.align in [ALIGN.TOP_CENTER, ALIGN.MIDDLE_CENTER, ALIGN.BOTTOM_CENTER]:
bx = (self.parent.cols/2)-(wr/2)
elif self.align in [ALIGN.TOP_RIGHT, ALIGN.MIDDLE_RIGHT, ALIGN.BOTTOM_RIGHT]:
bx = self.parent.cols - wr - 1
self.screen = curses.newwin(hr,wr,by,bx)
self.x, self.y = bx, by
self.height,self.width = self.screen.getmaxyx()
def refresh(self):
self.screen.erase()
self.screen.border(0,0,0,0)
toff = max(1,int((self.parent.cols/4)-(len(self.title)/2)))
toff = max(1, (self.width//2) - (len(self.title)//2))
self.parent.add_string(0,"{!white,black,bold!}%s"%self.title,self.screen,toff,False,True)
self._refresh_lines()
@ -169,11 +215,14 @@ class SelectablePopup(Popup):
A popup which will let the user select from some of the lines that
are added.
"""
def __init__(self,parent_mode,title,selection_callback,*args):
Popup.__init__(self,parent_mode,title)
def __init__(self,parent_mode,title, selection_callback, args=(), align=ALIGN.DEFAULT, immediate_action=False):
Popup.__init__(self,parent_mode, title, align=align)
self._selection_callback = selection_callback
self._selection_args = args
self._selectable_lines = []
self._immediate_action = immediate_action
self._select_data = []
self._line_foregrounds = []
self._udxs = {}
@ -242,17 +291,22 @@ class SelectablePopup(Popup):
len(self._selectable_lines) > 1):
idx = self._selectable_lines.index(self._selected)
self._selected = self._selectable_lines[idx-1]
if self._immediate_action:
self._selection_callback(idx, self._select_data[idx], *self._selection_args)
elif c == curses.KEY_DOWN:
#if len(self._lines)-self.lineoff > (self.height-2):
# self.lineoff += 1
idx = self._selectable_lines.index(self._selected)
if (idx < len(self._selectable_lines)-1):
self._selected = self._selectable_lines[idx+1]
if self._immediate_action:
self._selection_callback(idx, self._select_data[idx], *self._selection_args)
elif c == 27: # close on esc, no action
return True
elif c == curses.KEY_ENTER or c == 10:
idx = self._selectable_lines.index(self._selected)
return self._selection_callback(idx,self._select_data[idx],*self._selection_args)
return self._selection_callback(idx, self._select_data[idx], *self._selection_args)
if c > 31 and c < 256:
if chr(c) == 'q':
return True # close the popup
@ -270,12 +324,12 @@ class MessagePopup(Popup):
"""
Popup that just displays a message
"""
def __init__(self, parent_mode, title, message):
def __init__(self, parent_mode, title, message, align=ALIGN.DEFAULT):
self.message = message
self.width= int(parent_mode.cols/2)
lns = format_utils.wrap_string(self.message,self.width-2,3,True)
hr = min(len(lns)+2,int(parent_mode.rows/2))
Popup.__init__(self,parent_mode,title,height_req=hr)
Popup.__init__(self,parent_mode, title, align=align, height_req=hr)
self._lines = lns
def handle_resize(self):

View File

@ -153,7 +153,7 @@ def torrent_action(idx, data, mode, ids):
if len(ids) == 1:
mode.clear_marks()
return True
popup = SelectablePopup(mode,"Queue Action",do_queue,mode,ids)
popup = SelectablePopup(mode,"Queue Action", do_queue, (mode, ids))
popup.add_line("_Top",data=ACTION.QUEUE_TOP)
popup.add_line("_Up",data=ACTION.QUEUE_UP)
popup.add_line("_Down",data=ACTION.QUEUE_DOWN)
@ -266,10 +266,7 @@ def torrent_action(idx, data, mode, ids):
def create_popup(status):
cb = lambda result, ids=ids: _do_set_torrent_options(ids, result)
try:
option_popup = InputPopup(mode,"Set torrent options (Esc to cancel)",close_cb=cb, height_req=22)
except:
option_popup = InputPopup(mode,"Set torrent options (Esc to cancel)",close_cb=cb)
option_popup = InputPopup(mode,"Set torrent options (Esc to cancel)",close_cb=cb, height_req=22)
for (field, field_type) in torrent_options:
caption = "{!info!}" + torrent_options_to_names[field]
@ -318,7 +315,7 @@ def torrent_actions_popup(mode,tids,details=False, action = None):
if action != None:
torrent_action(-1, action, mode, tids)
return
popup = SelectablePopup(mode,"Torrent Actions",torrent_action,mode,tids)
popup = SelectablePopup(mode,"Torrent Actions",torrent_action, (mode, tids))
popup.add_line("_Pause",data=ACTION.PAUSE)
popup.add_line("_Resume",data=ACTION.RESUME)
if not details: