Module Gnumed.wxpython.gmPhraseWheel

GNUmed phrasewheel.

A class, extending wx.TextCtrl, which has a drop-down pick list, automatically filled based on the inital letters typed. Based on the interface of Richard Terry's Visual Basic client.

This is based on seminal work by Ian Haywood ihaywood@gnu.org

Functions

def shutdown()
Expand source code
def shutdown():
        """It can be useful to call this early from your shutdown code to avoid hangs on Notify()."""
        global _timers
        _log.info('shutting down %s pending timers', len(_timers))
        for timer in _timers:
                _log.debug('timer [%s]', timer)
                timer.Stop()
        _timers = []

It can be useful to call this early from your shutdown code to avoid hangs on Notify().

Classes

class cMultiPhraseWheel (*args, **kwargs)
Expand source code
class cMultiPhraseWheel(cPhraseWheelBase):

        def __init__(self, *args, **kwargs):

                super(cMultiPhraseWheel, self).__init__(*args, **kwargs)

                self.phrase_separators = default_phrase_separators
                self.left_part = ''
                self.right_part = ''

        #---------------------------------------------------------
        def GetData(self, can_create=False, as_instance=False, link_obj=None):
                super().GetData(can_create = can_create, link_obj = link_obj)
                if len(self._data) > 0:
                        if as_instance:
                                return self._data2instance(link_obj = link_obj)

                return list(self._data.values())

        #---------------------------------------------------------
        def list2data_dict(self, data_items=None):

                data_dict = {}

                for item in data_items:
                        try:
                                list_label = item['list_label']
                        except KeyError:
                                list_label = item['label']
                        try:
                                field_label = item['field_label']
                        except KeyError:
                                field_label = list_label
                        data_dict[field_label] = {'data': item['data'], 'list_label': list_label, 'field_label': field_label}

                return data_dict
        #---------------------------------------------------------
        # internal API
        #---------------------------------------------------------
        def _adjust_data_after_text_update(self):
                # the textctrl display must already be set properly
                new_data = {}
                # this way of looping automatically removes stale
                # data for labels which are no longer displayed
                for displayed_label in self.displayed_strings:
                        try:
                                new_data[displayed_label] = self._data[displayed_label]
                        except KeyError:
                                # this removes stale data for which there
                                # is no displayed_label anymore
                                pass

                self.data = new_data
        #---------------------------------------------------------
        def _extract_fragment_to_match_on(self):

                cursor_pos = self.GetInsertionPoint()

                entire_input = self.GetValue()
                if self.__phrase_separators.search(entire_input) is None:
                        self.left_part = ''
                        self.right_part = ''
                        return self.GetValue().strip()

                string_left_of_cursor = entire_input[:cursor_pos]
                string_right_of_cursor = entire_input[cursor_pos:]

                left_parts = [ lp.strip() for lp in self.__phrase_separators.split(string_left_of_cursor) ]
                if len(left_parts) == 0:
                        self.left_part = ''
                else:
                        self.left_part = '%s%s ' % (
                                ('%s ' % self.__phrase_separators.pattern[0]).join(left_parts[:-1]),
                                self.__phrase_separators.pattern[0]
                        )

                right_parts = [ rp.strip() for rp in self.__phrase_separators.split(string_right_of_cursor) ]
                self.right_part = '%s %s' % (
                        self.__phrase_separators.pattern[0],
                        ('%s ' % self.__phrase_separators.pattern[0]).join(right_parts[1:])
                )

                val = (left_parts[-1] + right_parts[0]).strip()
                return val
        #--------------------------------------------------------
        def _update_display_from_picked_item(self, item):
                val = ('%s%s%s' % (
                        self.left_part,
                        self._picklist_item2display_string(item = item),
                        self.right_part
                )).lstrip().lstrip(';').strip()
                self.suppress_text_update_smarts = True
                super(cMultiPhraseWheel, self).SetValue(val)
                # find item end and move cursor to that place:
                item_end = val.index(item['field_label']) + len(item['field_label'])
                self.SetInsertionPoint(item_end)
                return
        #--------------------------------------------------------
        def _update_data_from_picked_item(self, item):

                # add item to the data
                self._data[item['field_label']] = item

                # the textctrl display must already be set properly
                field_labels = [ p.strip() for p in self.__phrase_separators.split(self.GetValue().strip()) ]
                new_data = {}
                # this way of looping automatically removes stale
                # data for labels which are no longer displayed
                for field_label in field_labels:
                        try:
                                new_data[field_label] = self._data[field_label]
                        except KeyError:
                                # this removes stale data for which there
                                # is no displayed_label anymore
                                pass

                self.data = new_data
        #---------------------------------------------------------
        def _dictify_data(self, data=None, value=None):
                if type(data) == type([]):
                        # useful because self.GetData() returns just such a list
                        return self.list2data_dict(data_items = data)
                # else assume new-style already-dictified data
                return data
        #--------------------------------------------------------
        # properties
        #--------------------------------------------------------
        def _set_phrase_separators(self, phrase_separators):
                """Set phrase separators.

                - must be a valid regular expression pattern

                input is split into phrases at boundaries defined by
                this regex and matching is performed on the phrase
                the cursor is in only,

                after selection from picklist phrase_separators[0] is
                added to the end of the match in the PRW
                """
                self.__phrase_separators = regex.compile(phrase_separators, flags = regex.UNICODE)

        def _get_phrase_separators(self):
                return self.__phrase_separators.pattern

        phrase_separators = property(_get_phrase_separators, _set_phrase_separators)
        #--------------------------------------------------------
        def _get_displayed_strings(self):
                return [ p.strip() for p in self.__phrase_separators.split(self.GetValue().strip()) if p.strip() != '' ]

        displayed_strings = property(_get_displayed_strings)

Widget for smart guessing of user fields, after Richard Terry's interface.

  • VB implementation by Richard Terry
  • Python port by Ian Haywood for GNUmed
  • enhanced by Karsten Hilbert for GNUmed
  • enhanced by Ian Haywood for aumed
  • enhanced by Karsten Hilbert for GNUmed

@param matcher: a class used to find matches for the current input @type matcher: a L{match provider} instance or C{None}

@param selection_only: whether free-text can be entered without associated data @type selection_only: boolean

@param capitalisation_mode: how to auto-capitalize input, valid values are found in L{capitalize()} @type capitalisation_mode: integer

@param accepted_chars: a regex pattern defining the characters acceptable in the input string, if None no checking is performed @type accepted_chars: None or a string holding a valid regex pattern

@param final_regex: when the control loses focus the input is checked against this regular expression @type final_regex: a string holding a valid regex pattern

@param navigate_after_selection: whether or not to immediately navigate to the widget next-in-tab-order after selecting an item from the dropdown picklist @type navigate_after_selection: boolean

@param picklist_delay: this much time of user inactivity must have passed before the input related smarts kick in and the drop down pick list is shown @type picklist_delay: integer (milliseconds)

Ancestors

  • cPhraseWheelBase
  • wx._core.TextCtrl
  • wx._core.Control
  • wx._core.Window
  • wx._core.WindowBase
  • wx._core.EvtHandler
  • wx._core.Object
  • wx._core.Trackable
  • wx._core.TextEntry
  • sip.wrapper
  • sip.simplewrapper

Instance variables

prop displayed_strings
Expand source code
def _get_displayed_strings(self):
        return [ p.strip() for p in self.__phrase_separators.split(self.GetValue().strip()) if p.strip() != '' ]
prop phrase_separators
Expand source code
def _get_phrase_separators(self):
        return self.__phrase_separators.pattern

Methods

def list2data_dict(self, data_items=None)
Expand source code
def list2data_dict(self, data_items=None):

        data_dict = {}

        for item in data_items:
                try:
                        list_label = item['list_label']
                except KeyError:
                        list_label = item['label']
                try:
                        field_label = item['field_label']
                except KeyError:
                        field_label = list_label
                data_dict[field_label] = {'data': item['data'], 'list_label': list_label, 'field_label': field_label}

        return data_dict

Inherited members

class cPhraseWheel (parent=None, id=-1, *args, **kwargs)
Expand source code
class cPhraseWheel(cPhraseWheelBase):
        """Standard single-value Phrasewheel."""

        #---------------------------------------------------------
        def SetData(self, data=None):
                """Set the data and thereby set the value, too. if possible.

                If you call SetData() you better be prepared
                doing a scan of the entire potential match space.

                The data value must be found in the match space.

                Args:
                        data: None -> unset data, otherwise a valid (as per match provider) value from the search space
                """
                if data is None:
                        self._data = {}
                        return True

                # try getting match candidates
                self._update_candidates_in_picklist('*')

                # do we require a match ?
                if self.selection_only:
                        # yes, but we don't have any candidates
                        if len(self._current_match_candidates) == 0:
                                self.display_as_valid(valid = False)
                                return False

                # among candidates look for a match with <data>
                for candidate in self._current_match_candidates:
                        if candidate['data'] == data:
                                super(cPhraseWheel, self).SetText (
                                        value = candidate['field_label'],
                                        data = data,
                                        suppress_smarts = True
                                )
                                return True

                # no match found in candidates (but needed) ...
                if self.selection_only:
                        self.display_as_valid(valid = False)
                        return False

                # match providers simply return values, so turn them into the dict internally
                self._data = self._dictify_data(data = data)
                self.display_as_valid(valid = True)
                return True

        #--------------------------------------------------------
        # internal API
        #--------------------------------------------------------
        def _show_picklist(self, input2match):

                # this helps if the current input was already selected from the
                # list but still is the substring of another pick list item or
                # else the picklist will re-open just after selection
                if len(self._data) > 0:
                        self._picklist_dropdown.Hide()
                        return

                return super(cPhraseWheel, self)._show_picklist(input2match = input2match)

        #--------------------------------------------------------
        def _set_data_to_first_match(self):
                # data already set ?
                if len(self._data) > 0:
                        return True

                # needed ?
                val = self.GetValue().strip()
                if val == '':
                        return True

                # so try
                self._update_candidates_in_picklist(val = val)
                for candidate in self._current_match_candidates:
                        if candidate['field_label'] == val:
                                self._update_data_from_picked_item(candidate)
                                self.MarkDirty()
                                # tell listeners about the user's selection
                                for callback in self._on_selection_callbacks:
                                        callback(self._data)
                                return True

                # no exact match found
                if self.selection_only:
                        gmDispatcher.send(signal = 'statustext', msg = self.selection_only_error_msg)
                        return False

                return True

        #---------------------------------------------------------
        def _adjust_data_after_text_update(self):
                self._data = {}

        #---------------------------------------------------------
        def _extract_fragment_to_match_on(self):
                return self.GetValue().strip()

Standard single-value Phrasewheel.

Ancestors

  • cPhraseWheelBase
  • wx._core.TextCtrl
  • wx._core.Control
  • wx._core.Window
  • wx._core.WindowBase
  • wx._core.EvtHandler
  • wx._core.Object
  • wx._core.Trackable
  • wx._core.TextEntry
  • sip.wrapper
  • sip.simplewrapper

Subclasses

Methods

def SetData(self, data=None)
Expand source code
def SetData(self, data=None):
        """Set the data and thereby set the value, too. if possible.

        If you call SetData() you better be prepared
        doing a scan of the entire potential match space.

        The data value must be found in the match space.

        Args:
                data: None -> unset data, otherwise a valid (as per match provider) value from the search space
        """
        if data is None:
                self._data = {}
                return True

        # try getting match candidates
        self._update_candidates_in_picklist('*')

        # do we require a match ?
        if self.selection_only:
                # yes, but we don't have any candidates
                if len(self._current_match_candidates) == 0:
                        self.display_as_valid(valid = False)
                        return False

        # among candidates look for a match with <data>
        for candidate in self._current_match_candidates:
                if candidate['data'] == data:
                        super(cPhraseWheel, self).SetText (
                                value = candidate['field_label'],
                                data = data,
                                suppress_smarts = True
                        )
                        return True

        # no match found in candidates (but needed) ...
        if self.selection_only:
                self.display_as_valid(valid = False)
                return False

        # match providers simply return values, so turn them into the dict internally
        self._data = self._dictify_data(data = data)
        self.display_as_valid(valid = True)
        return True

Set the data and thereby set the value, too. if possible.

If you call SetData() you better be prepared doing a scan of the entire potential match space.

The data value must be found in the match space.

Args

data
None -> unset data, otherwise a valid (as per match provider) value from the search space

Inherited members

class cPhraseWheelBase (parent=None, id=-1, *args, **kwargs)
Expand source code
class cPhraseWheelBase(wx.TextCtrl):
        """Widget for smart guessing of user fields, after Richard Terry's interface.

        - VB implementation by Richard Terry
        - Python port by Ian Haywood for GNUmed
        - enhanced by Karsten Hilbert for GNUmed
        - enhanced by Ian Haywood for aumed
        - enhanced by Karsten Hilbert for GNUmed

        @param matcher: a class used to find matches for the current input
        @type matcher: a L{match provider<Gnumed.pycommon.gmMatchProvider.cMatchProvider>}
                instance or C{None}

        @param selection_only: whether free-text can be entered without associated data
        @type selection_only: boolean

        @param capitalisation_mode: how to auto-capitalize input, valid values
                are found in L{capitalize()<Gnumed.pycommon.gmTools.capitalize>}
        @type capitalisation_mode: integer

        @param accepted_chars: a regex pattern defining the characters
                acceptable in the input string, if None no checking is performed
        @type accepted_chars: None or a string holding a valid regex pattern

        @param final_regex: when the control loses focus the input is
                checked against this regular expression
        @type final_regex: a string holding a valid regex pattern

        @param navigate_after_selection: whether or not to immediately
                navigate to the widget next-in-tab-order after selecting an
                item from the dropdown picklist
        @type navigate_after_selection: boolean

        @param picklist_delay: this much time of user inactivity must have
                passed before the input related smarts kick in and the drop
                down pick list is shown
        @type picklist_delay: integer (milliseconds)
        """
        def __init__ (self, parent=None, id=-1, *args, **kwargs):

                # behaviour
                self.matcher = None
                self.selection_only = False
                self.selection_only_error_msg = _('You must select a value from the picklist or type an exact match.')
                self.capitalisation_mode = gmTools.CAPS_NONE
                self.accepted_chars = None
                self.final_regex = '.*'
                self.final_regex_error_msg = _('The content is invalid. It must match the regular expression: [%%s]. <%s>') % self.__class__.__name__
                self.navigate_after_selection = False
                self.picklist_delay = 150               # milliseconds

                # state tracking
                self._has_focus = False
                self._current_match_candidates = []
                self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
                self.suppress_text_update_smarts = False

                self.__static_tt = None
                self.__static_tt_extra = None
                #  list_label - what's been selected from the dropdown list
                #  field_label - what's being shown in the widget after selection for the selected dropdown list item
                #  data - the underlying data corresponding to the selected item
                self._data = {}

                self._on_selection_callbacks = []
                self._on_lose_focus_callbacks = []
                self._on_set_focus_callbacks = []
                self._on_modified_callbacks = []

                try:
                        kwargs['style'] = kwargs['style'] | wx.TE_PROCESS_TAB | wx.TE_PROCESS_ENTER
                except KeyError:
                        kwargs['style'] = wx.TE_PROCESS_TAB | wx.TE_PROCESS_ENTER
                super(cPhraseWheelBase, self).__init__(parent, id, **kwargs)

                self.__my_startup_color = self.GetBackgroundColour()
                self.__background_color_without_focus = self.GetBackgroundColour()
                global color_prw_valid
                if color_prw_valid is None:
                        color_prw_valid = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)

                self.__init_dropdown(parent = parent)
                self.__register_events()
                self.__init_timer()

        #--------------------------------------------------------
        # external API
        #--------------------------------------------------------
        def GetData(self, can_create:bool=False, as_instance:bool=False, link_obj=None):
                """Retrieve the data associated with the displayed string(s).

                Returns:
                        None, if no data available, and unable to create data.

                        Or a data instance, if requested and data is available or create-able.

                        Or the data itself.
                """
                if not self._data:
                        if can_create:
                                self._create_data(link_obj = link_obj)

                if not self._data:
                        return None

                if as_instance:
                        return self._data2instance(link_obj = link_obj)

                return self._data['data']

        #---------------------------------------------------------
        def SetText(self, value:str='', data=None, suppress_smarts:bool=False):
                """Set both value and data of phrasewheel.

                Args:
                        value: some text to display in the control
                        data: the data value represented by the displayed text
                        suppress_smarts: whether to generate data based on value, always True if data is passed in
                """
                if value is None:
                        value = ''

                if (value == '') and (data is None):
                        self._data = {}
                        super(cPhraseWheelBase, self).SetValue(value)
                        return

                self.suppress_text_update_smarts = suppress_smarts

                if data:
                        self.suppress_text_update_smarts = True
                        self._data = self._dictify_data(data = data, value = value)
                super(cPhraseWheelBase, self).SetValue(value)
                self.display_as_valid(valid = True)

                # if data already available
                if len(self._data) > 0:
                        return True

                # empty text value ?
                if value == '':
                        # valid value not required ?
                        if not self.selection_only:
                                return True

                if not self._set_data_to_first_match():
                        # not found
                        if self.selection_only:
                                self.display_as_valid(valid = False)
                                return False

                return True

        #--------------------------------------------------------
        def set_from_instance(self, instance):
                raise NotImplementedError('[%s]: set_from_instance()' % self.__class__.__name__)
        #--------------------------------------------------------
        def set_from_pk(self, pk):
                raise NotImplementedError('[%s]: set_from_pk()' % self.__class__.__name__)
        #--------------------------------------------------------
        def display_as_valid(self, valid:bool=True):
                """Color input field based on content validity.

                        valid: whether the content ist valid (True) or invalid (False), False = partially invalid
                """
                assert valid in [True, False, None], '<valid> must be True or False or None'
                if valid is True:
                        color2show = self.__my_startup_color
                elif valid is False:
                        color2show = color_prw_invalid
                else:
                        color2show = color_prw_partially_invalid
                if self.IsEnabled():
                        self.SetBackgroundColour(color2show)
                        self.Refresh()
                        return

                self.__previous_enabled_bg_color = color2show

        #--------------------------------------------------------
        def Disable(self):
                self.Enable(enable = False)
        #--------------------------------------------------------
        def Enable(self, enable=True):
                if self.IsEnabled() is enable:
                        return

                if self.IsEnabled():
                        self.__previous_enabled_bg_color = self.GetBackgroundColour()

                super(cPhraseWheelBase, self).Enable(enable)

                if enable is True:
                        #self.SetBackgroundColour(color_prw_valid)
                        self.SetBackgroundColour(self.__previous_enabled_bg_color)
                elif enable is False:
                        self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND))
                else:
                        raise ValueError('<enable> must be True or False')

                self.Refresh()

        #--------------------------------------------------------
        # callback API
        #--------------------------------------------------------
        def add_callback_on_selection(self, callback=None):
                """Add a callback for invocation when a picklist item is selected.

                The callback will be invoked whenever an item is selected
                from the picklist. The associated data is passed in as
                a single parameter. Callbacks must be able to cope with
                None as the data parameter as that is sent whenever the
                user changes a previously selected value.
                """
                if not callable(callback):
                        raise ValueError('[add_callback_on_selection]: ignoring callback [%s], it is not callable' % callback)

                self._on_selection_callbacks.append(callback)

        #---------------------------------------------------------
        def add_callback_on_set_focus(self, callback=None):
                """Add a callback for invocation when getting focus."""
                if not callable(callback):
                        raise ValueError('[add_callback_on_set_focus]: ignoring callback [%s] - not callable' % callback)

                self._on_set_focus_callbacks.append(callback)

        #---------------------------------------------------------
        def add_callback_on_lose_focus(self, callback=None):
                """Add a callback for invocation when losing focus."""
                if not callable(callback):
                        raise ValueError('[add_callback_on_lose_focus]: ignoring callback [%s] - not callable' % callback)

                self._on_lose_focus_callbacks.append(callback)
        #---------------------------------------------------------
        def add_callback_on_modified(self, callback=None):
                """Add a callback for invocation when the content is modified.

                This callback will NOT be passed any values.
                """
                if not callable(callback):
                        raise ValueError('[add_callback_on_modified]: ignoring callback [%s] - not callable' % callback)

                self._on_modified_callbacks.append(callback)
        #--------------------------------------------------------
        # match provider proxies
        #--------------------------------------------------------
        def set_context(self, context=None, val=None):
                if self.matcher is not None:
                        self.matcher.set_context(context=context, val=val)
        #---------------------------------------------------------
        def unset_context(self, context=None):
                if self.matcher is not None:
                        self.matcher.unset_context(context=context)
        #--------------------------------------------------------
        # internal API
        #--------------------------------------------------------
        # picklist handling
        #--------------------------------------------------------
        def __init_dropdown(self, parent = None):
                szr_dropdown = None
                try:
                        #raise NotImplementedError              # uncomment for testing
                        self.__dropdown_needs_relative_position = False
                        self._picklist_dropdown = wx.PopupWindow(parent)
                        list_parent = self._picklist_dropdown
                        self.__use_fake_popup = False
                except NotImplementedError:
                        self.__use_fake_popup = True
                        # on MacOSX wx.PopupWindow is not implemented, so emulate it
                        szr_dropdown = wx.BoxSizer(wx.VERTICAL)
                        # using wx.MiniFrame
                        self.__dropdown_needs_relative_position = False
                        self._picklist_dropdown = wx.MiniFrame (
                                parent = parent,
                                id = -1,
                                style = wx.SIMPLE_BORDER | wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR | wx.POPUP_WINDOW
                        )
                        scroll_win = wx.ScrolledWindow(parent = self._picklist_dropdown, style = wx.NO_BORDER)
                        scroll_win.SetSizer(szr_dropdown)
                        list_parent = scroll_win
                        # using wx.Window
                        #self.__dropdown_needs_relative_position = True
                        #self._picklist_dropdown = wx.ScrolledWindow(parent=parent, style = wx.RAISED_BORDER)
                        #self._picklist_dropdown.SetSizer(szr_dropdown)
                        #list_parent = self._picklist_dropdown

                self.__mac_log('dropdown parent: %s' % self._picklist_dropdown.GetParent())

                self._picklist = cPhraseWheelListCtrl (
                        list_parent,
                        style = wx.LC_NO_HEADER
                )
                self._picklist.InsertColumn(0, '')

                if szr_dropdown is not None:
                        szr_dropdown.Add(self._picklist, 1, wx.EXPAND)

                self._picklist_dropdown.Hide()

        #--------------------------------------------------------
        def _show_picklist(self, input2match):
                """Display the pick list if useful."""

                self._picklist_dropdown.Hide()

                if not self._has_focus:
                        return

                if len(self._current_match_candidates) == 0:
                        return

                # if only one match and text == match: do not show
                # picklist but rather pick that match
                if len(self._current_match_candidates) == 1:
                        candidate = self._current_match_candidates[0]
                        if candidate['field_label'] == input2match:
                                self._update_data_from_picked_item(candidate)
                                return

                # recalculate size
                dropdown_size = self._picklist_dropdown.GetSize()
                border_width = 4
                extra_height = 25
                # height
                rows = len(self._current_match_candidates)
                if rows < 2:                            # 2 rows minimum
                        rows = 2
                if rows > 20:                           # 20 rows maximum
                        rows = 20
                self.__mac_log('dropdown needs rows: %s' % rows)
                pw_size = self.GetSize()
                dropdown_size.SetHeight (
                        (pw_size.height * rows)
                        + border_width
                        + extra_height
                )
                # width
                dropdown_size.SetWidth(min (
                        self.Size.width * 2,
                        self.Parent.Size.width
                ))

                # recalculate position
                (pw_x_abs, pw_y_abs) = self.ClientToScreen(0,0)
                self.__mac_log('phrasewheel position (on screen): x:%s-%s, y:%s-%s' % (pw_x_abs, (pw_x_abs+pw_size.width), pw_y_abs, (pw_y_abs+pw_size.height)))
                dropdown_new_x = pw_x_abs
                dropdown_new_y = pw_y_abs + pw_size.height
                self.__mac_log('desired dropdown position (on screen): x:%s-%s, y:%s-%s' % (dropdown_new_x, (dropdown_new_x+dropdown_size.width), dropdown_new_y, (dropdown_new_y+dropdown_size.height)))
                self.__mac_log('desired dropdown size: %s' % dropdown_size)

                # reaches beyond screen ?
                if (dropdown_new_y + dropdown_size.height) > self._screenheight:
                        self.__mac_log('dropdown extends offscreen (screen max y: %s)' % self._screenheight)
                        max_height = self._screenheight - dropdown_new_y - 4
                        self.__mac_log('max dropdown height would be: %s' % max_height)
                        if max_height > ((pw_size.height * 2) + 4):
                                dropdown_size.SetHeight(max_height)
                                self.__mac_log('possible dropdown position (on screen): x:%s-%s, y:%s-%s' % (dropdown_new_x, (dropdown_new_x+dropdown_size.width), dropdown_new_y, (dropdown_new_y+dropdown_size.height)))
                                self.__mac_log('possible dropdown size: %s' % dropdown_size)

                # now set dimensions
                self._picklist_dropdown.SetSize(dropdown_size)
                self._picklist.SetSize(self._picklist_dropdown.GetClientSize())
                self.__mac_log('pick list size set to: %s' % self._picklist_dropdown.GetSize())
                if self.__dropdown_needs_relative_position:
                        dropdown_new_x, dropdown_new_y = self._picklist_dropdown.GetParent().ScreenToClientXY(dropdown_new_x, dropdown_new_y)
                self._picklist_dropdown.Move(dropdown_new_x, dropdown_new_y)

                # select first value
                self._picklist.Select(0)

                # and show it
                self._picklist_dropdown.Show(True)

#               dropdown_top_left = self._picklist_dropdown.ClientToScreen(0,0)
#               dropdown_size = self._picklist_dropdown.GetSize()
#               dropdown_bottom_right = self._picklist_dropdown.ClientToScreen(dropdown_size.width, dropdown_size.height)
#               self.__mac_log('dropdown placement now (on screen): x:%s-%s, y:%s-%s' % (
#                       dropdown_top_left[0],
#                       dropdown_bottom_right[0],
#                       dropdown_top_left[1],
#                       dropdown_bottom_right[1])
#               )

        #--------------------------------------------------------
        def _hide_picklist(self):
                """Hide the pick list."""
                self._picklist_dropdown.Hide()

        #--------------------------------------------------------
        def _select_picklist_row(self, new_row_idx=None, old_row_idx=None):
                """Mark the given picklist row as selected."""
                if old_row_idx is not None:
                        pass                    # FIXME: do we need unselect here ? Select() should do it for us
                self._picklist.Select(new_row_idx)
                self._picklist.EnsureVisible(new_row_idx)
        #--------------------------------------------------------
        def _picklist_item2display_string(self, item=None):
                """Get string to display in the field for the given picklist item."""
                if item is None:
                        item = self._picklist.get_selected_item()
                try:
                        return item['field_label']
                except KeyError:
                        pass
                try:
                        return item['list_label']
                except KeyError:
                        pass
                try:
                        return item['label']
                except KeyError:
                        return '<no field_*/list_*/label in item>'
                        #return self._picklist.GetItemText(self._picklist.GetFirstSelected())

        #--------------------------------------------------------
        def _update_display_from_picked_item(self, item):
                """Update the display to show item strings."""
                # default to single phrase
                display_string = self._picklist_item2display_string(item = item)
                self.suppress_text_update_smarts = True
                super(cPhraseWheelBase, self).SetValue(display_string)
                # in single-phrase phrasewheels always set cursor to end of string
                self.SetInsertionPoint(self.GetLastPosition())
                return

        #--------------------------------------------------------
        # match generation
        #--------------------------------------------------------
        def _extract_fragment_to_match_on(self):
                raise NotImplementedError('[%s]: fragment extraction not implemented' % self.__class__.__name__)
        #---------------------------------------------------------
        def _update_candidates_in_picklist(self, val):
                """Get candidates matching the currently typed input."""

                # get all currently matching items
                self._current_match_candidates = []
                if self.matcher is not None:
                        matched, self._current_match_candidates = self.matcher.getMatches(val)
                        self._picklist.SetItems(self._current_match_candidates)

        #--------------------------------------------------------
        # tooltip handling
        #--------------------------------------------------------
        def _get_data_tooltip(self):
                # child classes can override this to provide
                # per data item dynamic tooltips,
                # by default do not support dynamic tooltip parts:
                return None

        #--------------------------------------------------------
        def __recalculate_tooltip(self):
                """Calculate dynamic tooltip part based on data item.

                - called via ._set_data() each time property .data (-> .__data) is set
                - hence also called the first time data is set
                - the static tooltip can be set any number of ways before that
                - only when data is first set does the dynamic part become relevant
                - hence it is sufficient to remember the static part when .data is
                  set for the first time
                """
                if self.__static_tt is None:
                        if self.ToolTip is None:
                                self.__static_tt = ''
                        else:
                                self.__static_tt = self.ToolTip.Tip

                # need to always calculate static part because
                # the dynamic part can have *become* None, again,
                # in which case we want to be able to re-set the
                # tooltip to the static part
                static_part = self.__static_tt
                if (self.__static_tt_extra) is not None and (self.__static_tt_extra.strip() != ''):
                        static_part = '%s\n\n%s' % (
                                static_part,
                                self.__static_tt_extra
                        )

                dynamic_part = self._get_data_tooltip()
                if dynamic_part is None:
                        self.SetToolTip(static_part)
                        return

                if static_part == '':
                        tt = dynamic_part
                else:
                        if dynamic_part.strip() == '':
                                tt = static_part
                        else:
                                tt = '%s\n\n%s\n\n%s' % (
                                        dynamic_part,
                                        gmTools.u_box_horiz_single * 32,
                                        static_part
                                )

                self.SetToolTip(tt)

        #--------------------------------------------------------
        def _get_static_tt_extra(self):
                return self.__static_tt_extra

        def _set_static_tt_extra(self, tt):
                self.__static_tt_extra = tt

        static_tooltip_extra = property(_get_static_tt_extra, _set_static_tt_extra)

        #--------------------------------------------------------
        # event handling
        #--------------------------------------------------------
        def __register_events(self):
                self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
                self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
                self.Bind(wx.EVT_KILL_FOCUS, self._on_lose_focus)
                self.Bind(wx.EVT_TEXT, self._on_text_update)
                self._picklist.Bind(wx.EVT_LEFT_DCLICK, self._on_list_item_selected)

        #--------------------------------------------------------
        def _on_key_down(self, event):
                """Is called when a key is pressed."""

                keycode = event.GetKeyCode()

                if keycode == wx.WXK_DOWN:
                        self.__on_cursor_down()
                        return

                if keycode == wx.WXK_UP:
                        self.__on_cursor_up()
                        return

                if keycode == wx.WXK_RETURN:
                        self._on_enter()
                        return

                if keycode == wx.WXK_TAB:
                        if event.ShiftDown():
                                self.Navigate(flags = wx.NavigationKeyEvent.IsBackward)
                                return
                        self.__on_tab()
                        self.Navigate(flags = wx.NavigationKeyEvent.IsForward)
                        return

                # FIXME: need PAGE UP/DOWN//POS1/END here to move in picklist
                if keycode in [wx.WXK_SHIFT, wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_LEFT, wx.WXK_RIGHT]:
                        pass

                # need to handle all non-character key presses *before* this check
                elif not self.__char_is_allowed(char = chr(event.GetUnicodeKey())):
                        wx.Bell()
                        # Richard doesn't show any error message here
                        return

                event.Skip()
                return
        #--------------------------------------------------------
        def _on_set_focus(self, event):

                self._has_focus = True
                event.Skip()

                self.__background_color_without_focus = self.GetBackgroundColour()
                self.SetBackgroundColour(COLOR_BG_PRW_WITH_FOCUS)
                self.Refresh()

                # notify interested parties
                for callback in self._on_set_focus_callbacks:
                        callback()

                self.__timer.Start(oneShot = True, milliseconds = self.picklist_delay)
                return True
        #--------------------------------------------------------
        def _on_lose_focus(self, event):
                """Do stuff when leaving the control.

                The user has had her say, so don't second guess
                intentions but do report error conditions.
                """
                event.Skip()
                self._has_focus = False
                self.__timer.Stop()
                self._hide_picklist()
                self.SetBackgroundColour(self.__background_color_without_focus)
                self.Refresh()
                wx.CallAfter(self.__on_lost_focus)
                return True

        #--------------------------------------------------------
        def __on_lost_focus(self):
                if not self:
                        return

                self.SetSelection(1,1)
                is_valid = True
                # the user may have typed a phrase that is an exact match,
                # however, just typing it won't associate data from the
                # picklist, so try do that now
                self._set_data_to_first_match()

                # check value against final_regex if any given
                if self.__final_regex.match(self.GetValue().strip()) is None:
                        gmDispatcher.send(signal = 'statustext', msg = self.final_regex_error_msg % self.final_regex)
                        is_valid = False

                self.display_as_valid(valid = is_valid)

                # notify interested parties
                for callback in self._on_lose_focus_callbacks:
                        callback()
        #--------------------------------------------------------
        def _on_list_item_selected(self, *args, **kwargs):
                """Gets called when user selected a list item."""

                self._hide_picklist()

                item = self._picklist.get_selected_item()
                # huh ?
                if item is None:
                        self.display_as_valid(valid = True)
                        return

                self._update_display_from_picked_item(item)
                self._update_data_from_picked_item(item)
                self.MarkDirty()

                # and tell the listeners about the user's selection
                for callback in self._on_selection_callbacks:
                        callback(self._data)

                if self.navigate_after_selection:
                        self.Navigate()

                return
        #--------------------------------------------------------
        def _on_text_update (self, event):
                """Internal handler for wx.EVT_TEXT.

                Called when text was changed by user or by SetValue().
                """
                if self.suppress_text_update_smarts:
                        self.suppress_text_update_smarts = False
                        return

                self._adjust_data_after_text_update()
                self._current_match_candidates = []

                val = self.GetValue().strip()
                ins_point = self.GetInsertionPoint()

                # if empty string then hide list dropdown window
                # we also don't need a timer event then
                if val == '':
                        self._hide_picklist()
                        self.__timer.Stop()
                else:
                        new_val = gmTools.capitalize(text = val, mode = self.capitalisation_mode)
                        if new_val != val:
                                self.suppress_text_update_smarts = True
                                super(cPhraseWheelBase, self).SetValue(new_val)
                                if ins_point > len(new_val):
                                        self.SetInsertionPointEnd()
                                else:
                                        self.SetInsertionPoint(ins_point)
                                        # FIXME: SetSelection() ?

                        # start timer for delayed match retrieval
                        self.__timer.Start(oneShot = True, milliseconds = self.picklist_delay)

                # notify interested parties
                for callback in self._on_modified_callbacks:
                        callback()

                return
        #--------------------------------------------------------
        # keypress handling
        #--------------------------------------------------------
        def _on_enter(self):
                """Called when the user pressed <ENTER>."""
                if self._picklist_dropdown.IsShown():
                        self._on_list_item_selected()
                        return

                # FIXME: check for errors before navigation
                self.Navigate()

        #--------------------------------------------------------
        def __on_cursor_down(self):

                if self._picklist_dropdown.IsShown():
                        idx_selected = self._picklist.GetFirstSelected()
                        if idx_selected < (len(self._current_match_candidates) - 1):
                                self._select_picklist_row(idx_selected + 1, idx_selected)
                        return

                # if we don't yet have a pick list: open new pick list
                # (this can happen when we TAB into a field pre-filled
                # with the top-weighted contextual item but want to
                # select another contextual item)
                self.__timer.Stop()
                if self.GetValue().strip() == '':
                        val = '*'
                else:
                        val = self._extract_fragment_to_match_on()
                self._update_candidates_in_picklist(val = val)
                self._show_picklist(input2match = val)

        #--------------------------------------------------------
        def __on_cursor_up(self):
                if self._picklist_dropdown.IsShown():
                        selected = self._picklist.GetFirstSelected()
                        if selected > 0:
                                self._select_picklist_row(selected-1, selected)
                #else:
                #       # FIXME: input history ?

        #--------------------------------------------------------
        def __on_tab(self):
                """Under certain circumstances take special action on <TAB>.

                returns:
                        True: <TAB> was handled
                        False: <TAB> was not handled

                -> can be used to decide whether to do further <TAB> handling outside this class
                """
                # are we seeing the picklist ?
                if not self._picklist_dropdown.IsShown():
                        return False

                # with only one candidate ?
                if len(self._current_match_candidates) != 1:
                        return False

                # and do we require the input to be picked from the candidates ?
                if not self.selection_only:
                        return False

                # then auto-select that item
                self._select_picklist_row(new_row_idx = 0)
                self._on_list_item_selected()

                return True
        #--------------------------------------------------------
        # timer handling
        #--------------------------------------------------------
        def __init_timer(self):
                self.__timer = _cPRWTimer()
                self.__timer.callback = self._on_timer_fired
                # initially stopped
                self.__timer.Stop()
        #--------------------------------------------------------
        def _on_timer_fired(self):
                """Callback for delayed match retrieval timer.

                if we end up here:
                 - delay has passed without user input
                 - the value in the input field has not changed since the timer started
                """
                # update matches according to current input
                val = self._extract_fragment_to_match_on()
                self._update_candidates_in_picklist(val = val)

                # we now have either:
                # - all possible items (within reasonable limits) if input was '*'
                # - all matching items
                # - an empty match list if no matches were found
                # also, our picklist is refilled and sorted according to weight
                wx.CallAfter(self._show_picklist, input2match = val)
        #----------------------------------------------------
        # random helpers and properties
        #----------------------------------------------------
        def __mac_log(self, msg):
                if self.__use_fake_popup:
                        _log.debug(msg)

        #--------------------------------------------------------
        def __char_is_allowed(self, char=None):
                # if undefined accept all chars
                if self.accepted_chars is None:
                        return True
                return (self.__accepted_chars.match(char) is not None)

        #--------------------------------------------------------
        def _set_accepted_chars(self, accepted_chars=None):
                if accepted_chars is None:
                        self.__accepted_chars = None
                else:
                        self.__accepted_chars = regex.compile(accepted_chars)

        def _get_accepted_chars(self):
                if self.__accepted_chars is None:
                        return None
                return self.__accepted_chars.pattern

        accepted_chars = property(_get_accepted_chars, _set_accepted_chars)

        #--------------------------------------------------------
        def _set_final_regex(self, final_regex=r'.*'):
                self.__final_regex = regex.compile(final_regex, flags = regex.UNICODE)

        def _get_final_regex(self):
                return self.__final_regex.pattern

        final_regex = property(_get_final_regex, _set_final_regex)

        #--------------------------------------------------------
        def _set_final_regex_error_msg(self, msg):
                self.__final_regex_error_msg = msg

        def _get_final_regex_error_msg(self):
                return self.__final_regex_error_msg

        final_regex_error_msg = property(_get_final_regex_error_msg, _set_final_regex_error_msg)

        #--------------------------------------------------------
        # data munging
        #--------------------------------------------------------
        def _set_data_to_first_match(self):
                return False

        #--------------------------------------------------------
        def _update_data_from_picked_item(self, item):
                self._data = self._dictify_data(data = item)

        #---------------------------------------------------------
        def _dictify_data(self, data=None, value=None) -> dict:
                if isinstance(data, dict):
                        # test for dict being well-formed
                        data['data']
                        data['list_label']
                        data['field_label']
                        return data

                if not value:
                        value = '%s' % data
                return {'data': data, 'list_label': value, 'field_label': value}

#       #--------------------------------------------------------
#       def _dictify_data(self, data=None, value=None):
#               raise NotImplementedError('[%s]: _dictify_data()' % self.__class__.__name__)
        #---------------------------------------------------------
        def _adjust_data_after_text_update(self):
                raise NotImplementedError('[%s]: cannot adjust data after text update' % self.__class__.__name__)
        #--------------------------------------------------------
        def _data2match(self, data):
                if self.matcher is None:
                        return None
                return self.matcher.get_match_by_data(data = data)

        #--------------------------------------------------------
        def _create_data(self, link_obj=None):
                """Must set self._data if possible/successful."""
                raise NotImplementedError('[%s]: cannot create data object' % self.__class__.__name__)

        #--------------------------------------------------------
        def _data2instance(self, link_obj=None):
                """Turn selected data into class instance.

                Returns:
                        A class instance, typically a subclass of gmBusinessDBObject.cBusinessDBObject, or None.
                """
                raise NotImplementedError('[%s]: cannot turn data object' % self.__class__.__name__)

        #--------------------------------------------------------
        def _get_raw_data(self):
                return self._data

        def _set_raw_data(self, raw_data:dict):
                """Explicitly set raw data of phrasewheel.

                Args:
                        raw_data: a dict with the keys 'data' (the actual value), 'list_label' (shown in the picklist when selecting an item), and 'field_label' (shown in the phrasewheel after this idem had been selected)
                """
                self._data = raw_data
                self.__recalculate_tooltip()

        raw_data = property(_get_raw_data, _set_raw_data)

Widget for smart guessing of user fields, after Richard Terry's interface.

  • VB implementation by Richard Terry
  • Python port by Ian Haywood for GNUmed
  • enhanced by Karsten Hilbert for GNUmed
  • enhanced by Ian Haywood for aumed
  • enhanced by Karsten Hilbert for GNUmed

@param matcher: a class used to find matches for the current input @type matcher: a L{match provider} instance or C{None}

@param selection_only: whether free-text can be entered without associated data @type selection_only: boolean

@param capitalisation_mode: how to auto-capitalize input, valid values are found in L{capitalize()} @type capitalisation_mode: integer

@param accepted_chars: a regex pattern defining the characters acceptable in the input string, if None no checking is performed @type accepted_chars: None or a string holding a valid regex pattern

@param final_regex: when the control loses focus the input is checked against this regular expression @type final_regex: a string holding a valid regex pattern

@param navigate_after_selection: whether or not to immediately navigate to the widget next-in-tab-order after selecting an item from the dropdown picklist @type navigate_after_selection: boolean

@param picklist_delay: this much time of user inactivity must have passed before the input related smarts kick in and the drop down pick list is shown @type picklist_delay: integer (milliseconds)

Ancestors

  • wx._core.TextCtrl
  • wx._core.Control
  • wx._core.Window
  • wx._core.WindowBase
  • wx._core.EvtHandler
  • wx._core.Object
  • wx._core.Trackable
  • wx._core.TextEntry
  • sip.wrapper
  • sip.simplewrapper

Subclasses

Instance variables

prop accepted_chars
Expand source code
def _get_accepted_chars(self):
        if self.__accepted_chars is None:
                return None
        return self.__accepted_chars.pattern
prop final_regex
Expand source code
def _get_final_regex(self):
        return self.__final_regex.pattern
prop final_regex_error_msg
Expand source code
def _get_final_regex_error_msg(self):
        return self.__final_regex_error_msg
prop raw_data
Expand source code
def _get_raw_data(self):
        return self._data
prop static_tooltip_extra
Expand source code
def _get_static_tt_extra(self):
        return self.__static_tt_extra

Methods

def Disable(self)
Expand source code
def Disable(self):
        self.Enable(enable = False)

Disable() -> bool

Disables the window.

def Enable(self, enable=True)
Expand source code
def Enable(self, enable=True):
        if self.IsEnabled() is enable:
                return

        if self.IsEnabled():
                self.__previous_enabled_bg_color = self.GetBackgroundColour()

        super(cPhraseWheelBase, self).Enable(enable)

        if enable is True:
                #self.SetBackgroundColour(color_prw_valid)
                self.SetBackgroundColour(self.__previous_enabled_bg_color)
        elif enable is False:
                self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND))
        else:
                raise ValueError('<enable> must be True or False')

        self.Refresh()

Enable(enable=True) -> bool

Enable or disable the window for user input.

def GetData(self, can_create: bool = False, as_instance: bool = False, link_obj=None)
Expand source code
def GetData(self, can_create:bool=False, as_instance:bool=False, link_obj=None):
        """Retrieve the data associated with the displayed string(s).

        Returns:
                None, if no data available, and unable to create data.

                Or a data instance, if requested and data is available or create-able.

                Or the data itself.
        """
        if not self._data:
                if can_create:
                        self._create_data(link_obj = link_obj)

        if not self._data:
                return None

        if as_instance:
                return self._data2instance(link_obj = link_obj)

        return self._data['data']

Retrieve the data associated with the displayed string(s).

Returns

None, if no data available, and unable to create data.

Or a data instance, if requested and data is available or create-able.

Or the data itself.

def SetText(self, value: str = '', data=None, suppress_smarts: bool = False)
Expand source code
def SetText(self, value:str='', data=None, suppress_smarts:bool=False):
        """Set both value and data of phrasewheel.

        Args:
                value: some text to display in the control
                data: the data value represented by the displayed text
                suppress_smarts: whether to generate data based on value, always True if data is passed in
        """
        if value is None:
                value = ''

        if (value == '') and (data is None):
                self._data = {}
                super(cPhraseWheelBase, self).SetValue(value)
                return

        self.suppress_text_update_smarts = suppress_smarts

        if data:
                self.suppress_text_update_smarts = True
                self._data = self._dictify_data(data = data, value = value)
        super(cPhraseWheelBase, self).SetValue(value)
        self.display_as_valid(valid = True)

        # if data already available
        if len(self._data) > 0:
                return True

        # empty text value ?
        if value == '':
                # valid value not required ?
                if not self.selection_only:
                        return True

        if not self._set_data_to_first_match():
                # not found
                if self.selection_only:
                        self.display_as_valid(valid = False)
                        return False

        return True

Set both value and data of phrasewheel.

Args

value
some text to display in the control
data
the data value represented by the displayed text
suppress_smarts
whether to generate data based on value, always True if data is passed in
def add_callback_on_lose_focus(self, callback=None)
Expand source code
def add_callback_on_lose_focus(self, callback=None):
        """Add a callback for invocation when losing focus."""
        if not callable(callback):
                raise ValueError('[add_callback_on_lose_focus]: ignoring callback [%s] - not callable' % callback)

        self._on_lose_focus_callbacks.append(callback)

Add a callback for invocation when losing focus.

def add_callback_on_modified(self, callback=None)
Expand source code
def add_callback_on_modified(self, callback=None):
        """Add a callback for invocation when the content is modified.

        This callback will NOT be passed any values.
        """
        if not callable(callback):
                raise ValueError('[add_callback_on_modified]: ignoring callback [%s] - not callable' % callback)

        self._on_modified_callbacks.append(callback)

Add a callback for invocation when the content is modified.

This callback will NOT be passed any values.

def add_callback_on_selection(self, callback=None)
Expand source code
def add_callback_on_selection(self, callback=None):
        """Add a callback for invocation when a picklist item is selected.

        The callback will be invoked whenever an item is selected
        from the picklist. The associated data is passed in as
        a single parameter. Callbacks must be able to cope with
        None as the data parameter as that is sent whenever the
        user changes a previously selected value.
        """
        if not callable(callback):
                raise ValueError('[add_callback_on_selection]: ignoring callback [%s], it is not callable' % callback)

        self._on_selection_callbacks.append(callback)

Add a callback for invocation when a picklist item is selected.

The callback will be invoked whenever an item is selected from the picklist. The associated data is passed in as a single parameter. Callbacks must be able to cope with None as the data parameter as that is sent whenever the user changes a previously selected value.

def add_callback_on_set_focus(self, callback=None)
Expand source code
def add_callback_on_set_focus(self, callback=None):
        """Add a callback for invocation when getting focus."""
        if not callable(callback):
                raise ValueError('[add_callback_on_set_focus]: ignoring callback [%s] - not callable' % callback)

        self._on_set_focus_callbacks.append(callback)

Add a callback for invocation when getting focus.

def display_as_valid(self, valid: bool = True)
Expand source code
def display_as_valid(self, valid:bool=True):
        """Color input field based on content validity.

                valid: whether the content ist valid (True) or invalid (False), False = partially invalid
        """
        assert valid in [True, False, None], '<valid> must be True or False or None'
        if valid is True:
                color2show = self.__my_startup_color
        elif valid is False:
                color2show = color_prw_invalid
        else:
                color2show = color_prw_partially_invalid
        if self.IsEnabled():
                self.SetBackgroundColour(color2show)
                self.Refresh()
                return

        self.__previous_enabled_bg_color = color2show

Color input field based on content validity.

valid: whether the content ist valid (True) or invalid (False), False = partially invalid

def set_context(self, context=None, val=None)
Expand source code
def set_context(self, context=None, val=None):
        if self.matcher is not None:
                self.matcher.set_context(context=context, val=val)
def set_from_instance(self, instance)
Expand source code
def set_from_instance(self, instance):
        raise NotImplementedError('[%s]: set_from_instance()' % self.__class__.__name__)
def set_from_pk(self, pk)
Expand source code
def set_from_pk(self, pk):
        raise NotImplementedError('[%s]: set_from_pk()' % self.__class__.__name__)
def unset_context(self, context=None)
Expand source code
def unset_context(self, context=None):
        if self.matcher is not None:
                self.matcher.unset_context(context=context)
class cPhraseWheelListCtrl (*args, **kwargs)
Expand source code
class cPhraseWheelListCtrl(wx.ListCtrl, listmixins.ListCtrlAutoWidthMixin):

        def __init__(self, *args, **kwargs):
                try:
                        kwargs['style'] = kwargs['style'] | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.SIMPLE_BORDER
                except KeyError:
                        pass
                wx.ListCtrl.__init__(self, *args, **kwargs)
                listmixins.ListCtrlAutoWidthMixin.__init__(self)
        #--------------------------------------------------------
        def SetItems(self, items):
                self.DeleteAllItems()
                self.__data = items
                pos = len(items) + 1
                for item in items:
                        #self.InsertItem(pos, label = item['list_label'])
                        self.InsertItem(pos, item['list_label'])
        #--------------------------------------------------------
        def GetSelectedItemData(self):
                sel_idx = self.GetFirstSelected()
                if sel_idx == -1:
                        return None
                return self.__data[sel_idx]['data']
        #--------------------------------------------------------
        def get_selected_item(self):
                sel_idx = self.GetFirstSelected()
                if sel_idx == -1:
                        return None
                return self.__data[sel_idx]
        #--------------------------------------------------------
        def get_selected_item_label(self):
                sel_idx = self.GetFirstSelected()
                if sel_idx == -1:
                        return None
                return self.__data[sel_idx]['list_label']

ListCtrl() ListCtrl(parent, id=ID_ANY, pos=DefaultPosition, size=DefaultSize, style=LC_ICON, validator=DefaultValidator, name=ListCtrlNameStr)

A list control presents lists in a number of formats: list view, report view, icon view and small icon view.

Ancestors

  • wx._core.ListCtrl
  • wx._core.Control
  • wx._core.Window
  • wx._core.WindowBase
  • wx._core.EvtHandler
  • wx._core.Object
  • wx._core.Trackable
  • sip.wrapper
  • sip.simplewrapper
  • wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin

Methods

def GetSelectedItemData(self)
Expand source code
def GetSelectedItemData(self):
        sel_idx = self.GetFirstSelected()
        if sel_idx == -1:
                return None
        return self.__data[sel_idx]['data']
def SetItems(self, items)
Expand source code
def SetItems(self, items):
        self.DeleteAllItems()
        self.__data = items
        pos = len(items) + 1
        for item in items:
                #self.InsertItem(pos, label = item['list_label'])
                self.InsertItem(pos, item['list_label'])
def get_selected_item(self)
Expand source code
def get_selected_item(self):
        sel_idx = self.GetFirstSelected()
        if sel_idx == -1:
                return None
        return self.__data[sel_idx]
def get_selected_item_label(self)
Expand source code
def get_selected_item_label(self):
        sel_idx = self.GetFirstSelected()
        if sel_idx == -1:
                return None
        return self.__data[sel_idx]['list_label']