# HG changeset patch # User Laurent Bessard # Date 1369756377 -7200 # Node ID 276a30c68eaad388e3b959b11e6d5005d98ade7e # Parent 3e7bd88fcff7c8c90e460e52b0ca475e0aff894d Fixed bugs with TextCtrlAutoComplete diff -r 3e7bd88fcff7 -r 276a30c68eaa controls/TextCtrlAutoComplete.py --- a/controls/TextCtrlAutoComplete.py Tue May 28 17:52:07 2013 +0200 +++ b/controls/TextCtrlAutoComplete.py Tue May 28 17:52:57 2013 +0200 @@ -28,28 +28,23 @@ MAX_ITEM_COUNT = 10 MAX_ITEM_SHOWN = 6 if wx.Platform == '__WXMSW__': - ITEM_INTERVAL_HEIGHT = 3 + LISTBOX_BORDER_HEIGHT = 2 + LISTBOX_INTERVAL_HEIGHT = 0 else: - ITEM_INTERVAL_HEIGHT = 6 - -if wx.Platform == '__WXMSW__': - popupclass = wx.PopupTransientWindow -else: - popupclass = wx.PopupWindow - -class PopupWithListbox(popupclass): + LISTBOX_BORDER_HEIGHT = 4 + LISTBOX_INTERVAL_HEIGHT = 6 + +class PopupWithListbox(wx.PopupWindow): def __init__(self, parent, choices=[]): - popupclass.__init__(self, parent, wx.SIMPLE_BORDER) + wx.PopupWindow.__init__(self, parent, wx.BORDER_SIMPLE) self.ListBox = wx.ListBox(self, -1, style=wx.LB_HSCROLL|wx.LB_SINGLE|wx.LB_SORT) - if not wx.Platform == '__WXMSW__': - self.ListBox.Bind(wx.EVT_LISTBOX, self.OnListBoxClick) - self.ListBox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnListBoxClick) - + self.SetChoices(choices) - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) + self.ListBox.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.ListBox.Bind(wx.EVT_MOTION, self.OnMotion) def SetChoices(self, choices): max_text_width = 0 @@ -64,10 +59,14 @@ itemcount = min(len(choices), MAX_ITEM_SHOWN) width = self.Parent.GetSize()[0] - height = max_text_height * itemcount + ITEM_INTERVAL_HEIGHT * (itemcount + 1) + height = max_text_height * itemcount + \ + LISTBOX_INTERVAL_HEIGHT * max(0, itemcount - 1) + \ + 2 * LISTBOX_BORDER_HEIGHT if max_text_width + 10 > width: height += 15 size = wx.Size(width, height) + if wx.Platform == '__WXMSW__': + size.width -= 2 self.ListBox.SetSize(size) self.SetClientSize(size) @@ -87,28 +86,28 @@ def GetSelection(self): return self.ListBox.GetStringSelection() - def ProcessLeftDown(self, event): + def OnLeftDown(self, event): selected = self.ListBox.HitTest(wx.Point(event.m_x, event.m_y)) + parent_size = self.Parent.GetSize() + parent_rect = wx.Rect(0, -parent_size[1], parent_size[0], parent_size[1]) if selected != wx.NOT_FOUND: wx.CallAfter(self.Parent.SetValueFromSelected, self.ListBox.GetString(selected)) - return False - - def OnListBoxClick(self, event): - selected = event.GetSelection() - if selected != wx.NOT_FOUND: - wx.CallAfter(self.Parent.SetValueFromSelected, self.ListBox.GetString(selected)) - event.Skip() - - def OnKeyDown(self, event): - self.Parent.ProcessEvent(event) - - def OnDismiss(self): - self.Parent.listbox = None - wx.CallAfter(self.Parent.DismissListBox) + elif parent_rect.InsideXY(event.m_x, event.m_y): + result, x, y = self.Parent.HitTest(wx.Point(event.m_x, event.m_y + parent_size[1])) + if result != wx.TE_HT_UNKNOWN: + self.Parent.SetInsertionPoint(self.Parent.XYToPosition(x, y)) + else: + wx.CallAfter(self.Parent.DismissListBox) + event.Skip() + + def OnMotion(self, event): + self.ListBox.SetSelection( + self.ListBox.HitTest(wx.Point(event.m_x, event.m_y))) + event.Skip() class TextCtrlAutoComplete(wx.TextCtrl): - def __init__ (self, parent, appframe, choices=None, dropDownClick=True, + def __init__ (self, parent, choices=None, dropDownClick=True, element_path=None, **therest): """ Constructor works just like wx.TextCtrl except you can pass in a @@ -119,11 +118,11 @@ therest['style'] = wx.TE_PROCESS_ENTER | therest.get('style', 0) wx.TextCtrl.__init__(self, parent, **therest) - self.AppFrame = appframe #Some variables self._dropDownClick = dropDownClick self._lastinsertionpoint = None + self._hasfocus = False self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y) self.element_path = element_path @@ -148,9 +147,6 @@ self.Bind(wx.EVT_LEFT_DOWN, self.OnClickToggleDown) self.Bind(wx.EVT_LEFT_UP, self.OnClickToggleUp) - def __del__(self): - self.AppFrame = None - def ChangeValue(self, value): wx.TextCtrl.ChangeValue(self, value) self.RefreshListBoxChoices() @@ -171,7 +167,11 @@ else: self.listbox.MoveSelection(-1) elif keycode in [wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_RETURN] and self.listbox is not None: - self.SetValueFromSelected(self.listbox.GetSelection()) + selected = self.listbox.GetSelection() + if selected != "": + self.SetValueFromSelected(selected) + else: + event.Skip() elif event.GetKeyCode() == wx.WXK_ESCAPE: self.DismissListBox() else: @@ -182,7 +182,9 @@ event.Skip() def OnClickToggleUp(self, event): - if self.GetInsertionPoint() == self._lastinsertionpoint: + if not self._hasfocus: + self._hasfocus = True + elif self.GetInsertionPoint() == self._lastinsertionpoint: wx.CallAfter(self.PopupListBox) self._lastinsertionpoint = None event.Skip() @@ -197,6 +199,7 @@ config.Flush() self.SetChoices(listentries) self.DismissListBox() + self._hasfocus = False event.Skip() def SetChoices(self, choices): @@ -207,13 +210,13 @@ return self._choices def SetValueFromSelected(self, selected): - """ - Sets the wx.TextCtrl value from the selected wx.ListCtrl item. - Will do nothing if no item is selected in the wx.ListCtrl. - """ - if selected != "": + """ + Sets the wx.TextCtrl value from the selected wx.ListCtrl item. + Will do nothing if no item is selected in the wx.ListCtrl. + """ + if selected != "": self.SetValue(selected) - self.DismissListBox() + self.DismissListBox() def RefreshListBoxChoices(self): if self.listbox is not None: @@ -229,22 +232,18 @@ # depending on available screen space... pos = self.ClientToScreen((0, 0)) sz = self.GetSize() + if wx.Platform == '__WXMSW__': + pos.x -= 2 + pos.y -= 2 self.listbox.Position(pos, (0, sz[1])) self.RefreshListBoxChoices() - if wx.Platform == '__WXMSW__': - self.listbox.Popup() - else: - self.listbox.Show() - self.AppFrame.EnableScrolling(False) + self.listbox.Show() def DismissListBox(self): if self.listbox is not None: - if wx.Platform == '__WXMSW__': - self.listbox.Dismiss() - else: - self.listbox.Destroy() + if self.listbox.ListBox.HasCapture(): + self.listbox.ListBox.ReleaseMouse() + self.listbox.Destroy() self.listbox = None - self.AppFrame.EnableScrolling(True) - diff -r 3e7bd88fcff7 -r 276a30c68eaa editors/ConfTreeNodeEditor.py --- a/editors/ConfTreeNodeEditor.py Tue May 28 17:52:07 2013 +0200 +++ b/editors/ConfTreeNodeEditor.py Tue May 28 17:52:57 2013 +0200 @@ -210,11 +210,8 @@ panel_style |= wx.SUNKEN_BORDER self.ParamsEditor = wx.ScrolledWindow(parent, style=panel_style) - self.ParamsEditor.Bind(wx.EVT_SIZE, self.OnWindowResize) - self.ParamsEditor.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) - - # Variable allowing disabling of ParamsEditor scroll when Popup shown - self.ScrollingEnabled = True + self.ParamsEditor.Bind(wx.EVT_SIZE, self.OnParamsEditorResize) + self.ParamsEditor.Bind(wx.EVT_SCROLLWIN, self.OnParamsEditorScroll) self.ParamsEditorSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=5) self.ParamsEditorSizer.AddGrowableCol(0) @@ -278,9 +275,6 @@ self.RefreshConfNodeParamsSizer() self.RefreshScrollbars() - def EnableScrolling(self, enable): - self.ScrollingEnabled = enable - def RefreshIECChannelControlsState(self): self.FullIECChannel.SetLabel(self.Controler.GetFullIEC_Channel()) self.IECCDownButton.Enable(self.Controler.BaseParams.getIEC_Channel() > 0) @@ -469,7 +463,6 @@ choices = self.ParentWindow.GetConfigEntry(element_path, [""]) textctrl = TextCtrlAutoComplete(name=element_infos["name"], parent=self.ParamsEditor, - appframe=self, choices=choices, element_path=element_path, size=wx.Size(300, -1)) @@ -477,7 +470,9 @@ boxsizer.AddWindow(textctrl) if element_infos["value"] is not None: textctrl.ChangeValue(str(element_infos["value"])) - textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, element_path)) + callback = self.GetTextCtrlCallBackFunction(textctrl, element_path) + textctrl.Bind(wx.EVT_TEXT_ENTER, callback) + textctrl.Bind(wx.EVT_KILL_FOCUS, callback) first = False @@ -569,11 +564,14 @@ self.ParamsEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy) - def OnWindowResize(self, event): + def OnParamsEditorResize(self, event): self.RefreshScrollbars() event.Skip() - def OnMouseWheel(self, event): - if self.ScrollingEnabled: - event.Skip() - + def OnParamsEditorScroll(self, event): + control = self.ParamsEditor.FindFocus() + if isinstance(control, TextCtrlAutoComplete): + control.DismissListBox() + self.Refresh() + event.Skip() +