5733422986
Color scheme for fuelmenu is now as follows: * Header/footer are light red * Buttons are light green * Text fields are light gray bg with black text fg, white bg when selected * Labels are now all uniformly colored to black, including radio button labels Removed unused color pallette entries Change-Id: I6d278b54b3a8c45dd9018c954aefc1300d3cbea8 Closes-Bug: #1564404
292 lines
9.5 KiB
Python
292 lines
9.5 KiB
Python
# Copyright 2013 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import logging
|
|
import urwid
|
|
import urwid.raw_display
|
|
import urwid.web_display
|
|
log = logging.getLogger('fuelmenu.urwidwrapper')
|
|
|
|
|
|
def TextField(keyword, label, width, default_value=None, tooltip=None,
|
|
toolbar=None, disabled=False, ispassword=False):
|
|
"""Returns an Urwid Edit object."""
|
|
if ispassword:
|
|
mask = "*"
|
|
else:
|
|
mask = None
|
|
if not tooltip:
|
|
edit_obj = urwid.Edit(('important', label.ljust(width)), default_value,
|
|
mask=mask, wrap='clip')
|
|
else:
|
|
edit_obj = TextWithTip(('important', label.ljust(width)),
|
|
default_value, tooltip, toolbar,
|
|
mask=mask, wrap='clip')
|
|
wrapped_obj = urwid.AttrWrap(edit_obj, 'editbx', 'editfc')
|
|
if disabled:
|
|
wrapped_obj = urwid.WidgetDisable(urwid.AttrWrap(edit_obj,
|
|
'important', 'editfc'))
|
|
# Add get_edit_text and set_edit_text to
|
|
# wrapped_obj so we can use later
|
|
wrapped_obj.set_edit_text = edit_obj.set_edit_text
|
|
wrapped_obj.get_edit_text = edit_obj.get_edit_text
|
|
return wrapped_obj
|
|
|
|
|
|
def ChoicesGroup(choices, default_value=None, fn=None):
|
|
"""Returns list of RadioButtons in a one-line GridFlow."""
|
|
rb_group = []
|
|
|
|
for txt in choices:
|
|
is_default = True if txt == default_value else False
|
|
urwid.AttrWrap(urwid.RadioButton(rb_group, txt,
|
|
is_default, on_state_change=fn,
|
|
user_data=txt),
|
|
'buttn', 'buttnf')
|
|
wrapped_choices = TabbedGridFlow(rb_group, 13, 3, 0, 'left')
|
|
# Bundle rb_group so it can be used later easily
|
|
wrapped_choices.rb_group = rb_group
|
|
return wrapped_choices
|
|
|
|
|
|
def CheckBox(label, state=False, callback=None):
|
|
"""Returns an Urwid CheckBox object."""
|
|
return urwid.CheckBox(label,
|
|
state=state,
|
|
on_state_change=callback)
|
|
|
|
|
|
def TextLabel(text):
|
|
"""Returns an Urwid text object."""
|
|
return urwid.Text(text)
|
|
|
|
|
|
def Columns(objects):
|
|
"""Returns a padded Urwid Columns object that is left aligned."""
|
|
# Objects is a list of widgets. Widgets may be optionally specified
|
|
# as a tuple with ('weight', weight, widget) or (width, widget).
|
|
# Tuples without a widget have a weight of 1."""
|
|
return urwid.Padding(TabbedColumns(objects, 1),
|
|
left=0, right=0, min_width=61)
|
|
|
|
|
|
def Button(text, callback=None):
|
|
"""Returns a wrapped Button with attributes buttn and buttnf."""
|
|
button = urwid.Button(text, callback)
|
|
return urwid.AttrMap(button, 'buttn', 'buttnf')
|
|
|
|
|
|
def SimpleListWalker(contents):
|
|
"""Returns an Urwid SimpleListWalker object."""
|
|
return urwid.SimpleListWalker(contents)
|
|
|
|
|
|
class WalkerStoredListBox(urwid.ListBox):
|
|
def __init__(self, list_walker):
|
|
super(WalkerStoredListBox, self).__init__(list_walker)
|
|
|
|
self.list_walker = list_walker
|
|
|
|
|
|
class TabbedGridFlow(urwid.GridFlow):
|
|
|
|
def __init__(self, cells, cell_width, h_sep, v_sep, align):
|
|
urwid.GridFlow.__init__(self, cells=cells, cell_width=cell_width,
|
|
h_sep=h_sep, v_sep=v_sep, align=align)
|
|
|
|
def keypress(self, size, key):
|
|
if key == 'tab' and self.focus_position < (len(self.contents) - 1)\
|
|
and self.contents[self.focus_position + 1][0].selectable():
|
|
self.tab_next(self.focus_position)
|
|
elif key == 'shift tab' and self.focus_position > 0 \
|
|
and self.contents[self.focus_position - 1][0].selectable():
|
|
self.tab_prev(self.focus_position)
|
|
else:
|
|
return self.__super.keypress(size, key)
|
|
|
|
def tab_next(self, pos):
|
|
self.set_focus(pos + 1)
|
|
maxlen = (len(self.contents) - 1)
|
|
while pos < maxlen:
|
|
if self.contents[pos][0].selectable():
|
|
return
|
|
else:
|
|
pos += 1
|
|
|
|
if pos >= maxlen:
|
|
pos = 0
|
|
self.set_focus(pos)
|
|
|
|
def tab_prev(self, pos):
|
|
self.set_focus(pos - 1)
|
|
while pos > 0:
|
|
if self.contents[pos][0].selectable():
|
|
return
|
|
else:
|
|
pos -= 1
|
|
if pos == 0:
|
|
pos = (len(self.contents) - 1)
|
|
|
|
self.set_focus(pos)
|
|
|
|
def first_selectable(self):
|
|
'''returns index of first selectable widget in contents.'''
|
|
for pos, item in enumerate(self.contents):
|
|
if item[0].selectable():
|
|
return pos
|
|
return (len(self.contents) - 1)
|
|
|
|
|
|
class TabbedColumns(urwid.Columns):
|
|
|
|
def __init__(self, widget_list, dividechars=0, focus_column=None,
|
|
min_width=1, box_columns=None):
|
|
urwid.Columns.__init__(self, widget_list,
|
|
dividechars=dividechars,
|
|
focus_column=focus_column,
|
|
min_width=min_width,
|
|
box_columns=box_columns)
|
|
|
|
def keypress(self, size, key):
|
|
if key == 'tab' and self.focus_position < (len(self.contents) - 1)\
|
|
and self.widget_list[self.focus_position + 1].selectable():
|
|
self.tab_next(self.focus_position)
|
|
elif key == 'shift tab' and self.focus_position > 0 \
|
|
and self.widget_list[self.focus_position - 1].selectable():
|
|
self.tab_prev(self.focus_position)
|
|
else:
|
|
return self.__super.keypress(size, key)
|
|
|
|
def tab_next(self, pos):
|
|
self.set_focus(pos + 1)
|
|
maxlen = (len(self.contents) - 1)
|
|
while pos < maxlen:
|
|
if self.widget_list[pos].selectable():
|
|
return
|
|
else:
|
|
pos += 1
|
|
|
|
if pos >= maxlen:
|
|
pos = 0
|
|
self.set_focus(pos)
|
|
|
|
def tab_prev(self, pos):
|
|
self.set_focus(pos - 1)
|
|
while pos > 0:
|
|
if self.widget_list[pos].selectable():
|
|
return
|
|
else:
|
|
pos -= 1
|
|
if pos == 0:
|
|
pos = (len(self.widget_list) - 1)
|
|
|
|
self.set_focus(pos)
|
|
|
|
def first_selectable(self):
|
|
'''returns index of first selectable widget in widget_list.'''
|
|
for pos, item in enumerate(self.widget_list):
|
|
if item.selectable():
|
|
return pos
|
|
return (len(self.widget_list) - 1)
|
|
|
|
|
|
class TextWithTip(urwid.Edit):
|
|
def __init__(self, label, default_value=None, tooltip=None, toolbar=None,
|
|
mask=None, wrap='space'):
|
|
urwid.Edit.__init__(self, caption=label, edit_text=default_value,
|
|
mask=mask, wrap=wrap)
|
|
self.tip = tooltip
|
|
self.toolbar = toolbar
|
|
|
|
def render(self, size, focus=False):
|
|
if focus:
|
|
self.toolbar.set_text(self.tip)
|
|
canv = super(TextWithTip, self).render(size, focus)
|
|
return canv
|
|
|
|
|
|
class TabbedListWalker(urwid.ListWalker):
|
|
def __init__(self, lst):
|
|
self.lst = lst
|
|
self.focus = 0
|
|
|
|
def _modified(self):
|
|
return urwid.ListWalker._modified(self)
|
|
|
|
def tab_next(self):
|
|
item, pos = self.get_next(self.focus)
|
|
while pos is not None:
|
|
if item.selectable():
|
|
break
|
|
else:
|
|
item, pos = self.get_next(pos)
|
|
if pos is None:
|
|
pos = 0
|
|
self.focus = pos
|
|
self._modified()
|
|
try:
|
|
# Reset focus to first selectable widget in item
|
|
if hasattr(item, 'original_widget'):
|
|
item.original_widget.set_focus(
|
|
item.original_widget.first_selectable())
|
|
else:
|
|
item.set_focus(item.first_selectable())
|
|
except Exception:
|
|
# Ignore failure. Case only applies to TabbedColumns and
|
|
# TabbedGridFlow. Other items should fail silently.
|
|
pass
|
|
|
|
def tab_prev(self):
|
|
item, pos = self.get_prev(self.focus)
|
|
while pos is not None:
|
|
if item.selectable():
|
|
break
|
|
else:
|
|
item, pos = self.get_prev(pos)
|
|
|
|
if pos is None:
|
|
pos = (len(self.lst) - 1)
|
|
|
|
self.focus = pos
|
|
self._modified()
|
|
try:
|
|
if hasattr(item, 'original_widget'):
|
|
item.original_widget.set_focus(
|
|
len(item.original_widget.contents) - 1)
|
|
else:
|
|
item.set_focus(len(item.contents) - 1)
|
|
except Exception:
|
|
# Ignore failure. Case only applies to TabbedColumns and
|
|
# TabbedGridFlow. Other items should fail silently.
|
|
pass
|
|
|
|
def get_focus(self):
|
|
if self.lst:
|
|
return self.lst[self.focus], self.focus
|
|
else:
|
|
return None, None
|
|
|
|
def set_focus(self, focus):
|
|
self.focus = focus
|
|
|
|
def get_next(self, pos):
|
|
if (pos + 1) >= len(self.lst):
|
|
return None, None
|
|
return self.lst[pos + 1], pos + 1
|
|
|
|
def get_prev(self, pos):
|
|
if (pos - 1) < 0:
|
|
return None, None
|
|
return self.lst[pos - 1], pos - 1
|