Label tab traversal breaks if only editable on double click

In juce_Label.cpp, from line 353…

void Label::focusGained (FocusChangeType cause)
{
    if (editSingleClick
        && isEnabled()
        && cause == focusChangedByTabKey)
        showEditor();
}

produces the unexpected (at least for me) behaviour that tab traversal of a number of Labels breaks if they are set to only be editable on double click. Perhaps it should be:

void Label::focusGained (FocusChangeType cause)
{
    if (isEditable()
        && isEnabled()
        && cause == focusChangedByTabKey)
        showEditor();
}

?

Here’s an example - https://github.com/willricemusic/JuceLabelTabTraversalSuggestion

Does anyone know how I could improve the tab traversal behaviour in the GitHub example above so that:

  1. Labels show their TextEditor on double click.
  2. Once a Label’s TextEditor is visible, pressing the tab key traverses to the TextEditor of the next Label (& to the previous Label’s TextEditor if the shift key is depressed)
  3. Once editing is complete and the Label’s TextEditor no longer has focus, further presses of the tab key DO NOT traverse to the next Label and/or trigger its TextEditor.

The rightmost column in the example already does 1 & 2, but point 3 is proving tricky to achieve. Any help / suggestions much appreciated!

I’m not really sure that you’d want a double-click editor to go into editing mode whenever it gets the focus, otherwise if, for example, you just had one label in a panel, then clicking anywhere in the panel would put that label into edit mode.

Many thanks for the reply @jules, I really appreciate you taking the time to sweep up the un-answered threads!

As you say, I suspect the above is the wrong solution to my particular problem. I don’t specifically want my double-click Labels to go into edit mode when they gain focus; however, I do need to be able to tab traverse between the TextEditors of a list of double-click-able Labels once in edit mode and it seemed to me that calling showEditor() from focusGained() is the only easy way to achieve that…?

After several days reading & stepping through the Component / Label / TextEditor / KeyboardFocusTraverser code, I’m really struggling with creating the tab traversal behaviour I’m after:

  • List of Labels (see GitHub example)
  • Labels enter edit mode (only) on double-click
  • Once in edit mode, tab/shift-tab traverses to the TextEditor of the next/previous sibling Label
  • Escape / Return exits edit mode and returns focus to the Labels’ first parent Component which wantsKeyboardFocus
  • Once edit mode is left, further tab/shift-tab traversal continues from the Labels’ parent

I’d expect to be able to use the FocusChangeType ‘cause’ argument of Label::focusGained to differentiate between a Label gaining focus on tab-traversal (Label should enter edit mode) vs on esc/enter (Label should return focus to parent). However when tab traversing between labels, focusGained gets called twice:

  • First on the active TextEditor’s parent Label, with a cause of focusChangedDirectly
  • Then on the sibling Label, with a cause of focusChangedByTabKey

And that first (superfluous?) change of focus is indistinguishable from the change of focus you get when using Escape / Enter to exit edit mode.

The comment at line 381 of Label.cpp rather implies that it is expected that the focus traverses directly from a Label’s TextEditor to the Label’s sibling (rather than via the label itself as described above):

// We'll use a custom focus traverser here to make sure focus goes from the
// text editor to another component rather than back to the label itself.

Any advice will be hugely appreciated!

I’ve discovered that the first of these focus changes happens in Component::removeChildComponent due to line 1572 of juce_Component.cpp

My suggestion above does still check for cause == focusChangedByTabKey, so I don’t think clicking a parent component would cause unexpected entering into edit mode?