diff --git a/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp b/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp index 173abc753b..e3db4f92ef 100644 --- a/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp +++ b/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp @@ -154,6 +154,7 @@ XmlElement* ComponentTypeHandler::createXmlFor (Component* comp, const Component e->setAttribute (T("id"), String::toHexString (getComponentId (comp))); e->setAttribute (T("memberName"), comp->getComponentProperty (T("memberName"), false)); e->setAttribute (T("virtualName"), comp->getComponentProperty (T("virtualName"), false)); + e->setAttribute (T("explicitFocusOrder"), comp->getExplicitFocusOrder()); RelativePositionedRectangle pos (getComponentPosition (comp)); pos.updateFromComponent (*comp, layout); @@ -188,6 +189,7 @@ bool ComponentTypeHandler::restoreFromXml (const XmlElement& xml, setComponentId (comp, xml.getStringAttribute (T("id")).getHexValue64()); comp->setComponentProperty (T("memberName"), xml.getStringAttribute (T("memberName"))); comp->setComponentProperty (T("virtualName"), xml.getStringAttribute (T("virtualName"))); + comp->setExplicitFocusOrder (xml.getIntAttribute (T("explicitFocusOrder"))); RelativePositionedRectangle currentPos (getComponentPosition (comp)); currentPos.updateFromComponent (*comp, layout); @@ -330,7 +332,6 @@ private: String newValue, oldValue; }; - }; //============================================================================== @@ -370,6 +371,58 @@ private: JucerDocument& document; }; + +//============================================================================== +class FocusOrderProperty : public ComponentTextProperty +{ +public: + FocusOrderProperty (Component* comp, JucerDocument& document) + : ComponentTextProperty (T("focus order"), 8, false, comp, document) + { + } + + const String getText() const + { + return String (component->getExplicitFocusOrder()); + } + + void setText (const String& newText) + { + document.perform (new SetFocusOrderAction (component, *document.getComponentLayout(), newText.getIntValue()), + T("Change focus order")); + } + +private: + class SetFocusOrderAction : public ComponentUndoableAction + { + public: + SetFocusOrderAction (Component* const comp, ComponentLayout& layout, const int newOrder_) + : ComponentUndoableAction (comp, layout), + newValue (newOrder_) + { + oldValue = comp->getExplicitFocusOrder(); + } + + bool perform() + { + showCorrectTab(); + getComponent()->setExplicitFocusOrder (newValue); + changed(); + return true; + } + + bool undo() + { + showCorrectTab(); + getComponent()->setExplicitFocusOrder (oldValue); + changed(); + return true; + } + + int newValue, oldValue; + }; +}; + //============================================================================== void ComponentTypeHandler::getEditableProperties (Component* component, JucerDocument& document, @@ -386,6 +439,8 @@ void ComponentTypeHandler::getEditableProperties (Component* component, if (dynamic_cast (component) != 0) properties.add (new TooltipProperty (component, document)); + + properties.add (new FocusOrderProperty (component, document)); } void ComponentTypeHandler::addPropertiesToPropertyPanel (Component* comp, @@ -531,6 +586,11 @@ void ComponentTypeHandler::fillInCreationCode (GeneratedCode& code, Component* c << ");\n"; } + if (component->getExplicitFocusOrder() > 0) + s << memberVariableName << "->setExplicitFocusOrder (" + << component->getExplicitFocusOrder() + << ");\n"; + code.constructorCode += s; } diff --git a/src/juce_appframework/gui/components/controls/juce_ListBox.cpp b/src/juce_appframework/gui/components/controls/juce_ListBox.cpp index a35e324abd..fce0a75b9c 100644 --- a/src/juce_appframework/gui/components/controls/juce_ListBox.cpp +++ b/src/juce_appframework/gui/components/controls/juce_ListBox.cpp @@ -404,7 +404,7 @@ void ListBox::updateContent() if (selected [selected.size() - 1] >= totalItems) { - selected.removeRange (totalItems, 0x7fffffff - totalItems); + selected.removeRange (totalItems, INT_MAX - totalItems); if (selected.size() == 0) lastRowSelected = totalItems - 1; @@ -507,7 +507,7 @@ void ListBox::deselectRow (const int row) void ListBox::setSelectedRows (const SparseSet& setOfRowsToBeSelected) { selected = setOfRowsToBeSelected; - selected.removeRange (totalItems, 0x7fffffff - totalItems); + selected.removeRange (totalItems, INT_MAX - totalItems); if (! isRowSelected (lastRowSelected)) lastRowSelected = -1; diff --git a/src/juce_appframework/gui/components/controls/juce_TableHeaderComponent.cpp b/src/juce_appframework/gui/components/controls/juce_TableHeaderComponent.cpp index 164654947b..5305f3e2b6 100644 --- a/src/juce_appframework/gui/components/controls/juce_TableHeaderComponent.cpp +++ b/src/juce_appframework/gui/components/controls/juce_TableHeaderComponent.cpp @@ -156,7 +156,7 @@ void TableHeaderComponent::addColumn (const String& columnName, ci->minimumWidth = minimumWidth; ci->maximumWidth = maximumWidth; if (ci->maximumWidth < 0) - ci->maximumWidth = 0x7fffffff; + ci->maximumWidth = INT_MAX; jassert (ci->maximumWidth >= ci->minimumWidth); ci->propertyFlags = propertyFlags; diff --git a/src/juce_appframework/gui/components/juce_Component.cpp b/src/juce_appframework/gui/components/juce_Component.cpp index bf7d336cfc..f3f5bfaa4e 100644 --- a/src/juce_appframework/gui/components/juce_Component.cpp +++ b/src/juce_appframework/gui/components/juce_Component.cpp @@ -3188,6 +3188,16 @@ bool Component::isFocusContainer() const throw() return flags.isFocusContainerFlag; } +int Component::getExplicitFocusOrder() const throw() +{ + return getComponentPropertyInt (T("_jexfo"), false, 0); +} + +void Component::setExplicitFocusOrder (const int newFocusOrderIndex) throw() +{ + setComponentProperty (T("_jexfo"), newFocusOrderIndex); +} + KeyboardFocusTraverser* Component::createFocusTraverser() { if (flags.isFocusContainerFlag || parentComponent_ == 0) diff --git a/src/juce_appframework/gui/components/juce_Component.h b/src/juce_appframework/gui/components/juce_Component.h index 96cbd0a361..c032a4d8cc 100644 --- a/src/juce_appframework/gui/components/juce_Component.h +++ b/src/juce_appframework/gui/components/juce_Component.h @@ -998,10 +998,7 @@ public: */ bool getWantsKeyboardFocus() const throw(); - void setFocusContainer (const bool isFocusContainer) throw(); - - bool isFocusContainer() const throw(); - + //============================================================================== /** Chooses whether a click on this component automatically grabs the focus. By default this is set to true, but you might want a component which can @@ -1016,6 +1013,7 @@ public: */ bool getMouseClickGrabsKeyboardFocus() const throw(); + //============================================================================== /** Tries to give keyboard focus to this component. When the user clicks on a component or its grabKeyboardFocus() @@ -1049,6 +1047,13 @@ public: */ bool hasKeyboardFocus (const bool trueIfChildIsFocused) const throw(); + /** Returns the component that currently has the keyboard focus. + + @returns the focused component, or null if nothing is focused. + */ + static Component* getCurrentlyFocusedComponent() throw(); + + //============================================================================== /** Tries to move the keyboard focus to one of this component's siblings. This will try to move focus to either the next or previous component. (This @@ -1058,16 +1063,10 @@ public: @param moveToNext if true, the focus will move forwards; if false, it will move backwards - @see grabKeyboardFocus, setWantsKeyboardFocus + @see grabKeyboardFocus, setFocusContainer, setWantsKeyboardFocus */ void moveKeyboardFocusToSibling (const bool moveToNext); - /** Returns the component that currently has the keyboard focus. - - @returns the focused component, or null if nothing is focused. - */ - static Component* getCurrentlyFocusedComponent() throw(); - /** Creates a KeyboardFocusTraverser object to use to determine the logic by which focus should be passed from this component. @@ -1085,6 +1084,54 @@ public: */ virtual KeyboardFocusTraverser* createFocusTraverser(); + /** Returns the focus order of this component, if one has been specified. + + By default components don't have a focus order - in that case, this + will return 0. Lower numbers indicate that the component will be + earlier in the focus traversal order. + + To change the order, call setExplicitFocusOrder(). + + The focus order may be used by the KeyboardFocusTraverser class as part of + its algorithm for deciding the order in which components should be traversed. + See the KeyboardFocusTraverser class for more details on this. + + @see moveKeyboardFocusToSibling, createFocusTraverser, KeyboardFocusTraverser + */ + int getExplicitFocusOrder() const throw(); + + /** Sets the index used in determining the order in which focusable components + should be traversed. + + A value of 0 or less is taken to mean that no explicit order is wanted, and + that traversal should use other factors, like the component's position. + + @see getExplicitFocusOrder, moveKeyboardFocusToSibling + */ + void setExplicitFocusOrder (const int newFocusOrderIndex) throw(); + + /** Indicates whether this component is a parent for components that can have + their focus traversed. + + This flag is used by the default implementation of the createFocusTraverser() + method, which uses the flag to find the first parent component (of the currently + focused one) which wants to be a focus container. + + So using this method to set the flag to 'true' causes this component to + act as the top level within which focus is passed around. + + @see isFocusContainer, createFocusTraverser, moveKeyboardFocusToSibling + */ + void setFocusContainer (const bool isFocusContainer) throw(); + + /** Returns true if this component has been marked as a focus container. + + See setFocusContainer() for more details. + + @see setFocusContainer, moveKeyboardFocusToSibling, createFocusTraverser + */ + bool isFocusContainer() const throw(); + //============================================================================== /** Returns true if the component (and all its parents) are enabled. diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.cpp b/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.cpp index 6b1826ebef..0b7ffb8419 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.cpp +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.cpp @@ -56,12 +56,21 @@ public: static int compareElements (const Component* const first, const Component* const second) throw() { - int diff = first->getY() - second->getY(); + int explicitOrder1 = first->getExplicitFocusOrder(); + if (explicitOrder1 < 0) + explicitOrder1 = INT_MAX / 2; - if (diff == 0) - diff = first->getX() - second->getX(); + int explicitOrder2 = second->getExplicitFocusOrder(); + if (explicitOrder2 < 0) + explicitOrder2 = INT_MAX / 2; - return diff; + if (explicitOrder1 != explicitOrder2) + return explicitOrder2 - explicitOrder1; + + const int diff = first->getY() - second->getY(); + + return (diff == 0) ? first->getX() - second->getX() + : diff; } }; @@ -94,7 +103,7 @@ static void findAllFocusableComponents (Component* const parent, Array getParentComponent(); @@ -108,9 +117,11 @@ static Component* getIncrementedComponent (Component* const current, const int d Array comps; findAllFocusableComponents (focusContainer, comps); - const int index = comps.indexOf (current); - - return comps [(index + comps.size() + delta) % comps.size()]; + if (comps.size() > 0) + { + const int index = comps.indexOf (current); + return comps [(index + comps.size() + delta) % comps.size()]; + } } } diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.h b/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.h index 8ad085815b..4a64f93475 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.h +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyboardFocusTraverser.h @@ -39,11 +39,21 @@ class Component; /** Controls the order in which focus moves between components. - The default implementation of this class orders the components in a left-to-right, - top-to-bottom order. If you need traversal in a more customised way, you - can create a subclass that uses your own algorithm. - - @see Component::createFocusTraverser() + The default algorithm used by this class to work out the order of traversal + is as follows: + - if two components both have an explicit focus order specified, then the + one with the lowest number comes first (see the Component::setExplicitFocusOrder() + method). + - any component with an explicit focus order greater than 0 comes before ones + that don't have an order specified. + - any unspecified components are traversed in a left-to-right, then top-to-bottom + order. + + If you need traversal in a more customised way, you can create a subclass + of KeyboardFocusTraverser that uses your own algorithm, and use + Component::createFocusTraverser() to create it. + + @see Component::setExplicitFocusOrder, Component::createFocusTraverser */ class JUCE_API KeyboardFocusTraverser { diff --git a/src/juce_appframework/gui/graphics/fonts/juce_GlyphArrangement.cpp b/src/juce_appframework/gui/graphics/fonts/juce_GlyphArrangement.cpp index 5255a66a56..389a48592f 100644 --- a/src/juce_appframework/gui/graphics/fonts/juce_GlyphArrangement.cpp +++ b/src/juce_appframework/gui/graphics/fonts/juce_GlyphArrangement.cpp @@ -218,7 +218,7 @@ public: { ++accessCounter; - int oldestCounter = 0x7fffffff; + int oldestCounter = INT_MAX; int oldestIndex = 0; for (int i = numGlyphs; --i >= 0;) diff --git a/src/juce_appframework/gui/graphics/fonts/juce_Typeface.cpp b/src/juce_appframework/gui/graphics/fonts/juce_Typeface.cpp index e1cb2aee2b..3bdcb5ec33 100644 --- a/src/juce_appframework/gui/graphics/fonts/juce_Typeface.cpp +++ b/src/juce_appframework/gui/graphics/fonts/juce_Typeface.cpp @@ -476,7 +476,7 @@ public: } int replaceIndex = 0; - int bestLastUsageCount = 0x7fffffff; + int bestLastUsageCount = INT_MAX; for (i = faces.size(); --i >= 0;) { diff --git a/src/juce_core/text/juce_XmlElement.cpp b/src/juce_core/text/juce_XmlElement.cpp index 9491b583e2..47b3adb36f 100644 --- a/src/juce_core/text/juce_XmlElement.cpp +++ b/src/juce_core/text/juce_XmlElement.cpp @@ -826,7 +826,7 @@ void XmlElement::insertChildElement (XmlElement* const newNode, else { if (indexToInsertAt < 0) - indexToInsertAt = 0x7fffffff; + indexToInsertAt = INT_MAX; XmlElement* child = firstChildElement;