Commit cb27899a authored by Paul McCarthy's avatar Paul McCarthy 🚵
Browse files

Merge branch 'enh/atc' into 'master'

ENH,MNT: New AutoTextCtrl feature, simplify release model

See merge request fsl/fsleyes/widgets!76
parents ec82fa31 8d7c457e
......@@ -21,13 +21,10 @@
#
# https://hub.docker.com/u/pauldmccarthy/
#
# The test and style stages are executed on all branches of upstream and
# fork repositories.
# The test and style stages are executed on all branches.
#
# The doc stage is executed on release branches of the upstream repository.
#
# The build stage and deploy stages are executed on tags on the upstream
# repository, and the deploy stage must be manually instantiated.
# The doc, build, and deploy stages are executed on tags, and the deploy
# stage must be manually instantiated.
###########################################################################
......@@ -73,20 +70,6 @@ variables:
####################################
.only_upstream: &only_upstream
only:
- branches@fsl/fsleyes/widgets
.only_master: &only_master
only:
- master@fsl/fsleyes/widgets
.only_release_branches: &only_release_branches
only:
- /^v.+$/@fsl/fsleyes/widgets
.only_releases: &only_releases
only:
......@@ -123,9 +106,6 @@ variables:
.test: &test_template
<<: *setup_ssh
# Releases are just tags on a release
# branch, so we don't need to test them.
<<: *except_releases
tags:
......@@ -181,7 +161,7 @@ style:
###########
pages:
<<: *only_release_branches
<<: *only_releases
tags:
- docker
......
......@@ -2,6 +2,19 @@ This document contains the ``fsleyes-widgets`` release history in reverse
chronological order.
0.12.2 (Wednesday October 6th 2021)
-----------------------------------
Added
^^^^^
* New :data:`.ATC_NO_PROPAGATE_ENTER` style flag for the
:class:`.AutoTextCtrl`.
0.12.1 (Wednesday April 21st 2021)
----------------------------------
......
......@@ -18,7 +18,7 @@ This file is used to store the current ``fsleyes-widgets`` version.
"""
__version__ = '0.13.0.dev0'
__version__ = '0.12.2'
from fsleyes_widgets.utils import (WX_PYTHON, # noqa
......
......@@ -32,20 +32,24 @@ class AutoTextCtrl(wx.Panel):
def __init__(self, parent, style=0, modal=True):
"""Create an ``AutoTextCtrl``.
"""Create an ``AutoTextCtrl``. Supported style flags are:
- :data:`ATC_CASE_SENSITIVE`: restrict the auto-completion
options to case sensitive matches.
- :data:`ATC_NO_PROPAGATE_ENTER`: Cause enter events on the
:class:`AutoCompletePopup` to *not* be propagated upwards as
``EVT_ATC_TEXT_ENTER`` events.
:arg parent: The ``wx`` parent object.
:arg style: Can be :data:`ATC_CASE_SENSITIVE` to restrict the
auto-completion options to case sensitive matches.
:arg style: Style flags.
:arg modal: If ``True`` (the default), the :class:`AutoCompletePopup`
is shoown modally. This option is primarily for testing
purposes.
"""
self.__caseSensitive = style & ATC_CASE_SENSITIVE
wx.Panel.__init__(self, parent)
self.__style = style
self.__modal = modal
self.__popup = None
self.__textCtrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
......@@ -216,18 +220,13 @@ class AutoTextCtrl(wx.Panel):
prefix.
"""
text = text.strip()
style = 0
if self.__caseSensitive:
style |= ATC_CASE_SENSITIVE
text = text.strip()
popup = AutoCompletePopup(
self,
self,
text,
self.__options,
style)
self.__style)
if popup.GetCount() == 0:
popup.Destroy()
......@@ -275,6 +274,13 @@ auto-completion pattern matching will be case sensitive.
"""
ATC_NO_PROPAGATE_ENTER = 2
"""Syle flag for use with the :class:`AutoTextCtrl` class. If set,
enter events which occur on the :class:`AutoCompletePopup` list will
*not* be propagated as :attr:`EVT_ATC_TEXT_ENTER` events.
"""
_AutoTextCtrlEnterEvent, _EVT_ATC_TEXT_ENTER = wxevent.NewEvent()
......@@ -297,29 +303,30 @@ class AutoCompletePopup(wx.Dialog):
"""
def __init__(self, parent, atc, text, options, style=0):
"""Create an ``AutoCompletePopup``.
"""Create an ``AutoCompletePopup``. Accepts the same style flags as
the :class:`AutoTextCtrl`.
:arg parent: The ``wx`` parent object.
:arg atc: The :class:`AutoTextCtrl` that is using this popup.
:arg text: Initial text value.
:arg options: A list of all possible auto-completion options.
:arg style: Set to :data:`ATC_CASE_SENSITIVE` to make the
pattern matching case sensitive.
:arg style: Style flags.
"""
wx.Dialog.__init__(self,
parent,
style=(wx.NO_BORDER | wx.STAY_ON_TOP))
self.__alive = True
self.__caseSensitive = style & ATC_CASE_SENSITIVE
self.__atc = atc
self.__options = options
self.__textCtrl = wx.TextCtrl(self,
value=text,
style=wx.TE_PROCESS_ENTER)
self.__listBox = wx.ListBox( self,
style=(wx.LB_SINGLE))
self.__alive = True
self.__caseSensitive = style & ATC_CASE_SENSITIVE
self.__propagateEnter = not (style & ATC_NO_PROPAGATE_ENTER)
self.__atc = atc
self.__options = options
self.__textCtrl = wx.TextCtrl(self,
value=text,
style=wx.TE_PROCESS_ENTER)
self.__listBox = wx.ListBox( self,
style=(wx.LB_SINGLE))
self.__listBox.Set(self.__getMatches(text))
......@@ -430,9 +437,10 @@ class AutoCompletePopup(wx.Dialog):
self.__alive = False
value = self.__textCtrl.GetValue()
idx = self.__textCtrl.GetInsertionPoint()
atc = self.__atc
genEnter = genEnter and self.__propagateEnter
value = self.__textCtrl.GetValue()
idx = self.__textCtrl.GetInsertionPoint()
atc = self.__atc
# Under wx/GTK, we might still receive focus
# events, which will trigger another call to
......
......@@ -20,6 +20,7 @@ def sendEvent(target, evType, source=None):
target.ProcessEvent(wx.CommandEvent(evType, source.GetId()))
realYield()
# Simple test - programmatically
# set, then retrieve the value
def test_getSet():
......@@ -142,6 +143,35 @@ def _test_popup_select3():
assert atc.GetValue() == 'aba'
def test_popup_dblclick():
run_with_wx(_test_popup_dblclick)
def _test_popup_dblclick():
class FakeEv:
def __init__(self, keycode=None):
self.keycode = keycode
def GetKeyCode(self):
return self.keycode
def Skip(self):
pass
def ResumePropagation(self, a):
pass
parent = wx.GetApp().GetTopWindow()
atc = autott.AutoTextCtrl(parent, modal=False)
atc.AutoComplete(['aaa', 'aab', 'aba', 'bcc'])
addall(parent, [atc])
atc._AutoTextCtrl__onKeyDown(FakeEv(wx.WXK_RETURN))
atc.popup.listBox.SetSelection(0)
atc.popup._AutoCompletePopup__onListMouseDblClick(FakeEv())
realYield()
assert atc.GetValue() == 'aaa'
def test_popup_cancel():
run_with_wx(_test_popup_cancel)
def _test_popup_cancel():
......@@ -163,51 +193,77 @@ def _test_popup_cancel():
assert atc.GetValue() == ''
def test_popup_focusback():
run_with_wx(_test_popup_focusback)
def _test_popup_focusback():
sim = wx.UIActionSimulator()
def test_popup_propagate_enter():
run_with_wx(_test_popup_propagate_enter)
def _test_popup_propagate_enter():
sim = wx.UIActionSimulator()
parent = wx.GetApp().GetTopWindow()
atc = autott.AutoTextCtrl(parent, modal=False)
atc = autott.AutoTextCtrl(parent, modal=False)
called = [False]
def atcEnter(ev):
called[0] = True
addall(parent, [atc])
atc.Bind(autott.EVT_ATC_TEXT_ENTER, atcEnter)
atc.AutoComplete(['aaa', 'aab', 'aba', 'bcc'])
simkey(sim, atc.textCtrl, wx.WXK_RETURN)
simkey(sim, atc.popup.textCtrl, wx.WXK_DOWN)
simkey(sim, atc.popup.listBox, wx.WXK_UP)
simtext(sim, atc.popup.textCtrl, 'abc')
simtext(sim, atc, 'ab', enter=False)
assert atc.GetValue() == 'abc'
simkey(sim, atc.popup.textCtrl, wx.WXK_DOWN)
simkey(sim, atc.popup.listBox, wx.WXK_RETURN)
assert atc.GetValue() == 'aba'
assert called[0]
def test_popup_dblclick():
run_with_wx(_test_popup_dblclick)
def _test_popup_dblclick():
class FakeEv:
def __init__(self, keycode=None):
self.keycode = keycode
def GetKeyCode(self):
return self.keycode
def Skip(self):
pass
def ResumePropagation(self, a):
pass
def test_popup_no_propagate_enter():
run_with_wx(_test_popup_no_propagate_enter)
def _test_popup_no_propagate_enter():
sim = wx.UIActionSimulator()
parent = wx.GetApp().GetTopWindow()
atc = autott.AutoTextCtrl(parent, modal=False)
atc = autott.AutoTextCtrl(parent,
modal=False,
style=autott.ATC_NO_PROPAGATE_ENTER)
called = [False]
def atcEnter(ev):
called[0] = True
addall(parent, [atc])
atc.Bind(autott.EVT_ATC_TEXT_ENTER, atcEnter)
atc.AutoComplete(['aaa', 'aab', 'aba', 'bcc'])
simtext(sim, atc, 'ab', enter=False)
simkey(sim, atc.popup.textCtrl, wx.WXK_DOWN)
simkey(sim, atc.popup.listBox, wx.WXK_RETURN)
assert atc.GetValue() == 'aba'
assert not called[0]
def test_popup_focusback():
run_with_wx(_test_popup_focusback)
def _test_popup_focusback():
sim = wx.UIActionSimulator()
parent = wx.GetApp().GetTopWindow()
atc = autott.AutoTextCtrl(parent, modal=False)
addall(parent, [atc])
atc._AutoTextCtrl__onKeyDown(FakeEv(wx.WXK_RETURN))
atc.popup.listBox.SetSelection(0)
atc.popup._AutoCompletePopup__onListMouseDblClick(FakeEv())
realYield()
atc.AutoComplete(['aaa', 'aab', 'aba', 'bcc'])
assert atc.GetValue() == 'aaa'
simkey(sim, atc.textCtrl, wx.WXK_RETURN)
simkey(sim, atc.popup.textCtrl, wx.WXK_DOWN)
simkey(sim, atc.popup.listBox, wx.WXK_UP)
simtext(sim, atc.popup.textCtrl, 'abc')
assert atc.GetValue() == 'abc'
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment