controls/TextCtrlAutoComplete.py
changeset 1784 64beb9e9c749
parent 1782 5b6ad7a7fd9d
child 1832 0f1081928d65
equal deleted inserted replaced
1729:31e63e25b4cc 1784:64beb9e9c749
    32     LISTBOX_INTERVAL_HEIGHT = 0
    32     LISTBOX_INTERVAL_HEIGHT = 0
    33 else:
    33 else:
    34     LISTBOX_BORDER_HEIGHT = 4
    34     LISTBOX_BORDER_HEIGHT = 4
    35     LISTBOX_INTERVAL_HEIGHT = 6
    35     LISTBOX_INTERVAL_HEIGHT = 6
    36 
    36 
       
    37 
    37 class PopupWithListbox(wx.PopupWindow):
    38 class PopupWithListbox(wx.PopupWindow):
    38     
    39 
    39     def __init__(self, parent, choices=[]):
    40     def __init__(self, parent, choices=[]):
    40         wx.PopupWindow.__init__(self, parent, wx.BORDER_SIMPLE)
    41         wx.PopupWindow.__init__(self, parent, wx.BORDER_SIMPLE)
    41         
    42 
    42         self.ListBox = wx.ListBox(self, -1, style=wx.LB_HSCROLL|wx.LB_SINGLE|wx.LB_SORT)
    43         self.ListBox = wx.ListBox(self, -1, style=wx.LB_HSCROLL | wx.LB_SINGLE | wx.LB_SORT)
    43         
    44 
    44         self.SetChoices(choices)
    45         self.SetChoices(choices)
    45         
    46 
    46         self.ListBox.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
    47         self.ListBox.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
    47         self.ListBox.Bind(wx.EVT_MOTION, self.OnMotion)
    48         self.ListBox.Bind(wx.EVT_MOTION, self.OnMotion)
    48     
    49 
    49     def SetChoices(self, choices):
    50     def SetChoices(self, choices):
    50         max_text_width = 0
    51         max_text_width = 0
    51         max_text_height = 0
    52         max_text_height = 0
    52         
    53 
    53         self.ListBox.Clear()
    54         self.ListBox.Clear()
    54         for choice in choices:
    55         for choice in choices:
    55             self.ListBox.Append(choice)
    56             self.ListBox.Append(choice)
    56             w, h = self.ListBox.GetTextExtent(choice)
    57             w, h = self.ListBox.GetTextExtent(choice)
    57             max_text_width = max(max_text_width, w)
    58             max_text_width = max(max_text_width, w)
    58             max_text_height = max(max_text_height, h)
    59             max_text_height = max(max_text_height, h)
    59         
    60 
    60         itemcount = min(len(choices), MAX_ITEM_SHOWN)
    61         itemcount = min(len(choices), MAX_ITEM_SHOWN)
    61         width = self.Parent.GetSize()[0]
    62         width = self.Parent.GetSize()[0]
    62         height = max_text_height * itemcount + \
    63         height = \
    63                  LISTBOX_INTERVAL_HEIGHT * max(0, itemcount - 1) + \
    64             max_text_height * itemcount + \
    64                  2 * LISTBOX_BORDER_HEIGHT
    65             LISTBOX_INTERVAL_HEIGHT * max(0, itemcount - 1) + \
       
    66             2 * LISTBOX_BORDER_HEIGHT
    65         if max_text_width + 10 > width:
    67         if max_text_width + 10 > width:
    66             height += 15
    68             height += 15
    67         size = wx.Size(width, height)
    69         size = wx.Size(width, height)
    68         if wx.Platform == '__WXMSW__':
    70         if wx.Platform == '__WXMSW__':
    69             size.width -= 2
    71             size.width -= 2
    70         self.ListBox.SetSize(size)
    72         self.ListBox.SetSize(size)
    71         self.SetClientSize(size)
    73         self.SetClientSize(size)
    72     
    74 
    73     def MoveSelection(self, direction):
    75     def MoveSelection(self, direction):
    74         selected = self.ListBox.GetSelection()
    76         selected = self.ListBox.GetSelection()
    75         if selected == wx.NOT_FOUND:
    77         if selected == wx.NOT_FOUND:
    76             if direction >= 0:
    78             if direction >= 0:
    77                 selected = 0
    79                 selected = 0
    80         else:
    82         else:
    81             selected = (selected + direction) % (self.ListBox.GetCount() + 1)
    83             selected = (selected + direction) % (self.ListBox.GetCount() + 1)
    82         if selected == self.ListBox.GetCount():
    84         if selected == self.ListBox.GetCount():
    83             selected = wx.NOT_FOUND
    85             selected = wx.NOT_FOUND
    84         self.ListBox.SetSelection(selected)
    86         self.ListBox.SetSelection(selected)
    85     
    87 
    86     def GetSelection(self):
    88     def GetSelection(self):
    87         return self.ListBox.GetStringSelection()
    89         return self.ListBox.GetStringSelection()
    88     
    90 
    89     def OnLeftDown(self, event):
    91     def OnLeftDown(self, event):
    90         selected = self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY()))
    92         selected = self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY()))
    91         parent_size = self.Parent.GetSize()
    93         parent_size = self.Parent.GetSize()
    92         parent_rect = wx.Rect(0, -parent_size[1], parent_size[0], parent_size[1])
    94         parent_rect = wx.Rect(0, -parent_size[1], parent_size[0], parent_size[1])
    93         if selected != wx.NOT_FOUND:
    95         if selected != wx.NOT_FOUND:
    97             if result != wx.TE_HT_UNKNOWN:
    99             if result != wx.TE_HT_UNKNOWN:
    98                 self.Parent.SetInsertionPoint(self.Parent.XYToPosition(x, y))
   100                 self.Parent.SetInsertionPoint(self.Parent.XYToPosition(x, y))
    99         else:
   101         else:
   100             wx.CallAfter(self.Parent.DismissListBox)
   102             wx.CallAfter(self.Parent.DismissListBox)
   101         event.Skip()
   103         event.Skip()
   102     
   104 
   103     def OnMotion(self, event):
   105     def OnMotion(self, event):
   104         self.ListBox.SetSelection(
   106         self.ListBox.SetSelection(
   105             self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY())))
   107             self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY())))
   106         event.Skip()
   108         event.Skip()
   107     
   109 
       
   110 
   108 class TextCtrlAutoComplete(wx.TextCtrl):
   111 class TextCtrlAutoComplete(wx.TextCtrl):
   109 
   112 
   110     def __init__ (self, parent, choices=None, dropDownClick=True,
   113     def __init__(self, parent, choices=None, dropDownClick=True,
   111                   element_path=None, **therest):
   114                  element_path=None, **therest):
   112         """
   115         """
   113         Constructor works just like wx.TextCtrl except you can pass in a
   116         Constructor works just like wx.TextCtrl except you can pass in a
   114         list of choices.  You can also change the choice list at any time
   117         list of choices.  You can also change the choice list at any time
   115         by calling setChoices.
   118         by calling setChoices.
   116         """
   119         """
   117 
   120 
   118         therest['style'] = wx.TE_PROCESS_ENTER | therest.get('style', 0)
   121         therest['style'] = wx.TE_PROCESS_ENTER | therest.get('style', 0)
   119 
   122 
   120         wx.TextCtrl.__init__(self, parent, **therest)
   123         wx.TextCtrl.__init__(self, parent, **therest)
   121         
   124 
   122         #Some variables
   125         # Some variables
   123         self._dropDownClick = dropDownClick
   126         self._dropDownClick = dropDownClick
   124         self._lastinsertionpoint = None
   127         self._lastinsertionpoint = None
   125         self._hasfocus = False
   128         self._hasfocus = False
   126         
   129 
   127         self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
   130         self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
   128         self.element_path = element_path
   131         self.element_path = element_path
   129         
   132 
   130         self.listbox = None
   133         self.listbox = None
   131         
   134 
   132         self.SetChoices(choices)
   135         self.SetChoices(choices)
   133 
   136 
   134         #gp = self
   137         # gp = self
   135         #while ( gp != None ) :
   138         # while ( gp != None ) :
   136         #    gp.Bind ( wx.EVT_MOVE , self.onControlChanged, gp )
   139         #    gp.Bind ( wx.EVT_MOVE , self.onControlChanged, gp )
   137         #    gp.Bind ( wx.EVT_SIZE , self.onControlChanged, gp )
   140         #    gp.Bind ( wx.EVT_SIZE , self.onControlChanged, gp )
   138         #    gp = gp.GetParent()
   141         #    gp = gp.GetParent()
   139 
   142 
   140         self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
   143         self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
   141         self.Bind(wx.EVT_TEXT_ENTER, self.OnControlChanged)
   144         self.Bind(wx.EVT_TEXT_ENTER, self.OnControlChanged)
   142         self.Bind(wx.EVT_TEXT, self.OnEnteredText)
   145         self.Bind(wx.EVT_TEXT, self.OnEnteredText)
   143         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
   146         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
   144 
   147 
   145         #If need drop down on left click
   148         # If need drop down on left click
   146         if dropDownClick:
   149         if dropDownClick:
   147             self.Bind(wx.EVT_LEFT_DOWN, self.OnClickToggleDown)
   150             self.Bind(wx.EVT_LEFT_DOWN, self.OnClickToggleDown)
   148             self.Bind(wx.EVT_LEFT_UP, self.OnClickToggleUp)
   151             self.Bind(wx.EVT_LEFT_UP, self.OnClickToggleUp)
   149 
   152 
   150     def ChangeValue(self, value):
   153     def ChangeValue(self, value):
   199             config.Flush()
   202             config.Flush()
   200             self.SetChoices(listentries)
   203             self.SetChoices(listentries)
   201         self.DismissListBox()
   204         self.DismissListBox()
   202         self._hasfocus = False
   205         self._hasfocus = False
   203         event.Skip()
   206         event.Skip()
   204     
   207 
   205     def SetChoices(self, choices):
   208     def SetChoices(self, choices):
   206         self._choices = choices
   209         self._choices = choices
   207         self.RefreshListBoxChoices()
   210         self.RefreshListBoxChoices()
   208         
   211 
   209     def GetChoices(self):
   212     def GetChoices(self):
   210         return self._choices
   213         return self._choices
   211     
   214 
   212     def SetValueFromSelected(self, selected):
   215     def SetValueFromSelected(self, selected):
   213         """
   216         """
   214         Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
   217         Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
   215         Will do nothing if no item is selected in the wx.ListCtrl.
   218         Will do nothing if no item is selected in the wx.ListCtrl.
   216         """
   219         """
   217         if selected != "":
   220         if selected != "":
   218             self.SetValue(selected)
   221             self.SetValue(selected)
   219         self.DismissListBox()
   222         self.DismissListBox()
   220     
   223 
   221     def RefreshListBoxChoices(self):
   224     def RefreshListBoxChoices(self):
   222         if self.listbox is not None:
   225         if self.listbox is not None:
   223             text = self.GetValue()
   226             text = self.GetValue()
   224             choices = [choice for choice in self._choices if choice.startswith(text)]
   227             choices = [choice for choice in self._choices if choice.startswith(text)]
   225             self.listbox.SetChoices(choices)
   228             self.listbox.SetChoices(choices)
   226 
   229 
   227     def PopupListBox(self):
   230     def PopupListBox(self):
   228         if self.listbox is None:
   231         if self.listbox is None:
   229             self.listbox = PopupWithListbox(self)
   232             self.listbox = PopupWithListbox(self)
   230             
   233 
   231             # Show the popup right below or above the button
   234             # Show the popup right below or above the button
   232             # depending on available screen space...
   235             # depending on available screen space...
   233             pos = self.ClientToScreen((0, 0))
   236             pos = self.ClientToScreen((0, 0))
   234             sz = self.GetSize()
   237             sz = self.GetSize()
   235             if wx.Platform == '__WXMSW__':
   238             if wx.Platform == '__WXMSW__':
   236                 pos.x -= 2
   239                 pos.x -= 2
   237                 pos.y -= 2
   240                 pos.y -= 2
   238             self.listbox.Position(pos, (0, sz[1]))
   241             self.listbox.Position(pos, (0, sz[1]))
   239             
   242 
   240             self.RefreshListBoxChoices()
   243             self.RefreshListBoxChoices()
   241             
   244 
   242             self.listbox.Show()
   245             self.listbox.Show()
   243 
   246 
   244     def DismissListBox(self):
   247     def DismissListBox(self):
   245         if self.listbox is not None:
   248         if self.listbox is not None:
   246             if self.listbox.ListBox.HasCapture():
   249             if self.listbox.ListBox.HasCapture():