The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace KeyboardFocusHelpers
  20. {
  21. // This will sort a set of components, so that they are ordered in terms of
  22. // left-to-right and then top-to-bottom.
  23. struct ScreenPositionComparator
  24. {
  25. static int compareElements (const Component* const first, const Component* const second)
  26. {
  27. const int explicitOrder1 = getOrder (first);
  28. const int explicitOrder2 = getOrder (second);
  29. if (explicitOrder1 != explicitOrder2)
  30. return explicitOrder1 - explicitOrder2;
  31. const int yDiff = first->getY() - second->getY();
  32. return yDiff == 0 ? first->getX() - second->getX()
  33. : yDiff;
  34. }
  35. static int getOrder (const Component* const c)
  36. {
  37. const int order = c->getExplicitFocusOrder();
  38. return order > 0 ? order : (std::numeric_limits<int>::max() / 2);
  39. }
  40. };
  41. static void findAllFocusableComponents (Component* const parent, Array <Component*>& comps)
  42. {
  43. if (parent->getNumChildComponents() > 0)
  44. {
  45. Array <Component*> localComps;
  46. ScreenPositionComparator comparator;
  47. for (int i = parent->getNumChildComponents(); --i >= 0;)
  48. {
  49. Component* const c = parent->getChildComponent (i);
  50. if (c->isVisible() && c->isEnabled())
  51. localComps.addSorted (comparator, c);
  52. }
  53. for (int i = 0; i < localComps.size(); ++i)
  54. {
  55. Component* const c = localComps.getUnchecked (i);
  56. if (c->getWantsKeyboardFocus())
  57. comps.add (c);
  58. if (! c->isFocusContainer())
  59. findAllFocusableComponents (c, comps);
  60. }
  61. }
  62. }
  63. static Component* findFocusContainer (Component* c)
  64. {
  65. c = c->getParentComponent();
  66. if (c != nullptr)
  67. while (c->getParentComponent() != nullptr && ! c->isFocusContainer())
  68. c = c->getParentComponent();
  69. return c;
  70. }
  71. static Component* getIncrementedComponent (Component* const current, const int delta)
  72. {
  73. Component* focusContainer = findFocusContainer (current);
  74. if (focusContainer != nullptr)
  75. {
  76. Array <Component*> comps;
  77. KeyboardFocusHelpers::findAllFocusableComponents (focusContainer, comps);
  78. if (comps.size() > 0)
  79. {
  80. const int index = comps.indexOf (current);
  81. return comps [(index + comps.size() + delta) % comps.size()];
  82. }
  83. }
  84. return nullptr;
  85. }
  86. }
  87. //==============================================================================
  88. KeyboardFocusTraverser::KeyboardFocusTraverser() {}
  89. KeyboardFocusTraverser::~KeyboardFocusTraverser() {}
  90. Component* KeyboardFocusTraverser::getNextComponent (Component* current)
  91. {
  92. jassert (current != nullptr);
  93. return KeyboardFocusHelpers::getIncrementedComponent (current, 1);
  94. }
  95. Component* KeyboardFocusTraverser::getPreviousComponent (Component* current)
  96. {
  97. jassert (current != nullptr);
  98. return KeyboardFocusHelpers::getIncrementedComponent (current, -1);
  99. }
  100. Component* KeyboardFocusTraverser::getDefaultComponent (Component* parentComponent)
  101. {
  102. Array <Component*> comps;
  103. if (parentComponent != nullptr)
  104. KeyboardFocusHelpers::findAllFocusableComponents (parentComponent, comps);
  105. return comps.getFirst();
  106. }