Skip to content

Commit

Permalink
Fixed tab focus ordering in NodeEditor.
Browse files Browse the repository at this point in the history
It's still possible to use a ListContainer in such a way that you get bad focus orders, but it's fixed enough for the purposes of the NodeEditor, which is the only place bad ordering has been reported to date. See comments in ListContainer.py for possible alternative approaches that may hold some promise, but were fruitless so far.

For the most part, fixes #107.
  • Loading branch information
johnhaddon committed Jul 9, 2013
1 parent 3aa277a commit 95ee7dc
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
24 changes: 20 additions & 4 deletions python/GafferUI/ListContainer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
##########################################################################
#
# Copyright (c) 2011, John Haddon. All rights reserved.
# Copyright (c) 2011-2012, Image Engine Design Inc. All rights reserved.
# Copyright (c) 2011-2013, Image Engine Design Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -126,9 +126,25 @@ def __setitem__( self, index, child ) :

del self[index]

for i in range( len( children ) - 1, -1, -1 ) :
self.insert( insertionIndex, children[i], expands[i] )

# It's very important that we insert widgets in the order in which
# they are to appear visually, because qt will define the tab-focus
# chain order based on order of insertion, and not based on the order
# of visual appearance. It's still possible to make several calls to
# __setitem__ out of sequence and end up with bad focus orders, but
# at least this way a slice set at one time will be in the correct order.
#
# Investigation into a method of achieving perfect ordering all the
# time didn't yield anything better than this. One attempt called
# setTabOrder() for every child, starting with the last child - this
# worked when the children of the ListContainer where childless,
# but not when they had children. Another possibility was to reimplement
# QWidget.focusNextPrevChild() at the GafferUI.Window level, iterating
# through the focus chain as for QApplicationPrivate::focusNextPrevChild_helper(),
# but using knowledge of Container order to override the sequence where
# necessary. This seemed like it might have promise, but is not straightforward.
for i in range( 0, len( children ) ) :
self.insert( insertionIndex + i, children[i], expands[i] )

def __getitem__( self, index ) :

return self.__widgets[index]
Expand Down
24 changes: 23 additions & 1 deletion python/GafferUITest/ListContainerTest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
##########################################################################
#
# Copyright (c) 2011, John Haddon. All rights reserved.
# Copyright (c) 2011-2012, Image Engine Design Inc. All rights reserved.
# Copyright (c) 2011-2013, Image Engine Design Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -347,6 +347,28 @@ def testDelDoesntAffectVisibility( self ) :
l2 = GafferUI.ListContainer()
l2.append( b )
self.assertEqual( b.getVisible(), True )

def testFocusOrder( self ) :

l = GafferUI.ListContainer()

c = []
for i in range( 0, 10 ) :
c.append( GafferUI.TextWidget() )

l[:] = c

for i in range( 0, 9 ) :
self.assertTrue( l[i]._qtWidget().nextInFocusChain() is l[i+1]._qtWidget() )

def testSliceSetItemAtEnd( self ) :

c = GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Vertical )
c.append( TestWidget( "a" ) )

c[1:] = [ TestWidget( "b" ) ]
self.assertEqual( c[0].s, "a" )
self.assertEqual( c[1].s, "b" )

if __name__ == "__main__":
unittest.main()
Expand Down

0 comments on commit 95ee7dc

Please sign in to comment.