| @@ -154,6 +154,7 @@ XmlElement* ComponentTypeHandler::createXmlFor (Component* comp, const Component | |||||
| e->setAttribute (T("id"), String::toHexString (getComponentId (comp))); | e->setAttribute (T("id"), String::toHexString (getComponentId (comp))); | ||||
| e->setAttribute (T("memberName"), comp->getComponentProperty (T("memberName"), false)); | e->setAttribute (T("memberName"), comp->getComponentProperty (T("memberName"), false)); | ||||
| e->setAttribute (T("virtualName"), comp->getComponentProperty (T("virtualName"), false)); | e->setAttribute (T("virtualName"), comp->getComponentProperty (T("virtualName"), false)); | ||||
| e->setAttribute (T("explicitFocusOrder"), comp->getExplicitFocusOrder()); | |||||
| RelativePositionedRectangle pos (getComponentPosition (comp)); | RelativePositionedRectangle pos (getComponentPosition (comp)); | ||||
| pos.updateFromComponent (*comp, layout); | pos.updateFromComponent (*comp, layout); | ||||
| @@ -188,6 +189,7 @@ bool ComponentTypeHandler::restoreFromXml (const XmlElement& xml, | |||||
| setComponentId (comp, xml.getStringAttribute (T("id")).getHexValue64()); | setComponentId (comp, xml.getStringAttribute (T("id")).getHexValue64()); | ||||
| comp->setComponentProperty (T("memberName"), xml.getStringAttribute (T("memberName"))); | comp->setComponentProperty (T("memberName"), xml.getStringAttribute (T("memberName"))); | ||||
| comp->setComponentProperty (T("virtualName"), xml.getStringAttribute (T("virtualName"))); | comp->setComponentProperty (T("virtualName"), xml.getStringAttribute (T("virtualName"))); | ||||
| comp->setExplicitFocusOrder (xml.getIntAttribute (T("explicitFocusOrder"))); | |||||
| RelativePositionedRectangle currentPos (getComponentPosition (comp)); | RelativePositionedRectangle currentPos (getComponentPosition (comp)); | ||||
| currentPos.updateFromComponent (*comp, layout); | currentPos.updateFromComponent (*comp, layout); | ||||
| @@ -330,7 +332,6 @@ private: | |||||
| String newValue, oldValue; | String newValue, oldValue; | ||||
| }; | }; | ||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -370,6 +371,58 @@ private: | |||||
| JucerDocument& document; | JucerDocument& document; | ||||
| }; | }; | ||||
| //============================================================================== | |||||
| class FocusOrderProperty : public ComponentTextProperty <Component> | |||||
| { | |||||
| public: | |||||
| FocusOrderProperty (Component* comp, JucerDocument& document) | |||||
| : ComponentTextProperty <Component> (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 <Component> | |||||
| { | |||||
| public: | |||||
| SetFocusOrderAction (Component* const comp, ComponentLayout& layout, const int newOrder_) | |||||
| : ComponentUndoableAction <Component> (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, | void ComponentTypeHandler::getEditableProperties (Component* component, | ||||
| JucerDocument& document, | JucerDocument& document, | ||||
| @@ -386,6 +439,8 @@ void ComponentTypeHandler::getEditableProperties (Component* component, | |||||
| if (dynamic_cast <SettableTooltipClient*> (component) != 0) | if (dynamic_cast <SettableTooltipClient*> (component) != 0) | ||||
| properties.add (new TooltipProperty (component, document)); | properties.add (new TooltipProperty (component, document)); | ||||
| properties.add (new FocusOrderProperty (component, document)); | |||||
| } | } | ||||
| void ComponentTypeHandler::addPropertiesToPropertyPanel (Component* comp, | void ComponentTypeHandler::addPropertiesToPropertyPanel (Component* comp, | ||||
| @@ -531,6 +586,11 @@ void ComponentTypeHandler::fillInCreationCode (GeneratedCode& code, Component* c | |||||
| << ");\n"; | << ");\n"; | ||||
| } | } | ||||
| if (component->getExplicitFocusOrder() > 0) | |||||
| s << memberVariableName << "->setExplicitFocusOrder (" | |||||
| << component->getExplicitFocusOrder() | |||||
| << ");\n"; | |||||
| code.constructorCode += s; | code.constructorCode += s; | ||||
| } | } | ||||
| @@ -404,7 +404,7 @@ void ListBox::updateContent() | |||||
| if (selected [selected.size() - 1] >= totalItems) | if (selected [selected.size() - 1] >= totalItems) | ||||
| { | { | ||||
| selected.removeRange (totalItems, 0x7fffffff - totalItems); | |||||
| selected.removeRange (totalItems, INT_MAX - totalItems); | |||||
| if (selected.size() == 0) | if (selected.size() == 0) | ||||
| lastRowSelected = totalItems - 1; | lastRowSelected = totalItems - 1; | ||||
| @@ -507,7 +507,7 @@ void ListBox::deselectRow (const int row) | |||||
| void ListBox::setSelectedRows (const SparseSet<int>& setOfRowsToBeSelected) | void ListBox::setSelectedRows (const SparseSet<int>& setOfRowsToBeSelected) | ||||
| { | { | ||||
| selected = setOfRowsToBeSelected; | selected = setOfRowsToBeSelected; | ||||
| selected.removeRange (totalItems, 0x7fffffff - totalItems); | |||||
| selected.removeRange (totalItems, INT_MAX - totalItems); | |||||
| if (! isRowSelected (lastRowSelected)) | if (! isRowSelected (lastRowSelected)) | ||||
| lastRowSelected = -1; | lastRowSelected = -1; | ||||
| @@ -156,7 +156,7 @@ void TableHeaderComponent::addColumn (const String& columnName, | |||||
| ci->minimumWidth = minimumWidth; | ci->minimumWidth = minimumWidth; | ||||
| ci->maximumWidth = maximumWidth; | ci->maximumWidth = maximumWidth; | ||||
| if (ci->maximumWidth < 0) | if (ci->maximumWidth < 0) | ||||
| ci->maximumWidth = 0x7fffffff; | |||||
| ci->maximumWidth = INT_MAX; | |||||
| jassert (ci->maximumWidth >= ci->minimumWidth); | jassert (ci->maximumWidth >= ci->minimumWidth); | ||||
| ci->propertyFlags = propertyFlags; | ci->propertyFlags = propertyFlags; | ||||
| @@ -3188,6 +3188,16 @@ bool Component::isFocusContainer() const throw() | |||||
| return flags.isFocusContainerFlag; | 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() | KeyboardFocusTraverser* Component::createFocusTraverser() | ||||
| { | { | ||||
| if (flags.isFocusContainerFlag || parentComponent_ == 0) | if (flags.isFocusContainerFlag || parentComponent_ == 0) | ||||
| @@ -998,10 +998,7 @@ public: | |||||
| */ | */ | ||||
| bool getWantsKeyboardFocus() const throw(); | 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. | /** 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 | By default this is set to true, but you might want a component which can | ||||
| @@ -1016,6 +1013,7 @@ public: | |||||
| */ | */ | ||||
| bool getMouseClickGrabsKeyboardFocus() const throw(); | bool getMouseClickGrabsKeyboardFocus() const throw(); | ||||
| //============================================================================== | |||||
| /** Tries to give keyboard focus to this component. | /** Tries to give keyboard focus to this component. | ||||
| When the user clicks on a component or its grabKeyboardFocus() | When the user clicks on a component or its grabKeyboardFocus() | ||||
| @@ -1049,6 +1047,13 @@ public: | |||||
| */ | */ | ||||
| bool hasKeyboardFocus (const bool trueIfChildIsFocused) const throw(); | 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. | /** 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 | 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 | @param moveToNext if true, the focus will move forwards; if false, it will | ||||
| move backwards | move backwards | ||||
| @see grabKeyboardFocus, setWantsKeyboardFocus | |||||
| @see grabKeyboardFocus, setFocusContainer, setWantsKeyboardFocus | |||||
| */ | */ | ||||
| void moveKeyboardFocusToSibling (const bool moveToNext); | 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 | /** Creates a KeyboardFocusTraverser object to use to determine the logic by | ||||
| which focus should be passed from this component. | which focus should be passed from this component. | ||||
| @@ -1085,6 +1084,54 @@ public: | |||||
| */ | */ | ||||
| virtual KeyboardFocusTraverser* createFocusTraverser(); | 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. | /** Returns true if the component (and all its parents) are enabled. | ||||
| @@ -56,12 +56,21 @@ public: | |||||
| static int compareElements (const Component* const first, const Component* const second) throw() | 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 <Componen | |||||
| } | } | ||||
| } | } | ||||
| static Component* getIncrementedComponent (Component* const current, const int delta) | |||||
| static Component* getIncrementedComponent (Component* const current, const int delta) throw() | |||||
| { | { | ||||
| Component* focusContainer = current->getParentComponent(); | Component* focusContainer = current->getParentComponent(); | ||||
| @@ -108,9 +117,11 @@ static Component* getIncrementedComponent (Component* const current, const int d | |||||
| Array <Component*> comps; | Array <Component*> comps; | ||||
| findAllFocusableComponents (focusContainer, 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()]; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -39,11 +39,21 @@ class Component; | |||||
| /** | /** | ||||
| Controls the order in which focus moves between components. | 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 | class JUCE_API KeyboardFocusTraverser | ||||
| { | { | ||||
| @@ -218,7 +218,7 @@ public: | |||||
| { | { | ||||
| ++accessCounter; | ++accessCounter; | ||||
| int oldestCounter = 0x7fffffff; | |||||
| int oldestCounter = INT_MAX; | |||||
| int oldestIndex = 0; | int oldestIndex = 0; | ||||
| for (int i = numGlyphs; --i >= 0;) | for (int i = numGlyphs; --i >= 0;) | ||||
| @@ -476,7 +476,7 @@ public: | |||||
| } | } | ||||
| int replaceIndex = 0; | int replaceIndex = 0; | ||||
| int bestLastUsageCount = 0x7fffffff; | |||||
| int bestLastUsageCount = INT_MAX; | |||||
| for (i = faces.size(); --i >= 0;) | for (i = faces.size(); --i >= 0;) | ||||
| { | { | ||||
| @@ -826,7 +826,7 @@ void XmlElement::insertChildElement (XmlElement* const newNode, | |||||
| else | else | ||||
| { | { | ||||
| if (indexToInsertAt < 0) | if (indexToInsertAt < 0) | ||||
| indexToInsertAt = 0x7fffffff; | |||||
| indexToInsertAt = INT_MAX; | |||||
| XmlElement* child = firstChildElement; | XmlElement* child = firstChildElement; | ||||