[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r9164 - trunk/gnue-forms/src/uidrivers/curses/widgets
From: |
johannes |
Subject: |
[gnue] r9164 - trunk/gnue-forms/src/uidrivers/curses/widgets |
Date: |
Thu, 14 Dec 2006 09:40:13 -0600 (CST) |
Author: johannes
Date: 2006-12-14 09:40:12 -0600 (Thu, 14 Dec 2006)
New Revision: 9164
Modified:
trunk/gnue-forms/src/uidrivers/curses/widgets/_base.py
trunk/gnue-forms/src/uidrivers/curses/widgets/entry.py
Log:
Started refactoring curses entry widgets (not done yet)
Modified: trunk/gnue-forms/src/uidrivers/curses/widgets/_base.py
===================================================================
--- trunk/gnue-forms/src/uidrivers/curses/widgets/_base.py 2006-12-13
09:59:22 UTC (rev 9163)
+++ trunk/gnue-forms/src/uidrivers/curses/widgets/_base.py 2006-12-14
15:40:12 UTC (rev 9164)
@@ -38,6 +38,21 @@
"""
# -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
+
+ def __init__(self, event):
+
+ UIWidget.__init__(self, event)
+ self.__focus_index = None
+
+ self.top = 0
+ self.left = 0
+ self.width = 0
+ self.height = 0
+
+
+ # -------------------------------------------------------------------------
# Create a widget
# -------------------------------------------------------------------------
@@ -46,12 +61,6 @@
Initialize the coordinates of a widget. These coordinates will be set
later using set_size_and_fit().
"""
-
- self.top = 0
- self.left = 0
- self.width = 0
- self.height = 0
-
self._parent = event.container
@@ -78,6 +87,17 @@
""" Returns wether the container is ready for output or not """
return self._container_is_ready_()
+
+ # -------------------------------------------------------------------------
+ # Call a method of a given widget (if it exists)
+ # -------------------------------------------------------------------------
+
+ def _call_widget_(self, index, method, *args, **kwargs):
+
+ func = getattr(self.widgets[index], method, None)
+ if func:
+ func(*args, **kwargs)
+
# -------------------------------------------------------------------------
# Focus handling
@@ -86,19 +106,21 @@
def _ui_set_focus_(self, index):
self._uiDriver._focus_widget = self
- self._get_focus(index)
+ self.__focus_index = index
+ self._call_widget_(index, '_ui_set_focus_')
# -------------------------------------------------------------------------
def _ui_focus_in_(self, index):
- pass
+ self._call_widget_(index, '_ui_focus_in_')
# -------------------------------------------------------------------------
def _ui_focus_out_(self, index):
- self._lose_focus(index)
+ self._call_widget_(index, '_ui_focus_out_')
+ self.__focus_index = None
# -------------------------------------------------------------------------
@@ -121,6 +143,44 @@
# -------------------------------------------------------------------------
+ # Keypress
+ # -------------------------------------------------------------------------
+
+ def _keypress(self, key):
+
+ if self.__focus_index is not None:
+ widget = self.widgets[self.__focus_index]
+
+ # If the widget has an implementation for a keypress handler, let
+ # it try to handle the key
+ func = getattr(widget, '_keypress', None)
+ if func and func(key):
+ return
+
+ UIWidget._keypress(self, key)
+
+
+ # -------------------------------------------------------------------------
+ # Function keypress
+ # -------------------------------------------------------------------------
+
+ def _fkeypress(self, key, shift, ctrl, meta):
+
+ if self.__focus_index is not None:
+ widget = self.widgets[self.__focus_index]
+
+ # If the widget has an implementation for a keypress handler, let
+ # it try to handle the key
+ func = getattr(widget, '_fkeypress', None)
+ if func and func(key, shift, ctrl, meta):
+ return
+
+ UIWidget._fkeypress(self, key, shift, ctrl, meta)
+
+
+
+
+ # -------------------------------------------------------------------------
# Get the minimum size of a widget
# -------------------------------------------------------------------------
Modified: trunk/gnue-forms/src/uidrivers/curses/widgets/entry.py
===================================================================
--- trunk/gnue-forms/src/uidrivers/curses/widgets/entry.py 2006-12-13
09:59:22 UTC (rev 9163)
+++ trunk/gnue-forms/src/uidrivers/curses/widgets/entry.py 2006-12-14
15:40:12 UTC (rev 9164)
@@ -23,7 +23,7 @@
import curses
-from _base import UIHelper
+from gnue.forms.uidrivers.curses.widgets import _base
__all__ = ['UIEntry']
@@ -31,119 +31,96 @@
# Entry class
# =============================================================================
-class UIEntry(UIHelper):
+class UIEntry(_base.UIHelper):
"""
Interface implementation for <entry> widgets.
"""
# -------------------------------------------------------------------------
- # Initialization
+ # Widget creation
# -------------------------------------------------------------------------
- def __init__(self, event):
+ def _create_widget_(self, event, spacer):
- UIHelper.__init__(self, event)
+ _base.UIHelper._create_widget_(self, event, spacer)
+
+ style = self._gfObject.style.lower()
+ build = getattr(self, '_UIEntry__build_%s' % style, None)
+ if not build:
+ build = self.__build_default
- self.__style = self._gfObject.style.lower()
- self.__value = {}
- self.__offset = {}
- self.__selection = {}
- self.__enabled = {}
- self.__voffset = {}
+ (self.label, self.widget) = build(spacer * (self._gfObject._gap + 1))
+ return self.widget
- self.__is_multiline = (self.__style == 'multiline')
- self.__focusIndex = None
- self.__cursor = (0, 0)
+ # -------------------------------------------------------------------------
+ # Create the various entry widgets
+ # -------------------------------------------------------------------------
- # additional indices for listboxes
- self.__index = {}
- self.__pindex = {}
- self.__oldCursor = 1
- self.__choices = []
+ def __build_default(self, row_offset, password=False):
- if self.__style == 'checkbox':
- self.__setCursor(1, 0)
+ result = TextEntry(self, row_offset, password)
+ return (None, result)
# -------------------------------------------------------------------------
- # Initialization per row
- # -------------------------------------------------------------------------
- def _create_widget_(self, event, spacer):
+ def __build_password(self, row_offset):
- UIHelper._create_widget_(self, event, spacer)
-
- self.__value[spacer] = None
- self.__selection[spacer] = None
- self.__enabled[spacer] = True
- self.__offset[spacer] = 0
- self.__voffset[spacer] = 0
- self.__index[spacer] = 0
- self.__pindex[spacer] = 1
+ return self.__build_default(row_offset, True)
-
# -------------------------------------------------------------------------
- # Enable/disable this entry
- # -------------------------------------------------------------------------
- def _ui_enable_(self, index):
- self.__enabled[index] = True
- self.__repaint(index)
+ def __build_dropdown(self, row_offset):
+ result = DropDownEntry(self, row_offset)
+ return (None, result)
+
# -------------------------------------------------------------------------
- def _ui_disable_(self, index):
- self.__enabled[index] = False
- self.__repaint(index)
+ def __build_checkbox(self, row_offset):
+ result = Checkbox(self, row_offset)
+ return (None, result)
+
# -------------------------------------------------------------------------
- # Focus has changed to this entry
- # -------------------------------------------------------------------------
- def _get_focus(self, index):
+ def __build_label(self, row_offset):
- self.__focusIndex = index
+ result = StaticText(self, row_offset)
+ return (None, result)
- self.__offset[index] = 0
- self.__voffset[index] = 0
- self.__index[index] = 0
- self.__pindex[index] = 1
+ # -------------------------------------------------------------------------
- if self.__style == 'listbox':
- self.__oldCursor = curses.curs_set(0)
+ def __build_listbox(self, row_offset):
- self.__update_cursor_position()
- self.__repaint(index)
+ result = ListBoxEntry(self, row_offset)
+ return (None, result)
+
# -------------------------------------------------------------------------
- # Focus has changed away from this entry
+ # Enable/disable this entry
# -------------------------------------------------------------------------
- def _lose_focus(self, index):
+ def _ui_enable_(self, index):
- if self.__style == 'listbox':
- curses.curs_set(self.__oldCursor)
+ self.widgets[index]._ui_enable_()
- self.__focusIndex = None
- self.__selection[index] = None
+ # -------------------------------------------------------------------------
- self.__repaint(index)
+ def _ui_disable_(self, index):
+ self.widgets[index]._ui_disable_()
+
+
# -------------------------------------------------------------------------
# Set value for entry
# -------------------------------------------------------------------------
def _ui_set_value_(self, index, value):
- if self.__style == 'listbox' and value in self.__choices:
- if self.__value[index] <> value:
- self.__index[index] = self.__choices.index(value)
- self.__pindex[index] = 1
- self.__offset[index] = self.__index[index]
+ self._call_widget_(index, '_ui_set_value_', value)
- self.__value[index] = value
- self.__repaint(index)
# -------------------------------------------------------------------------
# Update the list of choices
@@ -151,354 +128,564 @@
def _ui_set_choices_(self, index, choices):
- self.__choices = choices[:]
+ self._call_widget_(index, '_ui_set_choices_', choices)
+
# -------------------------------------------------------------------------
# Set cursor position
# -------------------------------------------------------------------------
def _ui_set_cursor_position_(self, index, position):
- if not self.ready():
- return
+ self._call_widget_(index, '_ui_set_cursor_position_', position)
- old_selection = self.__selection[index]
- self.__selection[index] = None
- need_repaint = old_selection is not None
- assert gDebug(2, "----- new position: %s" % position)
- assert gDebug(2, " Value : %r" % self.__value[index])
- assert gDebug(2, " Curr.Offset : %s/%s" % (self.__offset[index],
- self.__voffset[index]))
+ # -------------------------------------------------------------------------
+ # Set start and end of selection area
+ # -------------------------------------------------------------------------
- if self.__style in ['checkbox', 'listbox']:
- return
+ def _ui_set_selected_area_(self, index, selection1, selection2):
- if self.__is_multiline:
- if position == 0 or self.__value[index] is None:
- self.__offset[index] = 0
- self.__voffset[index] = 0
- self.__repaint(index)
- self.__setCursor(0, 0)
- return
+ self._call_widget_(index, '_ui_set_selected_area_', selection1,
+ selection2)
- # Grab the text portion, which is everything up to position. If the
- # last character is a newline, we can remove this, since it would
- # result in a wrong vertical offset
- value = self.__value[index][:position+1]
- vcorr = [0, 1][value[-1] == '\n']
+ # -------------------------------------------------------------------------
+ # Clipboard and selection
+ # -------------------------------------------------------------------------
- assert gDebug(2, " Cut-Part : %r" % value)
- assert gDebug(2, " Vert.Correct: %s" % vcorr)
+ def _ui_cut_(self, index):
+
+ self._call_widget_(index, '_ui_cut_')
- # Get the vertical cursor-position and offset
- cpVertical = value.count('\n') - self.__voffset[index] - vcorr
+ # -------------------------------------------------------------------------
- if cpVertical < 0:
- # the position is not visible right now, so we need to scroll
- # up (which means changing the voffset). We set the
- # cursor-position to line 0.
- self.__voffset[index] += cpVertical
- cpVertical = 1
- need_repaint = True
+ def _ui_copy_(self, index):
- elif cpVertical >= self.height:
- # the position is not visible right now, so we need to scroll
- # down (which means changing the voffset).
- self.__voffset[index] = value.count('\n') - \
- self.height + 1 - vcorr
- cpVertical = self.height # Pos. are Zero-based
- need_repaint = True
+ self._call_widget_(index, '_ui_copy_')
- # Now, after having a valid row, we need to determine the
horizontal
- # offset based on the last line holding our requested position.
- currentLine = value.splitlines()[-1]
- cpHorizontal = len(currentLine) - self.__offset[index] - 1
+ # -------------------------------------------------------------------------
- if cpHorizontal < 0:
- # Beyond left margin, so scroll to the left
- self.__offset[index] += cpHorizontal
- cpHorizontal = 0
- need_repaint = True
+ def _ui_paste_(self, index):
+
+ self._call_widget_(index, '_ui_paste_')
- elif cpHorizontal > self.width:
- self.__offset[index] = len(currentLine) - self.width
- cpHorizontal = self.width
- need_repaint = True
+ # -------------------------------------------------------------------------
- if need_repaint:
- self.__repaint(index)
+ def _ui_select_all_(self, index):
+
+ self._call_widget_(index, '_ui_select_all_')
- cpHorizontal = min(cpHorizontal, self.width)
- cpHorizontal = max(cpHorizontal, 0)
- cpVertical = min(cpVertical, self.height - 1)
- cpVertical = max(cpVertical, 0)
- assert gDebug(2, "H/V: %s/%s - Offsets %s/%s" % (cpHorizontal,
- cpVertical, self.__offset[index], self.__voffset[index]))
+ # -------------------------------------------------------------------------
+ #
+ # -------------------------------------------------------------------------
- self.__setCursor(cpHorizontal, cpVertical)
+ def set_size_and_fit(self, width, height):
+ self.width = width
+ self.height = height
+ for widget in self.widgets:
+ widget._repaint_()
+
+
+ # -------------------------------------------------------------------------
+ # Get the size hints for an entry
+ # -------------------------------------------------------------------------
+
+ def get_size_hints(self, vertical=None):
+
+ label = ''
+ if self._gfObject.style != 'checkbox':
+ label = getattr(self._gfObject, 'label', '')
+
+ # Only stretch entries if they're in a horizontal container or if they
+ # are multiline edits
+ if not vertical or self._gfObject.style == 'multiline':
+ stretch = self.stretch
else:
- if self.__style != ['checkbox']:
- npos = position - self.__offset[index]
- if npos > self.width:
- self.__offset[index] = position - self.width
- npos = self.width
- self.__repaint(index)
- need_repaint = False
+ stretch = 0
- elif npos < 0:
- self.__offset[index] += npos
- npos = 0
- self.__repaint(index)
- need_repaint = False
+ return (self.min_width or 20, self.min_height or 1, len(label),
stretch)
- position = npos
- if need_repaint:
- self.__repaint(index)
+# =============================================================================
+# Base Entry Widget
+# =============================================================================
- self.__setCursor(position, 0)
+class BaseEntry(object):
+ """
+ The base class for widget implementations
+ """
-
# -------------------------------------------------------------------------
- # Set start and end of selection area
+ # Constructor
# -------------------------------------------------------------------------
- def _ui_set_selected_area_(self, index, selection1, selection2):
+ def __init__(self, entry, row_offset):
- if selection1 == selection2:
- self.__selection[index] = None
- else:
- self.__selection[index] = (selection1, selection2)
+ self.entry = entry
+ self.row_offset = row_offset
+ self.value = None
+ self.choices = []
+ self.has_focus = False
+ self.enabled = True
- self.__repaint(index)
- gDebug(2, "Set-Selection: %s %s %s" % (index, selection1, selection2))
# -------------------------------------------------------------------------
- # Clipboard and selection
+ # Virtual Methods
# -------------------------------------------------------------------------
- def _ui_cut_(self, index):
+ def _repaint_(self):
+ """
+ Descendants must implement this method to draw the widget onto it's
+ parent
+ """
pass
+
# -------------------------------------------------------------------------
+ # Event Handler
+ # -------------------------------------------------------------------------
- def _ui_copy_(self, index):
- pass
+ def _ui_set_value_(self, value):
+ self.value = value
+ self._repaint_()
+
# -------------------------------------------------------------------------
- def _ui_paste_(self, index):
- pass
+ def _ui_set_choices_(self, choices):
+ self.choices = choices
+ self._repaint_()
+
# -------------------------------------------------------------------------
- def _ui_select_all_(self, index):
- pass
+ def _ui_focus_in_(self):
+ self.has_focus = True
+ self._repaint_()
+
# -------------------------------------------------------------------------
- # Update entry representation on screen
+
+ def _ui_focus_out_(self):
+
+ self.has_focus = False
+ self._repaint_()
+
# -------------------------------------------------------------------------
- def __repaint(self, index):
+ def _ui_enable_(self):
- if not self.ready():
- return
+ self.enabled = True
+ self._repaint_()
- if self.__style == 'listbox':
- # First draw the visible items of the listbox
- offset = self.__offset[index]
- lines = self.__choices[offset:offset + self.height]
+ # -------------------------------------------------------------------------
- for (line, value) in enumerate(lines):
- text = value.ljust(self.width)[:self.width]
- attr = self.__get_attr(index, (line == self.__pindex[index]-1))
- # Note: this is not safe if there's a gap !
- self._set_text(index+line, text, attr)
+ def _ui_disable_(self):
- self._parent.move(self.left, self.top + self.__pindex[index] - 1)
+ self.enabled = False
+ self._repaint_()
- elif self.__is_multiline:
- # Create all visible, empty lines
- data = [''.ljust(self.width)] * self.height
- hOffset = self.__offset[index]
- vOffset = self.__voffset[index]
- # Overwrite these empty lines with the data as stated by v/h-Offset
- if self.__value[index]:
- add =
self.__value[index].splitlines()[vOffset:vOffset+self.height]
- for (ix, text) in enumerate(add):
- text = text[hOffset:hOffset + self.width]
- data[ix] = text.ljust(self.width)[:self.width]
+ # -------------------------------------------------------------------------
+ # Properties
+ # -------------------------------------------------------------------------
- attr = self.__get_attr(index)
+ def __get_top(self):
+ return self.entry.top + self.row_offset
- # And write everything to screen
- for (ix, text) in enumerate(data):
- self._set_text(index + ix, text, attr, self.__selection[index])
+ top = property(__get_top, None, None, """ Get the upper left row """)
- else:
- value = self.__value[index]
- offset = self.__offset[index]
- text = ''
+ # -------------------------------------------------------------------------
- if self.__style in['default', 'label', 'dropdown']:
- text = value or ''
- text = text[offset:offset + self.width]
- text += ' ' * (self.width - len(text))
+ def __get_left(self):
+ return self.entry.left
- elif self.__style == 'password':
- text = '*' * len(value or '')
- text = text[offset:offset + self.width]
- text += ' ' * (self.width - len(text))
+ left = property(__get_left, None, None, """ The upper left colum """)
- elif self.__style == 'checkbox':
- attr = self._uiDriver.attr['background']
- self._set_text(index, ' %s' % self._gfObject.label, attr)
+ # -------------------------------------------------------------------------
- if self.__value[index] is None:
- text = '[-]'
- elif self.__value[index]:
- text = '[X]'
- else:
- text = '[ ]'
+ def __get_width(self):
+ return self.entry.width
- else:
- gDebug(2, "STYLE==%s" % self.__style)
+ width = property(__get_width, None, None, """ The widget width """)
- attr = self.__get_attr(index)
- self._set_text(index, text, attr, self.__selection[index])
+ # -------------------------------------------------------------------------
+ def __get_height(self):
+ return self.entry.height
+ height = property(__get_height, None, None, """ The widget height """)
+
# -------------------------------------------------------------------------
- # Get the current screen attributes to be used
- # -------------------------------------------------------------------------
- def __get_attr(self, index, selected=False):
+ def __get_attr(self):
- add = 0
- if self.__style == 'label':
- attr = 'background'
- elif not self.__enabled[index]:
+ if not self.enabled:
attr = 'disabled'
- elif index == self.__focusIndex:
+ elif self.has_focus:
attr = 'focusentry'
- if self.__style == 'listbox' and selected:
- add = curses.A_STANDOUT
else:
attr = 'entry'
- return self._uiDriver.attr[attr] + add
+ return self.entry._uiDriver.attr[attr]
+ attribute = property(__get_attr, None, None,
+ """ The current attribute to use for this widget """)
+# =============================================================================
+# Static Text style entry
+# =============================================================================
+
+class StaticText(BaseEntry):
+ """
+ A static text entry is an read-only entry.
+ """
+
# -------------------------------------------------------------------------
- # handle keypress
+ # Draw the static text entry
# -------------------------------------------------------------------------
- def _keypress(self, key):
+ def _repaint_(self):
- if self.__style == 'dropdown' and key == chr(self._uiDriver.lookupKey):
- mapping = {}
- for item in self.__choices:
- mapping[item] = item
- res = self._uiDriver.getOption(u_("Select option"), mapping)
- if res is not None:
- self._request('REPLACEVALUE', text = res)
+ text = ("%s" % self.value)[:self.width]
+ text += ' ' * (self.width - len(text))
+ self.entry._parent.write(self.left, self.top, text,
+ self.entry._uiDriver.attr['background'])
+
+
+
+# =============================================================================
+# Single line text entry
+# =============================================================================
+
+class TextEntry(BaseEntry):
+ """
+ Entry widget implementing single line text or password entries.
+ """
+
+ # -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
+
+ def __init__(self, entry, row_offset, password=False):
+
+ BaseEntry.__init__(self, entry, row_offset)
+ self.password = password
+ self.selection = None
+ self.offset = 0
+
+
+ # -------------------------------------------------------------------------
+ # UI event handler
+ # -------------------------------------------------------------------------
+
+ def _ui_set_cursor_position_(self, position):
+ """
+ Set the cursor position. An already existing selection gets
+ unselected.
+ """
+
+ # If there is a selection atm, we have to unselected it. Thus we need
+ # a repaint
+ need_repaint = self.selection is not None
+ self.selection = None
+
+ if not self.entry.ready():
+ return
+
+ pos = position - self.offset
+ if pos > self.width-1:
+ self.offset = position - self.width + 1
+ pos = self.width-1
+ need_repaint = True
+
+ elif pos < 0:
+ self.offset += pos
+ pos = 0
+ need_repaint = True
+
+ if need_repaint:
+ self._repaint_()
+
+ if self.has_focus:
+ self.entry._parent.move(self.left + pos, self.top)
+
+
+ # -------------------------------------------------------------------------
+
+ def _ui_set_selected_area_(self, selection1, selection2):
+ """
+ Set the current selection and repaint the widget
+ """
+
+ if selection1 == selection2:
+ self.selection = None
else:
+ self.selection = (selection1, selection2)
+ self._repaint_()
+
- sel = self.__selection[self.__focusIndex]
- assert gDebug(2, "SELECTION: %s" % repr(sel))
- UIHelper._keypress(self, key)
+ # -------------------------------------------------------------------------
+ def _ui_focus_out_(self):
+ """
+ On leaving a widget make sure to remove a selection as well as reset
+ the offset.
+ """
+ self.selection = None
+ self.offset = 0
+
+ BaseEntry._ui_focus_out_(self)
+
+
+
# -------------------------------------------------------------------------
- # handle function keypress
+ # Implementation Virtual methods
# -------------------------------------------------------------------------
- def _fkeypress(self, key, shift, ctrl, meta):
+ def _repaint_(self):
+ """
+ Draw the text entry widget
+ """
- if self.__style == 'listbox' and key in[curses.KEY_DOWN,
curses.KEY_UP]:
- self.__move([1, -1][key == curses.KEY_UP])
+ if self.password:
+ vtext = '*' * len(self.value or '')
else:
- UIHelper._fkeypress(self, key, shift, ctrl, meta)
+ vtext = self.value or ''
+ text = vtext[self.offset:self.offset + self.width]
+ text += ' ' * (self.width - len(text))
+ if self.selection:
+ (sel1, sel2) = self.selection
+ self.entry._parent.write(self.left, self.top, text[:sel1],
+ self.attribute)
+ self.entry._parent.write(self.left + sel1, self.top,
+ text[sel1:sel2], self.attribute + curses.A_STANDOUT)
+ self.entry._parent.write(self.left + sel2, self.top, text[sel2:],
+ self.attribute)
+ else:
+ self.entry._parent.write(self.left, self.top, text, self.attribute)
+
+# =============================================================================
+# Drodown Entry
+# =============================================================================
+
+class DropDownEntry(TextEntry):
+ """
+ A dropdown entry extends a single line text entry since it has a list of
+ allowed values from which the user can choose one.
+ """
+
# -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
- def __move(self, direction):
+ def __init__(self, entry, row_offset):
- index = self.__focusIndex
- self.__pindex[index] += direction
- self.__index[index] += direction
+ self.__mapping = {}
+ TextEntry.__init__(self, entry, row_offset)
- if self.__pindex[index] > self.height:
- if self.__index[index] < len(self.__choices):
- self.__offset[index] += direction
- elif self.__pindex[index] < 1:
- self.__offset[index] = max(0, self.__offset[index] - 1)
+ # -------------------------------------------------------------------------
+ # UI Event handler
+ # -------------------------------------------------------------------------
- self.__index[index] = max(0, self.__index[index])
- self.__index[index] = min(len(self.__choices) - 1, self.__index[index])
+ def _ui_set_choices_(self, choices):
- self.__pindex[index] = max(1, self.__pindex[index])
- self.__pindex[index] = min(self.__pindex[index], self.height)
+ TextEntry._ui_set_choices_(self, choices)
- self.__value[index] = self.__choices[self.__index[index]]
- self._request('REPLACEVALUE', text = self.__value[index])
+ self.__mapping = {}
+ for item in self.choices:
+ self.__mapping[item] = item
+
# -------------------------------------------------------------------------
- # Set cursor position for widget
+ # Keypress handler
# -------------------------------------------------------------------------
- def __setCursor(self, x, y):
+ def _keypress(self, key):
+ """
+ If the key is the lookup key a selection dialog will be displayed. If
+ the user selects an option a REPLACEVALUE event is generated.
+ Otherwise the key gets passed back and it should be handled by the
+ entry itself.
- self.__cursor = (x, y)
- self.__update_cursor_position()
+ @returns: True if the key event has been handled, False otherwise.
+ """
+ if key == chr(self.entry._uiDriver.lookupKey):
+ # We can handle the lookup key here
+ choice = self.entry._uiDriver.getOption(u_("Select option"),
+ self.__mapping)
+ if choice is not None:
+ self.entry._request('REPLACEVALUE', text=choice)
+
+ result = True
+ else:
+ result = False
+
+ return result
+
+
+# =============================================================================
+# Checkbox widget
+# =============================================================================
+
+class Checkbox(BaseEntry):
+
# -------------------------------------------------------------------------
- # Update cursor position
+ # UI event handler
# -------------------------------------------------------------------------
- def __update_cursor_position(self):
+ def _ui_focus_in_(self):
- if self.__focusIndex is not None:
- (x, y) = self.__cursor
- self._parent.move(self.left + x, self.top + self.__focusIndex + y)
+ BaseEntry._ui_focus_in_(self)
+ self.entry._parent.move(self.left + 1, self.top)
- def set_size_and_fit(self, width, height):
+ # -------------------------------------------------------------------------
+ # Draw the checkbox in it's current state
+ # -------------------------------------------------------------------------
- self.width = width
- self.height = height
+ def _repaint_(self):
- for index in range(len(self.widgets)):
- self.__repaint(index)
+ label = ' %s' % self.entry._gfObject.label
+ text = label[:self.width]
+ text += ' ' * (self.width - len(text))
+ self.entry._parent.write(self.left, self.top, text,
+ self.entry._uiDriver.attr['background'])
+ if self.value is None:
+ text = '[-]'
+ elif self.value:
+ text = '[X]'
+ else:
+ text = '[ ]'
+
+ self.entry._parent.write(self.left, self.top, text, self.attribute)
+
+
+# =============================================================================
+# A ListBox entry
+# =============================================================================
+
+class ListBoxEntry(BaseEntry):
+
# -------------------------------------------------------------------------
- # Get the size hints for an entry
+ # Constructor
# -------------------------------------------------------------------------
- def get_size_hints(self, vertical=None):
+ def __init__(self, entry, row_offset):
- label = ''
- if self.__style != 'checkbox':
- label = getattr(self._gfObject, 'label', '')
+ BaseEntry.__init__(self, entry, row_offset)
+ self.offset = 0
+ self.selected = None
+ self.display = None
+ self.__old_cursor = None
- # Only stretch entries if they're in a horizontal container or if they
- # are multiline edits
- if not vertical or self.__is_multiline:
- stretch = self.stretch
+
+ # -------------------------------------------------------------------------
+ # UI event handler
+ # -------------------------------------------------------------------------
+
+ def _ui_set_value_(self, value):
+
+ if value <> self.value:
+ # If the value has changed from outside (not due to a call of our
+ # __move method), we start off with a fresh display-offset. This
+ # means the newly set value will be the first row displayed in the
+ # listbox widget.
+ if value in self.choices:
+ self.selected = self.offset = self.choices.index(value)
+ else:
+ self.selected = self.offset = 0
+
+ self.display = 1
+
+ BaseEntry._ui_set_value_(self, value)
+
+
+ # -------------------------------------------------------------------------
+
+ def _ui_focus_in_(self):
+
+ self.__old_cursor = curses.curs_set(0)
+ BaseEntry._ui_focus_in_(self)
+
+ # -------------------------------------------------------------------------
+
+ def _ui_focus_out_(self):
+
+ curses.curs_set(self.__old_cursor)
+ BaseEntry._ui_focus_out_(self)
+
+
+ # -------------------------------------------------------------------------
+ # Draw the listbox widget
+ # -------------------------------------------------------------------------
+
+ def _repaint_(self):
+
+ lines = self.choices[self.offset:self.offset + self.height]
+ if len(lines) < self.height:
+ lines.extend([''] * (self.height - len(lines)))
+
+ for (row, value) in enumerate(lines):
+ text = value.ljust(self.width)[:self.width]
+ attr = self.attribute
+ if self.has_focus and row == self.display-1:
+ attr += curses.A_STANDOUT
+
+ self.entry._parent.write(self.left, self.top + row, text, attr)
+
+
+ # -------------------------------------------------------------------------
+ # Handle the up- and down-keys here
+ # -------------------------------------------------------------------------
+
+ def _fkeypress(self, key, shift, ctrl, meta):
+
+ if key in [curses.KEY_UP, curses.KEY_DOWN]:
+ self.__move([1, -1][key == curses.KEY_UP])
+ return True
else:
- stretch = 0
+ return False
- return (self.min_width or 20, self.min_height or 1, len(label),
stretch)
+ # -------------------------------------------------------------------------
+ # Select the prior/next element of the listbox
+ # -------------------------------------------------------------------------
+ def __move(self, direction):
+
+ self.display += direction
+ self.selected += direction
+
+ if self.display > self.height:
+ if self.selected < len(self.choices):
+ self.offset += direction
+
+ elif self.display < 1:
+ self.offset = max(0, self.offset - 1)
+
+ self.selected = max(0, self.selected)
+ self.selected = min(len(self.choices) - 1, self.selected)
+
+ self.display = max(1, self.display)
+ self.display = min(self.display, self.height)
+
+ # NOTE: in order to keep the display-index accross _ui_set_value_ calls
+ # we set it manually here.
+ self.value = self.choices[self.selected]
+ self.entry._request('REPLACEVALUE', text=self.value)
+
+
# =============================================================================
# Configuration data
# =============================================================================
@@ -507,4 +694,4 @@
'baseClass' : UIEntry,
'provides' : 'GFEntry',
'container' : 0,
- }
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r9164 - trunk/gnue-forms/src/uidrivers/curses/widgets,
johannes <=